From c75935e248c7f026997d2c23e8af04ef3e86cd97 Mon Sep 17 00:00:00 2001 From: anshlykov Date: Sun, 13 Sep 2020 23:50:27 +0300 Subject: [PATCH 1/2] skaffold deploy -t flag See #4455 --- cmd/skaffold/app/cmd/deploy.go | 16 ++++++ cmd/skaffold/app/cmd/deploy_test.go | 21 ++++++++ cmd/skaffold/app/cmd/flags.go | 2 +- docs/content/en/docs/references/cli/_index.md | 2 + pkg/skaffold/build/tag/util.go | 15 ++++++ pkg/skaffold/build/tag/util_test.go | 54 +++++++++++++++++++ 6 files changed, 109 insertions(+), 1 deletion(-) diff --git a/cmd/skaffold/app/cmd/deploy.go b/cmd/skaffold/app/cmd/deploy.go index 59f3cd1b473..4ba3fc4eb89 100644 --- a/cmd/skaffold/app/cmd/deploy.go +++ b/cmd/skaffold/app/cmd/deploy.go @@ -27,6 +27,7 @@ import ( "github.com/GoogleContainerTools/skaffold/cmd/skaffold/app/flags" "github.com/GoogleContainerTools/skaffold/cmd/skaffold/app/tips" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build" + "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/tag" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest" ) @@ -88,6 +89,21 @@ func getArtifactsToDeploy(out io.Writer, fromFile, fromCLI []build.Artifact, art deployed = build.MergeWithPreviousBuilds(fromCLI, deployed) deployed = build.MergeWithPreviousBuilds(fromFile, deployed) + if opts.CustomTag != "" { + for i := range deployed { + artifact := &deployed[i] + if artifact.Tag == "" { + artifact.Tag = artifact.ImageName + ":" + opts.CustomTag + } else { + newTag, err := tag.SetImageTag(artifact.Tag, opts.CustomTag) + if err != nil { + return nil, err + } + artifact.Tag = newTag + } + } + } + // Check that every image has a non empty tag for _, d := range deployed { if d.Tag == "" { diff --git a/cmd/skaffold/app/cmd/deploy_test.go b/cmd/skaffold/app/cmd/deploy_test.go index 7724ae6a2d2..fb48b926324 100644 --- a/cmd/skaffold/app/cmd/deploy_test.go +++ b/cmd/skaffold/app/cmd/deploy_test.go @@ -32,6 +32,7 @@ func TestGetDeployedArtifacts(t *testing.T) { fromFile []build.Artifact fromCLI []build.Artifact expected []build.Artifact + customTag string shouldErr bool }{ { @@ -82,9 +83,29 @@ func TestGetDeployedArtifacts(t *testing.T) { fromCLI: nil, shouldErr: true, }, + { + description: "override tag", + artifacts: []*latest.Artifact{{ImageName: "image1"}, {ImageName: "image2"}}, + fromFile: []build.Artifact{{ImageName: "image1", Tag: "image1:tag"}}, + fromCLI: []build.Artifact{{ImageName: "image2", Tag: "image2:tag"}}, + expected: []build.Artifact{{ImageName: "image1", Tag: "image1:test"}, {ImageName: "image2", Tag: "image2:test"}}, + customTag: "test", + }, + { + description: "override missing tag", + artifacts: []*latest.Artifact{{ImageName: "image1"}, {ImageName: "image2"}}, + fromFile: nil, + fromCLI: nil, + expected: []build.Artifact{{ImageName: "image1", Tag: "image1:test"}, {ImageName: "image2", Tag: "image2:test"}}, + customTag: "test", + }, } for _, test := range tests { testutil.Run(t, test.description, func(t *testutil.T) { + if test.customTag != "" { + t.Override(&opts.CustomTag, test.customTag) + } + deployed, err := getArtifactsToDeploy(ioutil.Discard, test.fromFile, test.fromCLI, test.artifacts) t.CheckErrorAndDeepEqual(test.shouldErr, err, test.expected, deployed) diff --git a/cmd/skaffold/app/cmd/flags.go b/cmd/skaffold/app/cmd/flags.go index 0c90174381f..a760a3a38cb 100644 --- a/cmd/skaffold/app/cmd/flags.go +++ b/cmd/skaffold/app/cmd/flags.go @@ -271,7 +271,7 @@ var flagRegistry = []Flag{ Value: &opts.CustomTag, DefValue: "", FlagAddMethod: "StringVar", - DefinedOn: []string{"build", "debug", "dev", "run"}, + DefinedOn: []string{"build", "debug", "dev", "run", "deploy"}, }, { Name: "minikube-profile", diff --git a/docs/content/en/docs/references/cli/_index.md b/docs/content/en/docs/references/cli/_index.md index 2432c36a463..32ab94f23cc 100644 --- a/docs/content/en/docs/references/cli/_index.md +++ b/docs/content/en/docs/references/cli/_index.md @@ -493,6 +493,7 @@ Options: --rpc-port=50051: tcp port to expose event API --skip-render=false: Don't render the manifests, just deploy them --status-check=true: Wait for deployed resources to stabilize + -t, --tag='': The optional custom tag to use for images which overrides the current Tagger configuration --tail=false: Stream logs from deployed objects (true by default for `skaffold dev` and `skaffold debug`) --toot=false: Emit a terminal beep after the deploy is complete --wait-for-deletions=true: Wait for pending deletions to complete before a deployment @@ -528,6 +529,7 @@ Env vars: * `SKAFFOLD_RPC_PORT` (same as `--rpc-port`) * `SKAFFOLD_SKIP_RENDER` (same as `--skip-render`) * `SKAFFOLD_STATUS_CHECK` (same as `--status-check`) +* `SKAFFOLD_TAG` (same as `--tag`) * `SKAFFOLD_TAIL` (same as `--tail`) * `SKAFFOLD_TOOT` (same as `--toot`) * `SKAFFOLD_WAIT_FOR_DELETIONS` (same as `--wait-for-deletions`) diff --git a/pkg/skaffold/build/tag/util.go b/pkg/skaffold/build/tag/util.go index b705a853338..2786bbe008b 100644 --- a/pkg/skaffold/build/tag/util.go +++ b/pkg/skaffold/build/tag/util.go @@ -40,3 +40,18 @@ func StripTags(taggedImages []string) []string { } return images } + +func SetImageTag(image, tag string) (string, error) { + parsed, err := docker.ParseReference(image) + if err != nil { + return "", err + } + image = parsed.BaseName + if tag != "" { + image = image + ":" + tag + } + if parsed.Digest != "" { + image = image + "@" + parsed.Digest + } + return image, nil +} diff --git a/pkg/skaffold/build/tag/util_test.go b/pkg/skaffold/build/tag/util_test.go index bf1de556c8e..7424747002c 100644 --- a/pkg/skaffold/build/tag/util_test.go +++ b/pkg/skaffold/build/tag/util_test.go @@ -59,3 +59,57 @@ func TestStripTags(t *testing.T) { }) } } + +func TestSetImageTag(t *testing.T) { + tests := []struct { + description string + image string + tag string + expectedImage string + shouldErr bool + }{ + { + description: "image with tag", + image: "gcr.io/foo/bar:latest", + tag: "test-1", + expectedImage: "gcr.io/foo/bar:test-1", + }, + { + description: "image with tag and digest", + image: "gcr.io/foo/bar:latest@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc", + tag: "test-2", + expectedImage: "gcr.io/foo/bar:test-2@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc", + }, + { + description: "image without tag and digest", + image: "gcr.io/foo/bar", + tag: "test-3", + expectedImage: "gcr.io/foo/bar:test-3", + }, + { + description: "empty tag", + image: "gcr.io/foo/bar:test-4", + expectedImage: "gcr.io/foo/bar", + }, + { + description: "image with digest", + image: "gcr.io/foo/bar@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc", + tag: "test-5", + expectedImage: "gcr.io/foo/bar:test-5@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc", + }, + { + description: "invalid reference", + image: "!!invalid!!", + shouldErr: true, + }, + } + + for _, test := range tests { + testutil.Run(t, test.description, func(t *testutil.T) { + t.Parallel() + + image, err := SetImageTag(test.image, test.tag) + t.CheckErrorAndDeepEqual(test.shouldErr, err, test.expectedImage, image) + }) + } +} From 23d16901139ca185bbf709f15599e26dad499290 Mon Sep 17 00:00:00 2001 From: anshlykov Date: Thu, 17 Sep 2020 17:01:16 +0300 Subject: [PATCH 2/2] refactor --- cmd/skaffold/app/cmd/deploy.go | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/cmd/skaffold/app/cmd/deploy.go b/cmd/skaffold/app/cmd/deploy.go index 4ba3fc4eb89..bdce88c8782 100644 --- a/cmd/skaffold/app/cmd/deploy.go +++ b/cmd/skaffold/app/cmd/deploy.go @@ -89,9 +89,26 @@ func getArtifactsToDeploy(out io.Writer, fromFile, fromCLI []build.Artifact, art deployed = build.MergeWithPreviousBuilds(fromCLI, deployed) deployed = build.MergeWithPreviousBuilds(fromFile, deployed) + deployed, err := applyCustomTag(deployed) + if err != nil { + return nil, err + } + + // Check that every image has a non empty tag + for _, d := range deployed { + if d.Tag == "" { + tips.PrintUseRunVsDeploy(out) + return nil, fmt.Errorf("no tag provided for image [%s]", d.ImageName) + } + } + + return deployed, nil +} + +func applyCustomTag(artifacts []build.Artifact) ([]build.Artifact, error) { if opts.CustomTag != "" { - for i := range deployed { - artifact := &deployed[i] + var result []build.Artifact + for _, artifact := range artifacts { if artifact.Tag == "" { artifact.Tag = artifact.ImageName + ":" + opts.CustomTag } else { @@ -101,16 +118,9 @@ func getArtifactsToDeploy(out io.Writer, fromFile, fromCLI []build.Artifact, art } artifact.Tag = newTag } + result = append(result, artifact) } + return result, nil } - - // Check that every image has a non empty tag - for _, d := range deployed { - if d.Tag == "" { - tips.PrintUseRunVsDeploy(out) - return nil, fmt.Errorf("no tag provided for image [%s]", d.ImageName) - } - } - - return deployed, nil + return artifacts, nil }