From f205e7c1af33220bfbee3650ade0433a1150b48c Mon Sep 17 00:00:00 2001 From: Andreas Salhus Bakseter <141913422+baksetercx@users.noreply.github.com> Date: Tue, 14 Jan 2025 14:25:14 +0100 Subject: [PATCH 1/3] Add image digest to Helm deploy --- pkg/build/build.go | 10 +++++++--- pkg/build/build_test.go | 10 ++++------ pkg/deploy/deploy.go | 41 +++++++++++++++++++++++++++++++++++++++ pkg/deploy/deploy_test.go | 36 ++++++++++++++++++++++++++++++++++ pkg/deploy/helm.go | 11 +++++++++-- pkg/deploy/helm_test.go | 28 +++++++++++++++++++------- pkg/run/run.go | 2 +- 7 files changed, 119 insertions(+), 19 deletions(-) create mode 100644 pkg/deploy/deploy_test.go diff --git a/pkg/build/build.go b/pkg/build/build.go index 5e2f432..60d2563 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -18,7 +18,11 @@ import ( "github.com/urfave/cli/v3" ) -const commandName = "build" +const ( + commandName = "build" + DefaultElviaContainerRegistry = "containerregistryelvia.azurecr.io" + DefaultCacheTag = "latest-cache" +) func Command() *cli.Command { return &cli.Command{ @@ -54,7 +58,7 @@ func Command() *cli.Command { &cli.StringFlag{ Name: "cache-tag", Usage: "The tag to use for the cache image.", - Value: "latest-cache", + Value: DefaultCacheTag, Sources: cli.EnvVars("3LV_CACHE_TAG"), }, &cli.StringFlag{ @@ -173,7 +177,7 @@ func Build(_ context.Context, c *cli.Command) error { } cacheTag := c.String("cache-tag") - registry := utils.StringWithDefault(c.String("registry"), "containerregistryelvia.azurecr.io") + registry := utils.StringWithDefault(c.String("registry"), DefaultElviaContainerRegistry) push := c.Bool("push") skipAuthentication := c.Bool("skip-authentication") || !push diff --git a/pkg/build/build_test.go b/pkg/build/build_test.go index 8253263..49ae1c8 100644 --- a/pkg/build/build_test.go +++ b/pkg/build/build_test.go @@ -124,10 +124,9 @@ func TestBuildCommand2(t *testing.T) { dockerfilePath = "Dockerfile" buildContext = "." imageName = "ghcr.io/test-image" - cacheTag = "latest-cache" ) - imageNameWithCacheTag := imageName + ":" + cacheTag + imageNameWithCacheTag := imageName + ":" + DefaultCacheTag expectedCommandString := strings.Join( []string{ @@ -152,7 +151,7 @@ func TestBuildCommand2(t *testing.T) { dockerfilePath, buildContext, imageName, - cacheTag, + DefaultCacheTag, []string{}, &command.RunOptions{DryRun: true}, ) @@ -171,10 +170,9 @@ func TestBuildCommand3(t *testing.T) { dockerfilePath = "Dockerfile" buildContext = "." imageName = "ghcr.io/test-image" - cacheTag = "latest-cache" ) - imageNameWithCacheTag := imageName + ":" + cacheTag + imageNameWithCacheTag := imageName + ":" + DefaultCacheTag additionalTags := []string{"latest", "v42.0.1", "v420alpha"} expectedCommandString := strings.Join( @@ -206,7 +204,7 @@ func TestBuildCommand3(t *testing.T) { dockerfilePath, buildContext, imageName, - cacheTag, + DefaultCacheTag, additionalTags, &command.RunOptions{DryRun: true}, ) diff --git a/pkg/deploy/deploy.go b/pkg/deploy/deploy.go index b7de8be..1146ec7 100644 --- a/pkg/deploy/deploy.go +++ b/pkg/deploy/deploy.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/3lvia/cli/pkg/auth" + "github.com/3lvia/cli/pkg/build" "github.com/3lvia/cli/pkg/command" "github.com/3lvia/cli/pkg/shared" "github.com/3lvia/cli/pkg/style" @@ -199,6 +200,7 @@ func Deploy(ctx context.Context, c *cli.Command) error { return configForApplication.HelmValuesFile }() imageTag := c.String("image-tag") + imageDigest := getImageDigest(systemName, applicationName, imageTag) commitHash, err := utils.ResolveCommitHash(c.String("commit-hash")) if err != nil { @@ -261,6 +263,7 @@ func Deploy(ctx context.Context, c *cli.Command) error { environment, workloadType, imageTag, + imageDigest, repositoryName, commitHash, dryRun, @@ -428,3 +431,41 @@ func setupKubernetes( return nil } + +func dockerInspectCommand( + imageName string, + runOptions *command.RunOptions, +) command.Output { + return command.Run( + *exec.Command( + "docker", + "inspect", + "--format", + "{{index .RepoDigests 0}}", + imageName+":"+build.DefaultCacheTag, + ), + runOptions, + ) +} + +func getImageDigest( + systemName string, + applicationName string, + imageTag string, +) string { + imageName, err := build.GetImageName( + build.DefaultElviaContainerRegistry, + systemName, + applicationName, + ) + if err != nil { + return "" + } + + dockerInspectCommandOutput := dockerInspectCommand(imageName+":"+imageTag, nil) + if command.IsError(dockerInspectCommandOutput) { + return "" + } + + return dockerInspectCommandOutput.Output +} diff --git a/pkg/deploy/deploy_test.go b/pkg/deploy/deploy_test.go new file mode 100644 index 0000000..b364e25 --- /dev/null +++ b/pkg/deploy/deploy_test.go @@ -0,0 +1,36 @@ +package deploy + +import ( + "strings" + "testing" + + "github.com/3lvia/cli/pkg/command" +) + +func TestDockerInspectCommand(t *testing.T) { + t.Parallel() + + const imageName = "ghcr.io/3lvia/core/demo-api" + + expectedCommandString := strings.Join( + []string{ + "docker", + "inspect", + "--format", + "{{index .RepoDigests 0}}", + imageName + ":latest-cache", + }, + " ", + ) + + actualCommand := dockerInspectCommand( + imageName, + &command.RunOptions{DryRun: true}, + ) + + command.ExpectedCommandStringEqualsActualCommand( + t, + expectedCommandString, + actualCommand, + ) +} diff --git a/pkg/deploy/helm.go b/pkg/deploy/helm.go index d1d3d3d..3a1c262 100644 --- a/pkg/deploy/helm.go +++ b/pkg/deploy/helm.go @@ -62,6 +62,7 @@ func helmDeployCommand( environment string, workloadType string, imageTag string, + imageDigest string, repositoryName string, commitHash string, dryRun bool, @@ -103,13 +104,19 @@ func helmDeployCommand( "--set-string", "environment="+environment, "--set-string", - "image.tag="+imageTag, - "--set-string", "labels.repositoryName="+repositoryName, "--set-string", "labels.commitHash=\""+commitHash+"\"", ) + if imageTag != "" { + cmd.Args = append(cmd.Args, "--set-string", "image.tag="+imageTag) + } + + if imageDigest != "" { + cmd.Args = append(cmd.Args, "--set-string", "image.digest="+imageDigest) + } + if dryRun { cmd.Args = append(cmd.Args, "--dry-run") } diff --git a/pkg/deploy/helm_test.go b/pkg/deploy/helm_test.go index 2cb6e6a..f0bb933 100644 --- a/pkg/deploy/helm_test.go +++ b/pkg/deploy/helm_test.go @@ -101,6 +101,7 @@ func TestHelmDeployCommand1(t *testing.T) { environment = "dev" workloadType = "deployment" imageTag = "v12" + imageDigest = "sha256:1234567890" repositoryName = "core" commitHash = "123456" ) @@ -120,11 +121,13 @@ func TestHelmDeployCommand1(t *testing.T) { "--set-string", "environment=" + environment, "--set-string", - "image.tag=" + imageTag, - "--set-string", "labels.repositoryName=" + repositoryName, "--set-string", "labels.commitHash=\"" + commitHash + "\"", + "--set-string", + "image.tag=" + imageTag, + "--set-string", + "image.digest=" + imageDigest, }, " ", ) @@ -136,6 +139,7 @@ func TestHelmDeployCommand1(t *testing.T) { environment, workloadType, imageTag, + imageDigest, repositoryName, commitHash, false, @@ -160,6 +164,7 @@ func TestHelmDeployCommand2(t *testing.T) { environment = "prod" workloadType = "statefulset" imageTag = "v420" + imageDigest = "sha256:abcdef" repositoryName = "core-not-monorepo" commitHash = "abcdef" ) @@ -179,11 +184,13 @@ func TestHelmDeployCommand2(t *testing.T) { "--set-string", "environment=" + environment, "--set-string", - "image.tag=" + imageTag, - "--set-string", "labels.repositoryName=" + repositoryName, "--set-string", "labels.commitHash=\"" + commitHash + "\"", + "--set-string", + "image.tag=" + imageTag, + "--set-string", + "image.digest=" + imageDigest, }, " ", ) @@ -195,6 +202,7 @@ func TestHelmDeployCommand2(t *testing.T) { environment, workloadType, imageTag, + imageDigest, repositoryName, commitHash, false, @@ -219,6 +227,7 @@ func TestHelmDeployCommand3(t *testing.T) { environment = "prod" workloadType = "job" imageTag = "v420" + imageDigest = "sha256:abcdef" repositoryName = "core-not-monorepo" commitHash = "abcdef" ) @@ -230,6 +239,7 @@ func TestHelmDeployCommand3(t *testing.T) { environment, workloadType, imageTag, + imageDigest, repositoryName, commitHash, false, @@ -251,7 +261,8 @@ func TestHelmDeployCommand4(t *testing.T) { applicationName = "demo-api" environment = "prod" workloadType = "deployment" - imageTag = "v420" + imageTag = "" + imageDigest = "sha256:abcdef" repositoryName = "iss-demo-api" commitHash = "abcdef" ) @@ -271,11 +282,11 @@ func TestHelmDeployCommand4(t *testing.T) { "--set-string", "environment=" + environment, "--set-string", - "image.tag=" + imageTag, - "--set-string", "labels.repositoryName=" + repositoryName, "--set-string", "labels.commitHash=\"" + commitHash + "\"", + "--set-string", + "image.digest=" + imageDigest, }, " ", ) @@ -287,6 +298,7 @@ func TestHelmDeployCommand4(t *testing.T) { environment, workloadType, imageTag, + imageDigest, repositoryName, commitHash, false, @@ -311,6 +323,7 @@ func TestHelmDeployCommand5(t *testing.T) { environment = "prod" workloadType = "statefulset" imageTag = "v420" + imageDigest = "sha256:abcdef" repositoryName = "iss-demo-api" commitHash = "abcdef" ) @@ -322,6 +335,7 @@ func TestHelmDeployCommand5(t *testing.T) { environment, workloadType, imageTag, + imageDigest, repositoryName, commitHash, false, diff --git a/pkg/run/run.go b/pkg/run/run.go index ac05267..067814a 100644 --- a/pkg/run/run.go +++ b/pkg/run/run.go @@ -124,7 +124,7 @@ func generateComposeFile( composeTemplates, ComposeFileVariables{ ApplicationName: applicationName, - ImageName: imageName + ":latest-cache", + ImageName: imageName + build.DefaultCacheTag, Port: helmValues.Service.Port, TargetPort: helmValues.Service.TargetPort, EnvironmentVariables: helmValues.GetEnvironmentVariablesMap(), From 6510c2cb9c99aa6801eaf3d89ec0076dbebe1166 Mon Sep 17 00:00:00 2001 From: Andreas Salhus Bakseter <141913422+baksetercx@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:15:55 +0100 Subject: [PATCH 2/3] Fix rate-limit problem --- .github/workflows/e2e-tests.yml | 3 +++ pkg/upgrade/upgrade.go | 12 ++++++------ pkg/utils/utils.go | 9 +++++++++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 3e5a82a..e1cfd53 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -43,3 +43,6 @@ jobs: - name: 'Run tests for ${{ matrix.command }} command' run: './tests/${{ matrix.command }}/run_tests.sh' + env: + # Increases rate-limit of when downloading 3lv from GitHub in tests for '3lv upgrade'. + GITHUB_TOKEN: ${{ github.token }} diff --git a/pkg/upgrade/upgrade.go b/pkg/upgrade/upgrade.go index 2d5a21f..5d5d1be 100644 --- a/pkg/upgrade/upgrade.go +++ b/pkg/upgrade/upgrade.go @@ -17,7 +17,7 @@ import ( "github.com/3lvia/cli/pkg/command" "github.com/3lvia/cli/pkg/style" - "github.com/google/go-github/v67/github" + "github.com/3lvia/cli/pkg/utils" "github.com/urfave/cli/v3" "golang.org/x/mod/semver" ) @@ -163,6 +163,8 @@ func Upgrade(ctx context.Context, c *cli.Command, version string) error { } func getLatestBinaryURL(ctx context.Context) (string, error) { + githubClient := utils.GetAuthenticatedGithubClient() + if runtime.GOOS == "windows" { return "", errors.New( @@ -178,9 +180,7 @@ func getLatestBinaryURL(ctx context.Context) (string, error) { return "", fmt.Errorf("Auto-upgrade is not supported on %s", runtime.GOARCH) } - client := github.NewClient(nil) - - release, _, err := client.Repositories.GetLatestRelease(ctx, "3lvia", "cli") + release, _, err := githubClient.Repositories.GetLatestRelease(ctx, "3lvia", "cli") if err != nil { return "", err } @@ -204,9 +204,9 @@ func getLatestBinaryURL(ctx context.Context) (string, error) { } func GetLatestCLIVersion(ctx context.Context) (string, error) { - client := github.NewClient(nil) + githubClient := utils.GetAuthenticatedGithubClient() - release, _, err := client.Repositories.GetLatestRelease(ctx, "3lvia", "cli") + release, _, err := githubClient.Repositories.GetLatestRelease(ctx, "3lvia", "cli") if err != nil { return "", err } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index c4f3010..5cc65bf 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/3lvia/cli/pkg/style" + "github.com/google/go-github/v67/github" ) func RemoveZeroValues(slice []string) []string { @@ -160,3 +161,11 @@ func FirstNonEmpty(values ...string) string { return "" } + +func GetAuthenticatedGithubClient() *github.Client { + if os.Getenv("CI") == "1" { + return github.NewClient(nil).WithAuthToken(os.Getenv("GITHUB_TOKEN")) + } + + return github.NewClient(nil) +} From e2c46d4ae59f39c56495a863bc1278ec59db69bf Mon Sep 17 00:00:00 2001 From: Andreas Salhus Bakseter <141913422+baksetercx@users.noreply.github.com> Date: Tue, 21 Jan 2025 14:37:45 +0100 Subject: [PATCH 3/3] 0.29.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index b79f04f..ae6dd4e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.28.3 +0.29.0