diff --git a/pkg/skaffold/deploy/helm.go b/pkg/skaffold/deploy/helm.go index befb00daf68..ee1a7d2366d 100644 --- a/pkg/skaffold/deploy/helm.go +++ b/pkg/skaffold/deploy/helm.go @@ -26,6 +26,7 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "sort" "strconv" "strings" @@ -47,6 +48,14 @@ import ( "github.com/GoogleContainerTools/skaffold/pkg/skaffold/warnings" ) +var ( + // versionRegex extracts version from "helm version --client", for instance: "2.14.0-rc.2" + versionRegex = regexp.MustCompile(`\"v(\d[\w\.\-\.]+)`) + + // helm3Version represents the version cut-off for helm3 behavior + helm3Version = semver.MustParse("3.0.0-beta.0") +) + // HelmDeployer deploys workflows using the helm CLI type HelmDeployer struct { *latest.HelmDeploy @@ -87,10 +96,9 @@ func (h *HelmDeployer) Deploy(ctx context.Context, out io.Writer, builds []build hv, err := h.binVer(ctx) if err != nil { - logrus.Debugf("failed to parse binary version: %v", err) - } else { - logrus.Debugf("deploying with helm version %v", hv) + return NewDeployErrorResult(errors.Wrapf(err, "failed to determine binary version")) } + logrus.Infof("Deploying with helm v%s ...", hv) var dRes []Artifact nsMap := map[string]struct{}{} @@ -98,7 +106,7 @@ func (h *HelmDeployer) Deploy(ctx context.Context, out io.Writer, builds []build // Deploy every release for _, r := range h.Releases { - results, err := h.deployRelease(ctx, out, r, builds, valuesSet) + results, err := h.deployRelease(ctx, out, r, builds, valuesSet, hv) if err != nil { releaseName, _ := expand(r.Name, nil) @@ -182,13 +190,22 @@ func (h *HelmDeployer) Dependencies() ([]string, error) { // Cleanup deletes what was deployed by calling Deploy. func (h *HelmDeployer) Cleanup(ctx context.Context, out io.Writer) error { + hv, err := h.binVer(ctx) + if err != nil { + return errors.Wrap(err, "binary version") + } + for _, r := range h.Releases { releaseName, err := expand(r.Name, nil) if err != nil { return errors.Wrap(err, "cannot parse the release name template") } - if err := h.exec(ctx, out, false, "delete", releaseName, "--purge"); err != nil { + args := []string{"delete", releaseName} + if hv.LT(helm3Version) { + args = append(args, "--purge") + } + if err := h.exec(ctx, out, false, args...); err != nil { return errors.Wrapf(err, "deleting %s", releaseName) } } @@ -223,7 +240,7 @@ func (h *HelmDeployer) exec(ctx context.Context, out io.Writer, useSecrets bool, } // deployRelease deploys a single release -func (h *HelmDeployer) deployRelease(ctx context.Context, out io.Writer, r latest.HelmRelease, builds []build.Artifact, valuesSet map[string]bool) ([]Artifact, error) { +func (h *HelmDeployer) deployRelease(ctx context.Context, out io.Writer, r latest.HelmRelease, builds []build.Artifact, valuesSet map[string]bool, helmVersion semver.Version) ([]Artifact, error) { releaseName, err := expand(r.Name, nil) if err != nil { return nil, errors.Wrap(err, "cannot parse the release name template") @@ -235,9 +252,10 @@ func (h *HelmDeployer) deployRelease(ctx context.Context, out io.Writer, r lates flags: h.Flags.Upgrade, force: h.forceDeploy, chartPath: r.ChartPath, + helmVersion: helmVersion, } - if err := h.exec(ctx, ioutil.Discard, false, getArgs(releaseName)...); err != nil { + if err := h.exec(ctx, ioutil.Discard, false, getArgs(helmVersion, releaseName)...); err != nil { color.Yellow.Fprintf(out, "Helm release %s not installed. Installing...\n", releaseName) opts.upgrade = false @@ -294,7 +312,7 @@ func (h *HelmDeployer) deployRelease(ctx context.Context, out io.Writer, r lates var b bytes.Buffer // Be accepting of failure - if err := h.exec(ctx, &b, false, getArgs(releaseName)...); err != nil { + if err := h.exec(ctx, &b, false, getArgs(helmVersion, releaseName)...); err != nil { logrus.Warnf(err.Error()) return nil, nil } @@ -311,24 +329,19 @@ func (h *HelmDeployer) binVer(ctx context.Context) (semver.Version, error) { } var b bytes.Buffer - if err := h.exec(ctx, &b, false, "version", "--short", "-c"); err != nil { - return semver.Version{}, errors.Wrap(err, "helm version") + // Omits --client & --short, as some versions do not support it (v3.0.0-beta, for instance) + if err := h.exec(ctx, &b, false, "version"); err != nil { + return semver.Version{}, errors.Wrapf(err, "helm version command failed: %s", b.String()) } - bs := b.Bytes() - - // raw for 3.1: "v3.1.0+gb29d20b" - // raw for 2.15: "Client: v2.15.1+gcf1de4f" - raw := string(bs) - idx := strings.Index(raw, "v") - if idx < 0 { - return semver.Version{}, fmt.Errorf("v not found in output: %q", raw) + raw := b.String() + matches := versionRegex.FindStringSubmatch(raw) + if len(matches) == 0 { + return semver.Version{}, fmt.Errorf("unable to parse output: %q", raw) } - // Only read up to a + sign if provided: semver does not understand + notation. - rv := strings.Split(raw[idx+1:], "+")[0] - v, err := semver.Make(rv) + v, err := semver.Make(matches[1]) if err != nil { - return semver.Version{}, errors.Wrap(err, "semver make") + return semver.Version{}, errors.Wrapf(err, "semver make: %q", matches[1]) } h.bV = v @@ -343,6 +356,7 @@ type installOpts struct { chartPath string upgrade bool force bool + helmVersion semver.Version } // installArgs calculates the correct arguments to "helm install" @@ -360,7 +374,11 @@ func installArgs(r latest.HelmRelease, builds []build.Artifact, valuesSet map[st args = append(args, "--recreate-pods") } } else { - args = append(args, "install", "--name", o.releaseName) + args = append(args, "install") + if o.helmVersion.LT(helm3Version) { + args = append(args, "--name") + } + args = append(args, o.releaseName) args = append(args, o.flags...) } @@ -469,8 +487,12 @@ func installArgs(r latest.HelmRelease, builds []build.Artifact, valuesSet map[st } // getArgs calculates the correct arguments to "helm get" -func getArgs(releaseName string) []string { - return []string{"get", releaseName} +func getArgs(v semver.Version, releaseName string) []string { + args := []string{"get"} + if v.GTE(helm3Version) { + args = append(args, "all") + } + return append(args, releaseName) } // envVarForImage creates an environment map for an image and digest tag (fqn) diff --git a/pkg/skaffold/deploy/helm_test.go b/pkg/skaffold/deploy/helm_test.go index db357abe37b..83a1a3109b3 100644 --- a/pkg/skaffold/deploy/helm_test.go +++ b/pkg/skaffold/deploy/helm_test.go @@ -23,8 +23,6 @@ import ( "path/filepath" "testing" - "github.com/blang/semver" - "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/config" "github.com/GoogleContainerTools/skaffold/pkg/skaffold/event" @@ -322,6 +320,16 @@ HOOKS: MANIFEST: ` +var ( + // Output strings to emulate different versions of Helm + version20 = `Client: &version.Version{SemVer:"v2.15.1", GitCommit:"cf1de4f8ba70eded310918a8af3a96bfe8e7683b", GitTreeState:"clean"}\nError: cannot connect to Tiller\n` + version21 = `Client: &version.Version{SemVer:"v2.15.1", GitCommit:"cf1de4f8ba70eded310918a8af3a96bfe8e7683b", GitTreeState:"clean"}\nServer: &version.Version{SemVer:"v2.16.1", GitCommit:"bbdfe5e7803a12bbdf97e94cd847859890cf4050", GitTreeState:"clean"}\n` + version21rc = `Client: &version.Version{SemVer:"v2.14.0-rc.2", GitCommit:"05811b84a3f93603dd6c2fcfe57944dfa7ab7fd0", GitTreeState:"clean"}\nServer: &version.Version{SemVer:"v2.16.1", GitCommit:"bbdfe5e7803a12bbdf97e94cd847859890cf4050", GitTreeState:"clean"}\n` + version30b = `version.BuildInfo{Version:"v3.0.0-beta.3", GitCommit:"5cb923eecbe80d1ad76399aee234717c11931d9a", GitTreeState:"clean", GoVersion:"go1.12.9"}` + version30 = `version.BuildInfo{Version:"v3.0.0", GitCommit:"e29ce2a54e96cd02ccfce88bee4f58bb6e2a28b6", GitTreeState:"clean", GoVersion:"go1.13.4"}` + version31 = `version.BuildInfo{Version:"v3.1.1", GitCommit:"afe70585407b420d0097d07b21c47dc511525ac8", GitTreeState:"clean", GoVersion:"go1.13.8"}` +) + func TestHelmDeploy(t *testing.T) { tmpDir, err := ioutil.TempDir("", "TestHelmDeploy") if err != nil { @@ -339,7 +347,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy success", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -347,10 +355,50 @@ func TestHelmDeploy(t *testing.T) { runContext: makeRunContext(testDeployConfig, false), builds: testBuilds, }, + { + description: "helm3.0beta deploy success", + commands: testutil. + CmdRunWithOutput("helm version", version30b). + AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"), + runContext: makeRunContext(testDeployConfig, false), + builds: testBuilds, + }, + { + description: "helm3.0 deploy success", + commands: testutil. + CmdRunWithOutput("helm version", version30). + AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"), + runContext: makeRunContext(testDeployConfig, false), + builds: testBuilds, + }, + { + description: "helm3.1 deploy success", + commands: testutil. + CmdRunWithOutput("helm version", version31). + AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"), + runContext: makeRunContext(testDeployConfig, false), + builds: testBuilds, + }, + { + description: "helm3 unparseable version", + commands: testutil.CmdRunWithOutput("helm version", "gobbledygook"), + runContext: makeRunContext(testDeployConfig, false), + builds: testBuilds, + shouldErr: true, + }, { description: "deploy success with recreatePods", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21rc). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm --recreate-pods examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -361,7 +409,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy success with skipBuildDependencies", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21rc). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"), @@ -371,7 +419,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy should error for unmatched parameter", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -383,7 +431,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy success remote chart with skipBuildDependencies", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm stable/chartmuseum --namespace testNamespace --set-string image.tag=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"), @@ -393,7 +441,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy error remote chart without skipBuildDependencies", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm-remote --kubeconfig kubeconfig"). AndRunErr("helm --kube-context kubecontext dep build stable/chartmuseum --kubeconfig kubeconfig", fmt.Errorf("building helm dependencies")), runContext: makeRunContext(testDeployRemoteChart, false), @@ -403,7 +451,7 @@ func TestHelmDeploy(t *testing.T) { { description: "get failure should install not upgrade", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21). AndRunErr("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig", fmt.Errorf("not found")). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext install --name skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -411,10 +459,21 @@ func TestHelmDeploy(t *testing.T) { runContext: makeRunContext(testDeployConfig, false), builds: testBuilds, }, + { + description: "helm3 get failure should install not upgrade", + commands: testutil. + CmdRunWithOutput("helm version", version31). + AndRunErr("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig", fmt.Errorf("not found")). + AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext install skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig"), + runContext: makeRunContext(testDeployConfig, false), + builds: testBuilds, + }, { description: "get failure should install not upgrade with helm image strategy", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21). AndRunErr("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig", fmt.Errorf("not found")). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext install --name skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image.repository=docker.io:5000/skaffold-helm,image.tag=3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -425,7 +484,7 @@ func TestHelmDeploy(t *testing.T) { { description: "helm image strategy with explicit registry should set the Helm registry value", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21). AndRunErr("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig", fmt.Errorf("not found")). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext install --name skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image.registry=docker.io:5000,image.repository=skaffold-helm,image.tag=3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -436,7 +495,7 @@ func TestHelmDeploy(t *testing.T) { { description: "get success should upgrade by force, not install", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm --force examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -447,7 +506,7 @@ func TestHelmDeploy(t *testing.T) { { description: "get success should upgrade without force, not install", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -458,7 +517,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy error", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRunErr("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig", fmt.Errorf("unexpected error")). @@ -470,7 +529,7 @@ func TestHelmDeploy(t *testing.T) { { description: "dep build error", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRunErr("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig", fmt.Errorf("unexpected error")). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -480,22 +539,48 @@ func TestHelmDeploy(t *testing.T) { builds: testBuilds, }, { - description: "should package chart and deploy", + description: "helm 2.0 should package chart and deploy", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version20). AndRun("helm --kube-context kubecontext get foo --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build testdata/foo --kubeconfig kubeconfig"). - AndRunWithOutput("helm --kube-context kubecontext package testdata/foo --destination "+tmpDir+" --version 0.1.2 --app-version 1.2.3 --kubeconfig kubeconfig", "Packaged to "+filepath.Join(tmpDir, "foo-0.1.2.tgz")). + AndRunWithOutput("helm --kube-context kubecontext package testdata/foo --destination "+tmpDir+" --version 0.1.2 --app-version 1.2.3 --kubeconfig kubeconfig", fmt.Sprintf("Packaged to %s", filepath.Join(tmpDir, "foo-0.1.2.tgz"))). AndRun("helm --kube-context kubecontext upgrade foo " + filepath.Join(tmpDir, "foo-0.1.2.tgz") + " --namespace testNamespace --set-string image=foo:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext get foo --kubeconfig kubeconfig"), shouldErr: false, runContext: makeRunContext(testDeployFooWithPackaged, false), builds: testBuildsFoo, }, + { + description: "helm 3.0 beta should package chart and deploy", + commands: testutil. + CmdRunWithOutput("helm version", version30b). + AndRun("helm --kube-context kubecontext get all foo --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext dep build testdata/foo --kubeconfig kubeconfig"). + AndRunWithOutput("helm --kube-context kubecontext package testdata/foo --destination "+tmpDir+" --version 0.1.2 --app-version 1.2.3 --kubeconfig kubeconfig", fmt.Sprintf("Packaged to %s", filepath.Join(tmpDir, "foo-0.1.2.tgz"))). + AndRun("helm --kube-context kubecontext upgrade foo " + filepath.Join(tmpDir, "foo-0.1.2.tgz") + " --namespace testNamespace --set-string image=foo:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext get all foo --kubeconfig kubeconfig"), + shouldErr: false, + runContext: makeRunContext(testDeployFooWithPackaged, false), + builds: testBuildsFoo, + }, + { + description: "helm 3.1 should package chart and deploy", + commands: testutil. + CmdRunWithOutput("helm version", version31). + AndRun("helm --kube-context kubecontext get all foo --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext dep build testdata/foo --kubeconfig kubeconfig"). + AndRunWithOutput("helm --kube-context kubecontext package testdata/foo --destination "+tmpDir+" --version 0.1.2 --app-version 1.2.3 --kubeconfig kubeconfig", fmt.Sprintf("Packaged to %s", filepath.Join(tmpDir, "foo-0.1.2.tgz"))). + AndRun("helm --kube-context kubecontext upgrade foo " + filepath.Join(tmpDir, "foo-0.1.2.tgz") + " --namespace testNamespace --set-string image=foo:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --kubeconfig kubeconfig"). + AndRun("helm --kube-context kubecontext get all foo --kubeconfig kubeconfig"), + shouldErr: false, + runContext: makeRunContext(testDeployFooWithPackaged, false), + builds: testBuildsFoo, + }, { description: "should fail to deploy when packaging fails", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get foo --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build testdata/foo --kubeconfig kubeconfig"). AndRunErr("helm --kube-context kubecontext package testdata/foo --destination "+tmpDir+" --version 0.1.2 --app-version 1.2.3 --kubeconfig kubeconfig", fmt.Errorf("packaging failed")), @@ -506,7 +591,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy and get templated release name", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get -skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade -skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image.tag=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set some.key=somevalue --kubeconfig kubeconfig"). @@ -517,7 +602,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy with templated values", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set image.name=skaffold-helm --set image.tag=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 --set missing.key= --set other.key=FOOBAR --set some.key=somevalue --kubeconfig kubeconfig"). @@ -528,7 +613,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy with valuesFiles templated", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version20). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace -f skaffold-overrides.yaml --set-string image=docker.io:5000/skaffold-helm:3605e7bc17cf46e53f4d81c4cbc24e5b4c495184 -f /some/file-FOOBAR.yaml --kubeconfig kubeconfig"). @@ -539,7 +624,7 @@ func TestHelmDeploy(t *testing.T) { { description: "deploy without actual tags", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version20). AndRun("helm --kube-context kubecontext get skaffold-helm --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade skaffold-helm examples/test --namespace testNamespace --kubeconfig kubeconfig"). @@ -555,7 +640,7 @@ func TestHelmDeploy(t *testing.T) { { description: "first release without tag, second with tag", commands: testutil. - CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"). + CmdRunWithOutput("helm version", version21). AndRun("helm --kube-context kubecontext get other --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig"). AndRun("helm --kube-context kubecontext upgrade other examples/test --namespace testNamespace --kubeconfig kubeconfig"). @@ -587,48 +672,30 @@ func TestHelmDeploy(t *testing.T) { } } -func TestPackageHelmChart(t *testing.T) { - -} - -// TODO(tstromberg): Remove private function test once there are side-effects in a public function -func TestBinVer(t *testing.T) { +func TestHelmCleanup(t *testing.T) { tests := []struct { - description string - commands util.Command - runContext *runcontext.RunContext - want semver.Version - shouldErr bool + description string + commands util.Command + runContext *runcontext.RunContext + builds []build.Artifact + shouldErr bool + expectedWarnings []string }{ { - description: "helm 2.15.1", - commands: testutil.CmdRunWithOutput("helm version --short -c", "Client: v2.15.1+gcf1de4f"), - runContext: makeRunContext(testDeployConfig, false), - want: semver.MustParse("2.15.1"), - }, - { - description: "helm 3.1.0", - commands: testutil.CmdRunWithOutput("helm version --short -c", "v3.1.0+gb29d20b"), - runContext: makeRunContext(testDeployConfig, false), - want: semver.MustParse("3.1.0"), - }, - { - description: "helm 2.14.0-rc.2", - commands: testutil.CmdRunWithOutput("helm version --short -c", "Client: v2.14.0-rc.2+g05811b8"), - runContext: makeRunContext(testDeployConfig, false), - want: semver.MustParse("2.14.0-rc.2"), - }, - { - description: "helm 3.0.0", - commands: testutil.CmdRunWithOutput("helm version --short -c", "v3.0.0+ge29ce2a"), - runContext: makeRunContext(testDeployConfig, false), - want: semver.MustParse("3.0.0"), + description: "cleanup success", + commands: testutil. + CmdRunWithOutput("helm version", version21). + AndRun("helm --kube-context kubecontext delete skaffold-helm --purge --kubeconfig kubeconfig"), + runContext: makeRunContext(testDeployConfig, false), + builds: testBuilds, }, { - description: "garbage", - commands: testutil.CmdRunWithOutput("helm version --short -c", "WUTWUT?"), - runContext: makeRunContext(testDeployConfig, false), - shouldErr: true, + description: "helm3 cleanup success", + commands: testutil. + CmdRunWithOutput("helm version", version31). + AndRun("helm --kube-context kubecontext delete skaffold-helm --kubeconfig kubeconfig"), + runContext: makeRunContext(testDeployConfig, false), + builds: testBuilds, }, } for _, test := range tests { @@ -641,11 +708,9 @@ func TestBinVer(t *testing.T) { event.InitializeState(test.runContext.Cfg.Build) deployer := NewHelmDeployer(test.runContext) - got, err := deployer.binVer(context.Background()) + err := deployer.Cleanup(context.Background(), ioutil.Discard) t.CheckError(test.shouldErr, err) - if got.NE(test.want) { - t.Errorf("got version %q, want %q", got, test.want) - } + t.CheckDeepEqual(test.expectedWarnings, fakeWarner.Warnings) }) } }