From a274ac8a7cf2177662bef8d69ff2647e5ae6e6d4 Mon Sep 17 00:00:00 2001 From: Moritz Sanft <58110325+msanft@users.noreply.github.com> Date: Fri, 24 Feb 2023 12:00:04 +0100 Subject: [PATCH] ci: add cli k8s compatibility table artifact upload to ci (#1218) * add cli k8s compatibility api to ci * extend versionsapi package * rework cli info upload via ci * join errors natively * fix semver * upload from hack file * fix ci checks * add distributionid * setup go before running hack file * setup go after repo checkout * use logger instead of panic, invalidate cache * use provided ctx Co-authored-by: Paul Meyer <49727155+katexochen@users.noreply.github.com> --------- Co-authored-by: Paul Meyer <49727155+katexochen@users.noreply.github.com> --- .github/workflows/build-os-image.yml | 27 ++- hack/cli-k8s-compatibility/main.go | 66 +++++++ hack/go.mod | 2 + hack/go.sum | 4 + internal/versionsapi/client/client.go | 10 ++ internal/versionsapi/cliinfo.go | 95 ++++++++++ internal/versionsapi/cliinfo_test.go | 221 ++++++++++++++++++++++++ internal/versionsapi/fetcher/fetcher.go | 5 + internal/versionsapi/version.go | 6 + internal/versionsapi/version_test.go | 143 +++++++++++++-- 10 files changed, 558 insertions(+), 21 deletions(-) create mode 100644 hack/cli-k8s-compatibility/main.go create mode 100644 internal/versionsapi/cliinfo.go create mode 100644 internal/versionsapi/cliinfo_test.go diff --git a/.github/workflows/build-os-image.yml b/.github/workflows/build-os-image.yml index b48308f14..9c7749950 100644 --- a/.github/workflows/build-os-image.yml +++ b/.github/workflows/build-os-image.yml @@ -122,6 +122,7 @@ jobs: imageName: ${{ steps.image-version.outputs.imageName }} imageNameShort: ${{ steps.image-version.outputs.imageNameShort }} imageApiBasePath: ${{ steps.image-version.outputs.imageApiBasePath }} + cliApiBasePath: ${{ steps.image-version.outputs.cliApiBasePath }} steps: - name: Checkout uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 @@ -193,6 +194,7 @@ jobs: echo "imageVersion=${IMAGE_VERSION}" echo "imageName=ref/${REF}/stream/${STREAM}/${IMAGE_VERSION}" echo "imageApiBasePath=constellation/v1/ref/${REF}/stream/${STREAM}/${IMAGE_VERSION}/image" + echo "cliApiBasePath=constellation/v1/ref/${REF}/stream/${STREAM}/${IMAGE_VERSION}/cli" } >> "$GITHUB_OUTPUT" if [[ "${REF}" = "-" ]] && [[ "${STREAM}" = "stable" ]]; then @@ -863,8 +865,8 @@ jobs: --no-progress done - upload-image-lookup-table: - name: "Upload image lookup table" + upload-artifacts: + name: "Upload image lookup table and CLI compatibility info" runs-on: ubuntu-22.04 needs: [build-settings, upload-os-image] permissions: @@ -918,8 +920,27 @@ jobs: echo -e "\`\`\`" } >> "$GITHUB_STEP_SUMMARY" + - name: Checkout + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + with: + ref: ${{ inputs.ref || github.head_ref }} + + - name: Setup Go environment + uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + with: + go-version: "1.20.1" + cache: true + + - name: Create CLI compatibility information artifact + shell: bash + run: | + go run ./hack/cli-k8s-compatibility/main.go \ + --ref=${{ needs.build-settings.outputs.ref }} \ + --stream=${{ needs.build-settings.outputs.stream }} \ + --version=${{ needs.build-settings.outputs.imageVersion }} \ + add-version-to-versionsapi: - needs: [upload-image-lookup-table, build-settings] + needs: [upload-artifacts, build-settings] name: "Add version to versionsapi" if: needs.build-settings.outputs.ref != '-' permissions: diff --git a/hack/cli-k8s-compatibility/main.go b/hack/cli-k8s-compatibility/main.go new file mode 100644 index 000000000..f840e5f60 --- /dev/null +++ b/hack/cli-k8s-compatibility/main.go @@ -0,0 +1,66 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ + +// cli-k8s-compatibility generates JSON output for a CLI version and its supported Kubernetes versions. +package main + +import ( + "context" + "flag" + + "github.com/edgelesssys/constellation/v2/internal/logger" + "github.com/edgelesssys/constellation/v2/internal/versions" + "github.com/edgelesssys/constellation/v2/internal/versionsapi" + "github.com/edgelesssys/constellation/v2/internal/versionsapi/client" + "go.uber.org/zap/zapcore" +) + +var ( + refFlag = flag.String("ref", "", "the reference name of the image") + streamFlag = flag.String("stream", "", "the stream name of the image") + versionFlag = flag.String("version", "", "the version of the image") +) + +func main() { + log := logger.New(logger.PlainLog, zapcore.DebugLevel) + ctx := context.Background() + + flag.Parse() + if *refFlag == "" { + log.Fatalf("ref must be set") + } + if *streamFlag == "" { + log.Fatalf("stream must be set") + } + if *versionFlag == "" { + log.Fatalf("version must be set") + } + + cliInfo := versionsapi.CLIInfo{ + Ref: *refFlag, + Stream: *streamFlag, + Version: *versionFlag, + Kubernetes: []string{}, + } + + for _, v := range versions.VersionConfigs { + cliInfo.Kubernetes = append(cliInfo.Kubernetes, v.ClusterVersion) + } + + c, err := client.NewClient(ctx, "eu-central-1", "cdn-constellation-backend", "E1H77EZTHC3NE4", false, log) + if err != nil { + log.Fatalf("creating s3 client: %w", err) + } + defer func() { + if err := c.InvalidateCache(ctx); err != nil { + log.Fatalf("invalidating cache: %w", err) + } + }() + + if err := c.UpdateCLIInfo(ctx, cliInfo); err != nil { + log.Fatalf("updating cli info: %w", err) + } +} diff --git a/hack/go.mod b/hack/go.mod index cb3c3df68..a6b545a5d 100644 --- a/hack/go.mod +++ b/hack/go.mod @@ -91,10 +91,12 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.18.10 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.13.10 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.49 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.28 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.18 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudfront v1.24.0 // indirect github.com/aws/aws-sdk-go-v2/service/ec2 v1.83.0 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.22 // indirect diff --git a/hack/go.sum b/hack/go.sum index e02547360..af3b78c36 100644 --- a/hack/go.sum +++ b/hack/go.sum @@ -227,6 +227,8 @@ github.com/aws/aws-sdk-go-v2/credentials v1.13.10 h1:T4Y39IhelTLg1f3xiKJssThnFxs github.com/aws/aws-sdk-go-v2/credentials v1.13.10/go.mod h1:tqAm4JmQaShel+Qi38hmd1QglSnnxaYt50k/9yGQzzc= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21 h1:j9wi1kQ8b+e0FBVHxCqCGo4kxDU175hoDHcWAi0sauU= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21/go.mod h1:ugwW57Z5Z48bpvUyZuaPy4Kv+vEfJWnIrky7RmkBvJg= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.49 h1:zPFhadkmXbXu3RVXTPU4HVW+g2DStMY+01cJaj//+Cw= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.49/go.mod h1:N9gSChQkKpdAj7vRpfKma4ND88zoZM+v6W2lJgWrDh4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27 h1:I3cakv2Uy1vNmmhRQmFptYDxOvBnwCdNwyw63N0RaRU= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27/go.mod h1:a1/UpzeyBBerajpnP5nGZa9mGzsBn5cOKxm6NWQsvoI= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21 h1:5NbbMrIzmUn/TXFqAle6mgrH5m9cOvMLRGL7pnG8tRE= @@ -235,6 +237,8 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.3.28 h1:KeTxcGdNnQudb46oOl4d90f2I33 github.com/aws/aws-sdk-go-v2/internal/ini v1.3.28/go.mod h1:yRZVr/iT0AqyHeep00SZ4YfBAKojXz08w3XMBscdi0c= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.18 h1:H/mF2LNWwX00lD6FlYfKpLLZgUW7oIzCBkig78x4Xok= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.18/go.mod h1:T2Ku+STrYQ1zIkL1wMvj8P3wWQaaCMKNdz70MT2FLfE= +github.com/aws/aws-sdk-go-v2/service/cloudfront v1.24.0 h1:k1RJsiyqnUm5u+jrYOls9MoP9xgqsVUOrfsYy9mxCro= +github.com/aws/aws-sdk-go-v2/service/cloudfront v1.24.0/go.mod h1:xUOmvPrMKmH94stXswKsGSkL02vMpNU+rTG+eIzFfNQ= github.com/aws/aws-sdk-go-v2/service/ec2 v1.83.0 h1:6eTsq8mUG4VCrqbebRYVtgkKguP9J2veJHuhdISMM+Y= github.com/aws/aws-sdk-go-v2/service/ec2 v1.83.0/go.mod h1:mV0E7631M1eXdB+tlGFIw6JxfsC7Pz7+7Aw15oLVhZw= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= diff --git a/internal/versionsapi/client/client.go b/internal/versionsapi/client/client.go index e56217e67..a4d3ff86d 100644 --- a/internal/versionsapi/client/client.go +++ b/internal/versionsapi/client/client.go @@ -140,6 +140,16 @@ func (c *Client) UpdateImageInfo(ctx context.Context, imageInfo versionsapi.Imag return update(ctx, c, imageInfo) } +// FetchCLIInfo fetches the given CLI info from the versions API. +func (c *Client) FetchCLIInfo(ctx context.Context, cliInfo versionsapi.CLIInfo) (versionsapi.CLIInfo, error) { + return fetch(ctx, c, cliInfo) +} + +// UpdateCLIInfo updates the given CLI info in the versions API. +func (c *Client) UpdateCLIInfo(ctx context.Context, cliInfo versionsapi.CLIInfo) error { + return update(ctx, c, cliInfo) +} + // DeleteRef deletes the given ref from the versions API. func (c *Client) DeleteRef(ctx context.Context, ref string) error { if err := versionsapi.ValidateRef(ref); err != nil { diff --git a/internal/versionsapi/cliinfo.go b/internal/versionsapi/cliinfo.go new file mode 100644 index 000000000..83d0d28e8 --- /dev/null +++ b/internal/versionsapi/cliinfo.go @@ -0,0 +1,95 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ + +package versionsapi + +import ( + "errors" + "fmt" + "net/url" + "path" + + "github.com/edgelesssys/constellation/v2/internal/constants" + "golang.org/x/mod/semver" +) + +// CLIInfo contains information about a specific CLI version (i.e. it's compatibility with Kubernetes versions). +type CLIInfo struct { + // Ref is the reference name of the image. + Ref string `json:"ref,omitempty"` + // Stream is the stream name of the image. + Stream string `json:"stream,omitempty"` + // Version is the version of the image. + Version string `json:"version,omitempty"` + // Kubernetes contains all compatible Kubernetes versions. + Kubernetes []string `json:"kubernetes,omitempty"` +} + +// JSONPath returns the S3 JSON path for this object. +func (c CLIInfo) JSONPath() string { + return path.Join( + constants.CDNAPIPrefix, + "ref", c.Ref, + "stream", c.Stream, + c.Version, + "cli", + "info.json", + ) +} + +// URL returns the URL to the JSON file for this object. +func (c CLIInfo) URL() (string, error) { + url, err := url.Parse(constants.CDNRepositoryURL) + if err != nil { + return "", fmt.Errorf("parsing CDN URL: %w", err) + } + url.Path = c.JSONPath() + return url.String(), nil +} + +// ValidateRequest validates the request parameters of the list. +// The Kubernetes slice must be empty. +func (c CLIInfo) ValidateRequest() error { + var retErr error + if err := ValidateRef(c.Ref); err != nil { + retErr = errors.Join(retErr, err) + } + if err := ValidateStream(c.Ref, c.Stream); err != nil { + retErr = errors.Join(retErr, err) + } + if !semver.IsValid(c.Version) { + retErr = errors.Join(retErr, fmt.Errorf("version %q is not a valid semver", c.Version)) + } + if len(c.Kubernetes) != 0 { + retErr = errors.Join(retErr, errors.New("Kubernetes slice must be empty for request")) + } + + return retErr +} + +// Validate checks if the CLI info is valid. +func (c CLIInfo) Validate() error { + var retErr error + if err := ValidateRef(c.Ref); err != nil { + retErr = errors.Join(retErr, err) + } + if err := ValidateStream(c.Ref, c.Stream); err != nil { + retErr = errors.Join(retErr, err) + } + if !semver.IsValid(c.Version) { + retErr = errors.Join(retErr, fmt.Errorf("version %q is not a valid semver", c.Version)) + } + if len(c.Kubernetes) == 0 { + retErr = errors.Join(retErr, errors.New("Kubernetes slice must not be empty")) + } + for _, k := range c.Kubernetes { + if !semver.IsValid(k) { + retErr = errors.Join(retErr, fmt.Errorf("Kubernetes version %q is not a valid semver", k)) + } + } + + return retErr +} diff --git a/internal/versionsapi/cliinfo_test.go b/internal/versionsapi/cliinfo_test.go new file mode 100644 index 000000000..f1f759f1b --- /dev/null +++ b/internal/versionsapi/cliinfo_test.go @@ -0,0 +1,221 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ + +package versionsapi + +import ( + "testing" + + "github.com/edgelesssys/constellation/v2/internal/constants" + "github.com/stretchr/testify/assert" +) + +func TestCLIInfoJSONPath(t *testing.T) { + testCases := map[string]struct { + info CLIInfo + wantPath string + }{ + "cli info": { + info: CLIInfo{ + Ref: "test-ref", + Stream: "nightly", + Version: "v1.0.0", + }, + wantPath: constants.CDNAPIPrefix + "/ref/test-ref/stream/nightly/v1.0.0/cli/info.json", + }, + "cli info release": { + info: CLIInfo{ + Ref: ReleaseRef, + Stream: "stable", + Version: "v1.0.0", + }, + wantPath: constants.CDNAPIPrefix + "/ref/-/stream/stable/v1.0.0/cli/info.json", + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert.Equal(t, tc.wantPath, tc.info.JSONPath()) + }) + } +} + +func TestCLIInfoURL(t *testing.T) { + testCases := map[string]struct { + info CLIInfo + wantURL string + wantPath string + }{ + "cli info": { + info: CLIInfo{ + Ref: "test-ref", + Stream: "nightly", + Version: "v1.0.0", + }, + wantURL: constants.CDNRepositoryURL + "/" + constants.CDNAPIPrefix + "/ref/test-ref/stream/nightly/v1.0.0/cli/info.json", + }, + "cli info release": { + info: CLIInfo{ + Ref: ReleaseRef, + Stream: "stable", + Version: "v1.0.0", + }, + wantURL: constants.CDNRepositoryURL + "/" + constants.CDNAPIPrefix + "/ref/-/stream/stable/v1.0.0/cli/info.json", + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + url, err := tc.info.URL() + assert.NoError(err) + assert.Equal(tc.wantURL, url) + }) + } +} + +func TestCLIInfoValidate(t *testing.T) { + testCases := map[string]struct { + info CLIInfo + wantErr bool + }{ + "valid cli info": { + info: CLIInfo{ + Ref: "test-ref", + Stream: "nightly", + Version: "v1.0.0", + Kubernetes: []string{"v1.26.1", "v1.3.3", "v1.32"}, + }, + }, + "invalid ref": { + info: CLIInfo{ + Ref: "", + Stream: "nightly", + Version: "v1.0.0", + Kubernetes: []string{"v1.26.1", "v1.3.3", "v1.32"}, + }, + wantErr: true, + }, + "invalid stream": { + info: CLIInfo{ + Ref: "test-ref", + Stream: "", + Version: "v1.0.0", + Kubernetes: []string{"v1.26.1", "v1.3.3", "v1.32"}, + }, + wantErr: true, + }, + "invalid version": { + info: CLIInfo{ + Ref: "test-ref", + Stream: "nightly", + Version: "", + Kubernetes: []string{"v1.26.1", "v1.3.3", "v1.32"}, + }, + wantErr: true, + }, + "invalid k8s versions": { + info: CLIInfo{ + Ref: "test-ref", + Stream: "nightly", + Version: "v1.0.0", + Kubernetes: []string{"1", "", "1.32"}, + }, + wantErr: true, + }, + "multiple errors": { + info: CLIInfo{ + Ref: "", + Stream: "", + Version: "", + }, + wantErr: true, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + err := tc.info.Validate() + + if tc.wantErr { + assert.Error(err) + } else { + assert.NoError(err) + } + }) + } +} + +func TestCLIInfoValidateRequest(t *testing.T) { + testCases := map[string]struct { + info CLIInfo + wantErr bool + }{ + "valid cli info": { + info: CLIInfo{ + Ref: "test-ref", + Stream: "nightly", + Version: "v1.0.0", + }, + }, + "invalid ref": { + info: CLIInfo{ + Ref: "", + Stream: "nightly", + Version: "v1.0.0", + }, + wantErr: true, + }, + "invalid stream": { + info: CLIInfo{ + Ref: "test-ref", + Stream: "", + Version: "v1.0.0", + }, + wantErr: true, + }, + "invalid version": { + info: CLIInfo{ + Ref: "test-ref", + Stream: "nightly", + Version: "", + }, + wantErr: true, + }, + "invalid k8s versions": { + info: CLIInfo{ + Ref: "test-ref", + Stream: "nightly", + Version: "v1.0.0", + Kubernetes: []string{"v1.26.1", "v1.3.3", "v1.32"}, + }, + wantErr: true, + }, + "multiple errors": { + info: CLIInfo{ + Ref: "", + Stream: "", + Version: "", + Kubernetes: []string{"v1.26.1", "v1.3.3", "v1.32"}, + }, + wantErr: true, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + err := tc.info.ValidateRequest() + + if tc.wantErr { + assert.Error(err) + } else { + assert.NoError(err) + } + }) + } +} diff --git a/internal/versionsapi/fetcher/fetcher.go b/internal/versionsapi/fetcher/fetcher.go index fe4ea5668..930e4eebc 100644 --- a/internal/versionsapi/fetcher/fetcher.go +++ b/internal/versionsapi/fetcher/fetcher.go @@ -49,6 +49,11 @@ func (f *Fetcher) FetchImageInfo(ctx context.Context, imageInfo versionsapi.Imag return fetch(ctx, f.httpc, imageInfo) } +// FetchCLIInfo fetches the given cli info from the versions API. +func (f *Fetcher) FetchCLIInfo(ctx context.Context, cliInfo versionsapi.CLIInfo) (versionsapi.CLIInfo, error) { + return fetch(ctx, f.httpc, cliInfo) +} + type apiObject interface { ValidateRequest() error Validate() error diff --git a/internal/versionsapi/version.go b/internal/versionsapi/version.go index c1d7a7a1c..ce1284e64 100644 --- a/internal/versionsapi/version.go +++ b/internal/versionsapi/version.go @@ -167,6 +167,8 @@ const ( VersionKindUnknown VersionKind = iota // VersionKindImage is the kind for image versions. VersionKindImage + // VersionKindCLI is the kind for CLI versions. + VersionKindCLI ) // MarshalJSON marshals the VersionKind to JSON. @@ -189,6 +191,8 @@ func (k VersionKind) String() string { switch k { case VersionKindImage: return "image" + case VersionKindCLI: + return "cli" default: return "unknown" } @@ -199,6 +203,8 @@ func VersionKindFromString(s string) VersionKind { switch strings.ToLower(s) { case "image": return VersionKindImage + case "cli": + return VersionKindCLI default: return VersionKindUnknown } diff --git a/internal/versionsapi/version_test.go b/internal/versionsapi/version_test.go index 56bb70301..42dd36a14 100644 --- a/internal/versionsapi/version_test.go +++ b/internal/versionsapi/version_test.go @@ -41,16 +41,41 @@ func TestNewVersionFromShortPath(t *testing.T) { Kind: VersionKindImage, }, }, + "stable release cli": { + path: "v9.9.9", + kind: VersionKindCLI, + wantVer: Version{ + Ref: ReleaseRef, + Stream: "stable", + Version: "v9.9.9", + Kind: VersionKindCLI, + }, + }, + "release debug cli": { + path: "stream/debug/v9.9.9", + kind: VersionKindCLI, + wantVer: Version{ + Ref: ReleaseRef, + Stream: "debug", + Version: "v9.9.9", + Kind: VersionKindCLI, + }, + }, "unknown kind": { path: "v9.9.9", kind: VersionKindUnknown, wantErr: true, }, - "invalid path": { + "invalid path image": { path: "va.b.c", kind: VersionKindImage, wantErr: true, }, + "invalid path cli": { + path: "va.b.c", + kind: VersionKindCLI, + wantErr: true, + }, } for name, tc := range testCases { @@ -100,6 +125,33 @@ func TestVersionShortPath(t *testing.T) { }, want: "ref/foo/stream/debug/v9.9.9", }, + "stable release cli": { + ver: Version{ + Ref: ReleaseRef, + Stream: "stable", + Version: "v9.9.9", + Kind: VersionKindCLI, + }, + want: "v9.9.9", + }, + "release debug cli": { + ver: Version{ + Ref: ReleaseRef, + Stream: "debug", + Version: "v9.9.9", + Kind: VersionKindCLI, + }, + want: "stream/debug/v9.9.9", + }, + "branch cli": { + ver: Version{ + Ref: "foo", + Stream: "debug", + Version: "v9.9.9", + Kind: VersionKindCLI, + }, + want: "ref/foo/stream/debug/v9.9.9", + }, } for name, tc := range testCases { @@ -117,7 +169,7 @@ func TestVersionValidate(t *testing.T) { ver Version wantErr bool }{ - "valid": { + "valid image": { ver: Version{ Ref: ReleaseRef, Stream: "stable", @@ -125,7 +177,7 @@ func TestVersionValidate(t *testing.T) { Kind: VersionKindImage, }, }, - "invalid ref": { + "invalid ref image": { ver: Version{ Ref: "foo/bar", Stream: "stable", @@ -134,7 +186,7 @@ func TestVersionValidate(t *testing.T) { }, wantErr: true, }, - "invalid stream": { + "invalid stream image": { ver: Version{ Ref: ReleaseRef, Stream: "foo/bar", @@ -143,7 +195,7 @@ func TestVersionValidate(t *testing.T) { }, wantErr: true, }, - "invalid version": { + "invalid version image": { ver: Version{ Ref: ReleaseRef, Stream: "stable", @@ -152,12 +204,38 @@ func TestVersionValidate(t *testing.T) { }, wantErr: true, }, - "invalid kind": { + "valid cli": { ver: Version{ Ref: ReleaseRef, Stream: "stable", Version: "v9.9.9", - Kind: VersionKindUnknown, + Kind: VersionKindCLI, + }, + }, + "invalid ref cli": { + ver: Version{ + Ref: "foo/bar", + Stream: "stable", + Version: "v9.9.9", + Kind: VersionKindCLI, + }, + wantErr: true, + }, + "invalid stream cli": { + ver: Version{ + Ref: ReleaseRef, + Stream: "foo/bar", + Version: "v9.9.9", + Kind: VersionKindCLI, + }, + wantErr: true, + }, + "invalid version cli": { + ver: Version{ + Ref: ReleaseRef, + Stream: "stable", + Version: "v9.9.9/foo", + Kind: VersionKindCLI, }, wantErr: true, }, @@ -266,7 +344,7 @@ func TestVersionListPathURL(t *testing.T) { wantPath string wantURL string }{ - "release": { + "release image": { ver: Version{ Ref: ReleaseRef, Stream: "stable", @@ -277,7 +355,7 @@ func TestVersionListPathURL(t *testing.T) { wantPath: constants.CDNAPIPrefix + "/ref/" + ReleaseRef + "/stream/stable/versions/major/v9/image.json", wantURL: constants.CDNRepositoryURL + "/" + constants.CDNAPIPrefix + "/ref/" + ReleaseRef + "/stream/stable/versions/major/v9/image.json", }, - "release with minor": { + "release with minor image": { ver: Version{ Ref: ReleaseRef, Stream: "stable", @@ -288,7 +366,7 @@ func TestVersionListPathURL(t *testing.T) { wantPath: constants.CDNAPIPrefix + "/ref/" + ReleaseRef + "/stream/stable/versions/minor/v9.9/image.json", wantURL: constants.CDNRepositoryURL + "/" + constants.CDNAPIPrefix + "/ref/" + ReleaseRef + "/stream/stable/versions/minor/v9.9/image.json", }, - "release with patch": { + "release with patch image": { ver: Version{ Ref: ReleaseRef, Stream: "stable", @@ -299,7 +377,7 @@ func TestVersionListPathURL(t *testing.T) { wantPath: "", wantURL: "", }, - "release with unknown": { + "release with unknown image": { ver: Version{ Ref: ReleaseRef, Stream: "stable", @@ -310,7 +388,7 @@ func TestVersionListPathURL(t *testing.T) { wantPath: "", wantURL: "", }, - "release debug stream": { + "release debug stream image": { ver: Version{ Ref: ReleaseRef, Stream: "debug", @@ -321,7 +399,7 @@ func TestVersionListPathURL(t *testing.T) { wantPath: constants.CDNAPIPrefix + "/ref/" + ReleaseRef + "/stream/debug/versions/major/v9/image.json", wantURL: constants.CDNRepositoryURL + "/" + constants.CDNAPIPrefix + "/ref/" + ReleaseRef + "/stream/debug/versions/major/v9/image.json", }, - "release debug stream with minor": { + "release debug stream with minor image": { ver: Version{ Ref: ReleaseRef, Stream: "debug", @@ -332,7 +410,7 @@ func TestVersionListPathURL(t *testing.T) { wantPath: constants.CDNAPIPrefix + "/ref/" + ReleaseRef + "/stream/debug/versions/minor/v9.9/image.json", wantURL: constants.CDNRepositoryURL + "/" + constants.CDNAPIPrefix + "/ref/" + ReleaseRef + "/stream/debug/versions/minor/v9.9/image.json", }, - "branch ref": { + "branch ref image": { ver: Version{ Ref: "foo", Stream: "debug", @@ -343,7 +421,7 @@ func TestVersionListPathURL(t *testing.T) { wantPath: constants.CDNAPIPrefix + "/ref/foo/stream/debug/versions/major/v9/image.json", wantURL: constants.CDNRepositoryURL + "/" + constants.CDNAPIPrefix + "/ref/foo/stream/debug/versions/major/v9/image.json", }, - "branch ref with minor": { + "branch ref with minor image": { ver: Version{ Ref: "foo", Stream: "debug", @@ -378,7 +456,7 @@ func TestVersionArtifactPathURL(t *testing.T) { ver Version wantPath string }{ - "release": { + "release image": { ver: Version{ Ref: ReleaseRef, Stream: "stable", @@ -387,7 +465,7 @@ func TestVersionArtifactPathURL(t *testing.T) { }, wantPath: constants.CDNAPIPrefix + "/ref/" + ReleaseRef + "/stream/stable/v9.9.9", }, - "release debug stream": { + "release debug stream image": { ver: Version{ Ref: ReleaseRef, Stream: "debug", @@ -396,7 +474,7 @@ func TestVersionArtifactPathURL(t *testing.T) { }, wantPath: constants.CDNAPIPrefix + "/ref/" + ReleaseRef + "/stream/debug/v9.9.9", }, - "branch ref": { + "branch ref image": { ver: Version{ Ref: "foo", Stream: "debug", @@ -405,6 +483,33 @@ func TestVersionArtifactPathURL(t *testing.T) { }, wantPath: constants.CDNAPIPrefix + "/ref/foo/stream/debug/v9.9.9", }, + "release cli": { + ver: Version{ + Ref: ReleaseRef, + Stream: "stable", + Version: "v9.9.9", + Kind: VersionKindCLI, + }, + wantPath: constants.CDNAPIPrefix + "/ref/" + ReleaseRef + "/stream/stable/v9.9.9", + }, + "release debug stream cli": { + ver: Version{ + Ref: ReleaseRef, + Stream: "debug", + Version: "v9.9.9", + Kind: VersionKindCLI, + }, + wantPath: constants.CDNAPIPrefix + "/ref/" + ReleaseRef + "/stream/debug/v9.9.9", + }, + "branch ref cli": { + ver: Version{ + Ref: "foo", + Stream: "debug", + Version: "v9.9.9", + Kind: VersionKindCLI, + }, + wantPath: constants.CDNAPIPrefix + "/ref/foo/stream/debug/v9.9.9", + }, } for name, tc := range testCases { @@ -422,6 +527,7 @@ func TestVersionArtifactPathURL(t *testing.T) { func TestVersionKindUnMarshalJson(t *testing.T) { testCases := map[string]VersionKind{ `"image"`: VersionKindImage, + `"cli"`: VersionKindCLI, `"unknown"`: VersionKindUnknown, } @@ -444,6 +550,7 @@ func TestVersionKindUnMarshalJson(t *testing.T) { func TestVersionKindFromString(t *testing.T) { testCases := map[string]VersionKind{ "image": VersionKindImage, + "cli": VersionKindCLI, "unknown": VersionKindUnknown, }