From 36c9c0e5202789f0f2c87fabf816900259de0fb8 Mon Sep 17 00:00:00 2001 From: Simon Alling Date: Tue, 19 Nov 2019 08:41:15 +0100 Subject: [PATCH 001/159] Simplify chart installable check The error conveys at least as much information as the boolean. Signed-off-by: Simon Alling --- cmd/helm/install.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 40935db17..4255125ae 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -176,8 +176,7 @@ func runInstall(args []string, client *action.Install, valueOpts *values.Options return nil, err } - validInstallableChart, err := isChartInstallable(chartRequested) - if !validInstallableChart { + if err := checkIfInstallable(chartRequested); err != nil { return nil, err } @@ -209,13 +208,13 @@ func runInstall(args []string, client *action.Install, valueOpts *values.Options return client.Run(chartRequested, vals) } -// isChartInstallable validates if a chart can be installed +// checkIfInstallable validates if a chart can be installed // // Application chart type is only installable -func isChartInstallable(ch *chart.Chart) (bool, error) { +func checkIfInstallable(ch *chart.Chart) error { switch ch.Metadata.Type { case "", "application": - return true, nil + return nil } - return false, errors.Errorf("%s charts are not installable", ch.Metadata.Type) + return errors.Errorf("%s charts are not installable", ch.Metadata.Type) } From 451e2158ad24594d8c67e2e4a99aefc5ffa84a9f Mon Sep 17 00:00:00 2001 From: Nguyen Hai Truong Date: Mon, 6 Jan 2020 22:54:47 +0700 Subject: [PATCH 002/159] Remove duplicated words (#7336) Although it is spelling mistakes, it might make an affects while reading. Signed-off-by: Nguyen Hai Truong Signed-off-by: EItanya --- internal/third_party/dep/fs/fs_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/third_party/dep/fs/fs_test.go b/internal/third_party/dep/fs/fs_test.go index bf4b803f8..a9678d8c1 100644 --- a/internal/third_party/dep/fs/fs_test.go +++ b/internal/third_party/dep/fs/fs_test.go @@ -170,7 +170,7 @@ func TestCopyDir(t *testing.T) { func TestCopyDirFail_SrcInaccessible(t *testing.T) { if runtime.GOOS == "windows" { // XXX: setting permissions works differently in - // Microsoft Windows. Skipping this this until a + // Microsoft Windows. Skipping this until a // compatible implementation is provided. t.Skip("skipping on windows") } @@ -209,7 +209,7 @@ func TestCopyDirFail_SrcInaccessible(t *testing.T) { func TestCopyDirFail_DstInaccessible(t *testing.T) { if runtime.GOOS == "windows" { // XXX: setting permissions works differently in - // Microsoft Windows. Skipping this this until a + // Microsoft Windows. Skipping this until a // compatible implementation is provided. t.Skip("skipping on windows") } @@ -309,7 +309,7 @@ func TestCopyDirFailOpen(t *testing.T) { // Microsoft Windows. os.Chmod(..., 0222) below is not // enough for the file to be readonly, and os.Chmod(..., // 0000) returns an invalid argument error. Skipping - // this this until a compatible implementation is + // this until a compatible implementation is // provided. t.Skip("skipping on windows") } @@ -478,7 +478,7 @@ func TestCopyFileSymlink(t *testing.T) { func TestCopyFileFail(t *testing.T) { if runtime.GOOS == "windows" { // XXX: setting permissions works differently in - // Microsoft Windows. Skipping this this until a + // Microsoft Windows. Skipping this until a // compatible implementation is provided. t.Skip("skipping on windows") } @@ -521,7 +521,7 @@ func TestCopyFileFail(t *testing.T) { } // setupInaccessibleDir creates a temporary location with a single -// directory in it, in such a way that that directory is not accessible +// directory in it, in such a way that directory is not accessible // after this function returns. // // op is called with the directory as argument, so that it can create From b7ff1e29327d33b6fe9b44b11d84c182d1adea45 Mon Sep 17 00:00:00 2001 From: "Jorge I. Gasca" <42793610+jorge-gasca@users.noreply.github.com> Date: Tue, 7 Jan 2020 12:25:15 -0500 Subject: [PATCH 003/159] fix(cmd): Fixes logging on action conf init error (#6909) * fix(cmd): Fixes logging on action conf init error Errors relating to initializing the action config cause helm to exit silently, except when in debug mode. This now emits the useful error. Closes #6863 Signed-off-by: Jorge Gasca * Remove unnecessary formatting of err struct Signed-off-by: Jorge Gasca Signed-off-by: EItanya --- cmd/helm/helm.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 2c3c9e401..112d5123f 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -68,8 +68,7 @@ func main() { cmd := newRootCmd(actionConfig, os.Stdout, os.Args[1:]) if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), os.Getenv("HELM_DRIVER"), debug); err != nil { - debug("%+v", err) - os.Exit(1) + log.Fatal(err) } if err := cmd.Execute(); err != nil { From 00769c4512c9c145eafb84f60e8a473de83b0209 Mon Sep 17 00:00:00 2001 From: Hu Shuai Date: Wed, 8 Jan 2020 17:19:00 +0800 Subject: [PATCH 004/159] Fix a typo "update" -> "updates" (#7346) Signed-off-by: Hu Shuai Signed-off-by: EItanya --- pkg/storage/storage.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 58a7eb06f..6528c48ba 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -66,7 +66,7 @@ func (s *Storage) Create(rls *rspb.Release) error { return s.Driver.Create(makeKey(rls.Name, rls.Version), rls) } -// Update update the release in storage. An error is returned if the +// Update updates the release in storage. An error is returned if the // storage backend fails to update the release or if the release // does not exist. func (s *Storage) Update(rls *rspb.Release) error { From 17dc43f0547d4fd7205de07428b97fbc4a5276fd Mon Sep 17 00:00:00 2001 From: EItanya Date: Wed, 8 Jan 2020 13:21:31 -0500 Subject: [PATCH 005/159] added config file string Signed-off-by: EItanya --- cmd/helm/root.go | 1 + internal/experimental/registry/client.go | 18 +++++++++++------- internal/experimental/registry/client_opts.go | 7 +++++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/cmd/helm/root.go b/cmd/helm/root.go index 3405299fd..ea0654c4b 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -416,6 +416,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string registryClient, err := registry.NewClient( registry.ClientOptDebug(settings.Debug), registry.ClientOptWriter(out), + registry.ClientOptCredentialsFile(settings.RepositoryConfig), ) if err != nil { // TODO: don't panic here, refactor newRootCmd to return error diff --git a/internal/experimental/registry/client.go b/internal/experimental/registry/client.go index d52d9f3e0..48d4d9ecc 100644 --- a/internal/experimental/registry/client.go +++ b/internal/experimental/registry/client.go @@ -41,11 +41,13 @@ const ( type ( // Client works with OCI-compliant registries and local Helm chart cache Client struct { - debug bool - out io.Writer - authorizer *Authorizer - resolver *Resolver - cache *Cache + debug bool + // path to repository config file e.g. ~/.docker/config.json + credentialsFile string + out io.Writer + authorizer *Authorizer + resolver *Resolver + cache *Cache } ) @@ -58,9 +60,11 @@ func NewClient(opts ...ClientOption) (*Client, error) { opt(client) } // set defaults if fields are missing + if client.credentialsFile == "" { + client.credentialsFile = helmpath.CachePath("registry", CredentialsFileBasename) + } if client.authorizer == nil { - credentialsFile := helmpath.CachePath("registry", CredentialsFileBasename) - authClient, err := auth.NewClient(credentialsFile) + authClient, err := auth.NewClient(client.credentialsFile) if err != nil { return nil, err } diff --git a/internal/experimental/registry/client_opts.go b/internal/experimental/registry/client_opts.go index cd295813a..76b527492 100644 --- a/internal/experimental/registry/client_opts.go +++ b/internal/experimental/registry/client_opts.go @@ -60,3 +60,10 @@ func ClientOptCache(cache *Cache) ClientOption { client.cache = cache } } + +// ClientOptCache returns a function that sets the cache setting on a client options set +func ClientOptCredentialsFile(credentialsFile string) ClientOption { + return func(client *Client) { + client.credentialsFile = credentialsFile + } +} From 2f534f97424ce4eaa3356e199e453e94bd65b4c6 Mon Sep 17 00:00:00 2001 From: EItanya Date: Wed, 8 Jan 2020 14:00:51 -0500 Subject: [PATCH 006/159] fix test Signed-off-by: EItanya --- cmd/helm/root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/root.go b/cmd/helm/root.go index ea0654c4b..1cee11458 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -416,7 +416,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string registryClient, err := registry.NewClient( registry.ClientOptDebug(settings.Debug), registry.ClientOptWriter(out), - registry.ClientOptCredentialsFile(settings.RepositoryConfig), + registry.ClientOptCredentialsFile(settings.RegistryConfig), ) if err != nil { // TODO: don't panic here, refactor newRootCmd to return error From 640d527190376a8b4945575f767065ebd47a83cb Mon Sep 17 00:00:00 2001 From: EItanya Date: Wed, 8 Jan 2020 14:03:06 -0500 Subject: [PATCH 007/159] removed panic, and replaced with error Signed-off-by: EItanya --- cmd/helm/helm.go | 5 ++++- cmd/helm/helm_test.go | 6 +++++- cmd/helm/root.go | 7 +++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 112d5123f..952719623 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -65,7 +65,10 @@ func main() { initKubeLogs() actionConfig := new(action.Configuration) - cmd := newRootCmd(actionConfig, os.Stdout, os.Args[1:]) + cmd, err := newRootCmd(actionConfig, os.Stdout, os.Args[1:]) + if err != nil { + log.Fatal(err) + } if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), os.Getenv("HELM_DRIVER"), debug); err != nil { log.Fatal(err) diff --git a/cmd/helm/helm_test.go b/cmd/helm/helm_test.go index 924e8e9d3..20e7ed3e9 100644 --- a/cmd/helm/helm_test.go +++ b/cmd/helm/helm_test.go @@ -107,7 +107,11 @@ func executeActionCommandC(store *storage.Storage, cmd string) (*cobra.Command, Log: func(format string, v ...interface{}) {}, } - root := newRootCmd(actionConfig, buf, args) + root, err := newRootCmd(actionConfig, buf, args) + if err != nil { + return nil, "", err + } + root.SetOutput(buf) root.SetArgs(args) diff --git a/cmd/helm/root.go b/cmd/helm/root.go index 1cee11458..45fbe544d 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -345,7 +345,7 @@ By default, the default directories depend on the Operating System. The defaults +------------------+---------------------------+--------------------------------+-------------------------+ ` -func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string) *cobra.Command { +func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string) (*cobra.Command, error) { cmd := &cobra.Command{ Use: "helm", Short: "The Helm package manager for Kubernetes.", @@ -419,8 +419,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string registry.ClientOptCredentialsFile(settings.RegistryConfig), ) if err != nil { - // TODO: don't panic here, refactor newRootCmd to return error - panic(err) + return nil, err } actionConfig.RegistryClient = registryClient cmd.AddCommand( @@ -431,5 +430,5 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string // Find and add plugins loadPlugins(cmd, out) - return cmd + return cmd, nil } From f604105547dc260f4388792de44a6eb9d2a1353f Mon Sep 17 00:00:00 2001 From: EItanya Date: Wed, 8 Jan 2020 14:11:06 -0500 Subject: [PATCH 008/159] fixed to mirror master Signed-off-by: EItanya --- cmd/helm/helm.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 952719623..ead4a2c49 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -67,11 +67,13 @@ func main() { actionConfig := new(action.Configuration) cmd, err := newRootCmd(actionConfig, os.Stdout, os.Args[1:]) if err != nil { - log.Fatal(err) + debug("%+v", err) + os.Exit(1) } if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), os.Getenv("HELM_DRIVER"), debug); err != nil { - log.Fatal(err) + debug("%+v", err) + os.Exit(1) } if err := cmd.Execute(); err != nil { From de1996e500c75faccbb8aadc1d2e8b788f83ac3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Lindh=C3=A9?= Date: Fri, 15 Nov 2019 12:45:47 +0100 Subject: [PATCH 009/159] Add comments about release Version variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I was looking into the `get` command, and got tripped up by the `Version` variable. It was unclear to me what Version represents, since it's called REVISION when doing e.g., `helm list`. But even after knowing this, it was not very clear to me why we (implicitly) set the Version variable to 0 but never seem to use it. `mhickey` explained to me on Slack that this gets the latest revision of the release. Makes sense, but I added a comment about that too, to clarify. Signed-off-by: Andreas Lindhé --- pkg/action/get.go | 1 + pkg/release/release.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/action/get.go b/pkg/action/get.go index c776eb696..f44b53307 100644 --- a/pkg/action/get.go +++ b/pkg/action/get.go @@ -26,6 +26,7 @@ import ( type Get struct { cfg *Configuration + // Initializing Version to 0 will get the latest revision of the release. Version int } diff --git a/pkg/release/release.go b/pkg/release/release.go index a436998aa..8582a86f3 100644 --- a/pkg/release/release.go +++ b/pkg/release/release.go @@ -33,7 +33,7 @@ type Release struct { Manifest string `json:"manifest,omitempty"` // Hooks are all of the hooks declared for this release. Hooks []*Hook `json:"hooks,omitempty"` - // Version is an int which represents the version of the release. + // Version is an int which represents the revision of the release. Version int `json:"version,omitempty"` // Namespace is the kubernetes namespace of the release. Namespace string `json:"namespace,omitempty"` From cca68288063d235a4c32ef1ba822dd487317c8dc Mon Sep 17 00:00:00 2001 From: liuming216448 Date: Fri, 13 Mar 2020 18:36:19 +0800 Subject: [PATCH 010/159] fix: allow to rollback to previous version even if no deployed releases(#6978) Signed-off-by: liuming --- pkg/action/rollback.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index 942c9d8af..0e09f8b6f 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -210,8 +210,14 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas } } + targetRelease.Info.Status = release.StatusDeployed + deployed, err := r.cfg.Releases.DeployedAll(currentRelease.Name) if err != nil { + if strings.Contains(err.Error(), "has no deployed releases") { + r.cfg.Log(err.Error()) + return targetRelease, nil + } return nil, err } // Supersede all previous deployments, see issue #2941. @@ -221,7 +227,5 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas r.cfg.recordRelease(rel) } - targetRelease.Info.Status = release.StatusDeployed - return targetRelease, nil } From bdf6f48704ed9e09d7fa636f025a3e2d344d42d4 Mon Sep 17 00:00:00 2001 From: Adam Reese Date: Tue, 14 Apr 2020 22:27:53 -0700 Subject: [PATCH 011/159] fix(pkg/kube): continue deleting objects when one fails * Continue deleting objects when one fails to minimize the risk of an upgrade ending in an unrecoverable state * Exclude failed deleted object from the returned result set Signed-off-by: Adam Reese --- pkg/kube/client.go | 12 ++++-------- pkg/kube/client_test.go | 17 ++++++++++++++--- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 05b26b12a..8a4831ffb 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -223,6 +223,7 @@ func (c *Client) Update(original, target ResourceList, force bool) (*Result, err if err := info.Get(); err != nil { c.Log("Unable to get obj %q, err: %s", info.Name, err) + continue } annotations, err := metadataAccessor.Annotations(info.Object) if err != nil { @@ -232,16 +233,11 @@ func (c *Client) Update(original, target ResourceList, force bool) (*Result, err c.Log("Skipping delete of %q due to annotation [%s=%s]", info.Name, ResourcePolicyAnno, KeepPolicy) continue } - - res.Deleted = append(res.Deleted, info) if err := deleteResource(info); err != nil { - if apierrors.IsNotFound(err) { - c.Log("Attempted to delete %q, but the resource was missing", info.Name) - } else { - c.Log("Failed to delete %q, err: %s", info.Name, err) - return res, errors.Wrapf(err, "Failed to delete %q", info.Name) - } + c.Log("Failed to delete %q, err: %s", info.ObjectName(), err) + continue } + res.Deleted = append(res.Deleted, info) } return res, nil } diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index aa081423c..568afa094 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -164,9 +164,21 @@ func TestUpdate(t *testing.T) { t.Fatal(err) } - if _, err := c.Update(first, second, false); err != nil { + result, err := c.Update(first, second, false) + if err != nil { t.Fatal(err) } + + if len(result.Created) != 1 { + t.Errorf("expected 1 resource created, got %d", len(result.Created)) + } + if len(result.Updated) != 2 { + t.Errorf("expected 2 resource updated, got %d", len(result.Updated)) + } + if len(result.Deleted) != 1 { + t.Errorf("expected 1 resource deleted, got %d", len(result.Deleted)) + } + // TODO: Find a way to test methods that use Client Set // Test with a wait // if err := c.Update("test", objBody(codec, &listB), objBody(codec, &listC), false, 300, true); err != nil { @@ -190,8 +202,7 @@ func TestUpdate(t *testing.T) { "/namespaces/default/pods/squid:DELETE", } if len(expectedActions) != len(actions) { - t.Errorf("unexpected number of requests, expected %d, got %d", len(expectedActions), len(actions)) - return + t.Fatalf("unexpected number of requests, expected %d, got %d", len(expectedActions), len(actions)) } for k, v := range expectedActions { if actions[k] != v { From a1685b737dd6846bdc35c281bf841b9cc43cb104 Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Thu, 16 Apr 2020 10:11:07 +0800 Subject: [PATCH 012/159] Merge remote-tracking branch 'helm/master' Signed-off-by: Liu Ming --- pkg/action/rollback.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index f717610c8..81812983f 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -210,10 +210,7 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas } } - targetRelease.Info.Status = release.StatusDeployed - deployed, err := r.cfg.Releases.DeployedAll(currentRelease.Name) - if err != nil && !strings.Contains(err.Error(), "has no deployed releases") { return nil, err } @@ -224,5 +221,7 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas r.cfg.recordRelease(rel) } + targetRelease.Info.Status = release.StatusDeployed + return targetRelease, nil } From 999e4f266f0c69de023a55858b1284e9d89ee20e Mon Sep 17 00:00:00 2001 From: alan Date: Sat, 11 Apr 2020 23:14:24 +0800 Subject: [PATCH 013/159] group command for easy read Signed-off-by: Alan Zhu --- cmd/helm/root.go | 63 ++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/cmd/helm/root.go b/cmd/helm/root.go index 3ebea3bae..4752ccec5 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -25,6 +25,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/clientcmd" + "k8s.io/kubectl/pkg/util/templates" "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/internal/experimental/registry" @@ -134,31 +135,47 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string flags.ParseErrorsWhitelist.UnknownFlags = true flags.Parse(args) + commandGroups := templates.CommandGroups{ + { + Message: "Release Management Commands:", + Commands: []*cobra.Command{ + newInstallCmd(actionConfig, out), + newListCmd(actionConfig, out), + newGetCmd(actionConfig, out), + newStatusCmd(actionConfig, out), + newUpgradeCmd(actionConfig, out), + newHistoryCmd(actionConfig, out), + newRollbackCmd(actionConfig, out), + newReleaseTestCmd(actionConfig, out), + newUninstallCmd(actionConfig, out), + }, + }, + { + Message: "Chart Commands:", + Commands: []*cobra.Command{ + newCreateCmd(out), + newDependencyCmd(out), + newPackageCmd(out), + newTemplateCmd(actionConfig, out), + newLintCmd(out), + newVerifyCmd(out), + }, + }, + { + Message: "Chart Repository Commands:", + Commands: []*cobra.Command{ + newRepoCmd(out), + newSearchCmd(out), + newPullCmd(out), + newShowCmd(out), + }, + }, + } + commandGroups.Add(cmd) + templates.ActsAsRootCommand(cmd, []string{"options"}, commandGroups...) + // Add subcommands cmd.AddCommand( - // chart commands - newCreateCmd(out), - newDependencyCmd(out), - newPullCmd(out), - newShowCmd(out), - newLintCmd(out), - newPackageCmd(out), - newRepoCmd(out), - newSearchCmd(out), - newVerifyCmd(out), - - // release commands - newGetCmd(actionConfig, out), - newHistoryCmd(actionConfig, out), - newInstallCmd(actionConfig, out), - newListCmd(actionConfig, out), - newReleaseTestCmd(actionConfig, out), - newRollbackCmd(actionConfig, out), - newStatusCmd(actionConfig, out), - newTemplateCmd(actionConfig, out), - newUninstallCmd(actionConfig, out), - newUpgradeCmd(actionConfig, out), - newCompletionCmd(out), newEnvCmd(out), newPluginCmd(out), From 27ebfa8c561e758b60872b9bb081253036e559ff Mon Sep 17 00:00:00 2001 From: Thomas FREYSS Date: Thu, 23 Apr 2020 14:47:08 +0200 Subject: [PATCH 014/159] fix(*): remove bom in utf files when loading chart files (#6081) Removes the BOM prefix if present, in read files before processing the data. Affects the following pkg: - pkg/chart/loader: directory and archive loader - internal/ignore: when loading .helmignore file Signed-off-by: Thomas FREYSS --- internal/ignore/rules.go | 13 +++++- pkg/chart/loader/archive.go | 4 +- pkg/chart/loader/directory.go | 5 +++ pkg/chart/loader/load_test.go | 40 ++++++++++++++++++ .../loader/testdata/frobnitz_with_bom.tgz | Bin 0 -> 3523 bytes .../testdata/frobnitz_with_bom/.helmignore | 1 + .../testdata/frobnitz_with_bom/Chart.lock | 8 ++++ .../testdata/frobnitz_with_bom/Chart.yaml | 27 ++++++++++++ .../testdata/frobnitz_with_bom/INSTALL.txt | 1 + .../loader/testdata/frobnitz_with_bom/LICENSE | 1 + .../testdata/frobnitz_with_bom/README.md | 11 +++++ .../frobnitz_with_bom/charts/_ignore_me | 1 + .../charts/alpine/Chart.yaml | 5 +++ .../frobnitz_with_bom/charts/alpine/README.md | 9 ++++ .../charts/alpine/charts/mast1/Chart.yaml | 5 +++ .../charts/alpine/charts/mast1/values.yaml | 4 ++ .../charts/alpine/charts/mast2-0.1.0.tgz | Bin 0 -> 252 bytes .../charts/alpine/templates/alpine-pod.yaml | 14 ++++++ .../charts/alpine/values.yaml | 2 + .../charts/mariner-4.3.2.tgz | Bin 0 -> 967 bytes .../testdata/frobnitz_with_bom/docs/README.md | 1 + .../testdata/frobnitz_with_bom/icon.svg | 8 ++++ .../testdata/frobnitz_with_bom/ignore/me.txt | 0 .../frobnitz_with_bom/templates/template.tpl | 1 + .../testdata/frobnitz_with_bom/values.yaml | 6 +++ 25 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom.tgz create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/.helmignore create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/Chart.lock create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/Chart.yaml create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/INSTALL.txt create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/LICENSE create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/README.md create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/charts/_ignore_me create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/Chart.yaml create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/README.md create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/charts/mast1/Chart.yaml create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/charts/mast1/values.yaml create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/charts/mast2-0.1.0.tgz create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/templates/alpine-pod.yaml create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/values.yaml create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/charts/mariner-4.3.2.tgz create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/docs/README.md create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/icon.svg create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/ignore/me.txt create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/templates/template.tpl create mode 100644 pkg/chart/loader/testdata/frobnitz_with_bom/values.yaml diff --git a/internal/ignore/rules.go b/internal/ignore/rules.go index 9049aff0d..a80923baf 100644 --- a/internal/ignore/rules.go +++ b/internal/ignore/rules.go @@ -18,6 +18,7 @@ package ignore import ( "bufio" + "bytes" "io" "log" "os" @@ -65,8 +66,18 @@ func Parse(file io.Reader) (*Rules, error) { r := &Rules{patterns: []*pattern{}} s := bufio.NewScanner(file) + currentLine := 0 + utf8bom := []byte{0xEF, 0xBB, 0xBF} for s.Scan() { - if err := r.parseRule(s.Text()); err != nil { + scannedBytes := s.Bytes() + // We trim UTF8 BOM + if currentLine == 0 { + scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom) + } + line := string(scannedBytes) + currentLine++ + + if err := r.parseRule(line); err != nil { return r, err } } diff --git a/pkg/chart/loader/archive.go b/pkg/chart/loader/archive.go index 7e187a170..8b38cb89f 100644 --- a/pkg/chart/loader/archive.go +++ b/pkg/chart/loader/archive.go @@ -173,7 +173,9 @@ func LoadArchiveFiles(in io.Reader) ([]*BufferedFile, error) { return nil, err } - files = append(files, &BufferedFile{Name: n, Data: b.Bytes()}) + data := bytes.TrimPrefix(b.Bytes(), utf8bom) + + files = append(files, &BufferedFile{Name: n, Data: data}) b.Reset() } diff --git a/pkg/chart/loader/directory.go b/pkg/chart/loader/directory.go index a12c5158e..bbe543870 100644 --- a/pkg/chart/loader/directory.go +++ b/pkg/chart/loader/directory.go @@ -17,6 +17,7 @@ limitations under the License. package loader import ( + "bytes" "fmt" "io/ioutil" "os" @@ -30,6 +31,8 @@ import ( "helm.sh/helm/v3/pkg/chart" ) +var utf8bom = []byte{0xEF, 0xBB, 0xBF} + // DirLoader loads a chart from a directory type DirLoader string @@ -104,6 +107,8 @@ func LoadDir(dir string) (*chart.Chart, error) { return errors.Wrapf(err, "error reading %s", n) } + data = bytes.TrimPrefix(data, utf8bom) + files = append(files, &BufferedFile{Name: n, Data: data}) return nil } diff --git a/pkg/chart/loader/load_test.go b/pkg/chart/loader/load_test.go index 26513d359..3fa6bba0d 100644 --- a/pkg/chart/loader/load_test.go +++ b/pkg/chart/loader/load_test.go @@ -85,6 +85,38 @@ func TestLoadDirWithSymlink(t *testing.T) { verifyDependenciesLock(t, c) } +func TestLoadDirWithUTFBOM(t *testing.T) { + l, err := Loader("testdata/frobnitz_with_bom") + if err != nil { + t.Fatalf("Failed to load testdata: %s", err) + } + c, err := l.Load() + if err != nil { + t.Fatalf("Failed to load testdata: %s", err) + } + verifyFrobnitz(t, c) + verifyChart(t, c) + verifyDependencies(t, c) + verifyDependenciesLock(t, c) + verifyBomStripped(t, c.Files) +} + +func TestLoadArchiveWithUTFBOM(t *testing.T) { + l, err := Loader("testdata/frobnitz_with_bom.tgz") + if err != nil { + t.Fatalf("Failed to load testdata: %s", err) + } + c, err := l.Load() + if err != nil { + t.Fatalf("Failed to load testdata: %s", err) + } + verifyFrobnitz(t, c) + verifyChart(t, c) + verifyDependencies(t, c) + verifyDependenciesLock(t, c) + verifyBomStripped(t, c.Files) +} + func TestLoadV1(t *testing.T) { l, err := Loader("testdata/frobnitz.v1") if err != nil { @@ -465,3 +497,11 @@ func verifyChartFileAndTemplate(t *testing.T, c *chart.Chart, name string) { } } } + +func verifyBomStripped(t *testing.T, files []*chart.File) { + for _, file := range files { + if bytes.HasPrefix(file.Data, utf8bom) { + t.Errorf("Byte Order Mark still present in processed file %s", file.Name) + } + } +} diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom.tgz b/pkg/chart/loader/testdata/frobnitz_with_bom.tgz new file mode 100644 index 0000000000000000000000000000000000000000..be0cd027db34d392a875cf8151642f9922016dbd GIT binary patch literal 3523 zcmV;!4LtH6iwFpsexY6f17>n>Vs2@4dS7>GbZB2l` znyB~YxdYx5VfMWn1PB3&iueFgG=d@A)?MdMF5{FG{)R-w{q^;#sSRI4>wKcMw~Q(D5t@dOKi zA7!-`+)B<<`fn83E%ZMmB{eNBIT_~*crVotZ@BcY(W;T0Qmaxb{D8ts z_1_YIaQ)Y8DN8d^96jbvO|I-O_N{vddll(tl;3oR_>LlRN{?j%e|Fv3;H2(Vp zjr~7>TstE)F*Jz==xkxQcDaEBPcas0JpMhRCI6F$#3!btCVH_BkNj6Fn%jSBwZwm) z0P)|Y@W$+yxc)~$Oa8};_P(7k)84AX1OJsuWy|=lP9^c*7eM?ctW-K=IW)ybf;^?n zLYQGBaQ6!t2{|K6S$Q$J!BlXk z1%gDHgN?IT7z0Dvn`Gh`8*7BF8cjTJNEv94Q{pM$OwytaT-rzO|XDx3G{X%omY7TZ4=r_AR!ZE#RS*2Gl_&&Xd$7+NWmuW zhM=wJeTh%l@bVS75?5g2%?2O(#tjrbdahA{W`Y$I(5yrauEtfZD)CNtW(loE%kkf- zOK(O1+Tj1|)GEpU_XTdM|4iqyK&JWjSAjg)|HuGnHvc1OY5w;K-2OjjVr(=C3=lZ= zjxOzDXqILO+5!cF<_vI)XPD*)$no^E>` zp6q|ULSH}rYjnc+uh;05690XHKC=V-*8OGC6MpT_yp(I|Hu%rm*Cb8IC=QPas9e!g zE*rY@z}YiL{@3fl$KUr)4oMhwctFL(W9+cYPrd&7@VQucQrz6}pR6i=wfI7OW#=dR zl-zrtc6^sPYd)(k8v2F-3|d?H9;U1~b97$FKSwQ@U3~sXR(4Ic!?Eegz<*C4r|x>m zt||rr?GoFaT~&IvU+vNAeVx1X%}Bp@RQHolbm==PEh_f&>J_6O)jjjFpBDkmn}YS-*cw3 z@jJr|^B1b3Ws|CtP0PTEeA()Us))BgExwi;*e`x_yN?0~x9i%m=t@ce@nBbyyV$?0 zN`7t{{$$@b3$~`kc6w#~&Q7^I?`QqGO@H&ARkOg37tLSS_-*f(UDa!?HNHzi;B!@R zC7s`yIVgGXlzplx{rlL)Jd!zNzy;ZdJ3CG~Yc4smrTox)UnKV|sQg(ztTZ$r5rFF|=V;9}m_XP*lVf*QUz1}>X+1b{i>J`dw<{C%& z$ZNx%yFS0tv3p^MW6J_~{+iw6zhH_h*eQ|FG7EE2b$H52uYt`~^ zvE2*zC6Pt{JzVm)={wHV^hhWxKU}B@3i_da_#VT_x~wEe$+nlfZ@e73bniP?9Fa3; z7iL^sS>p(Oy`v#Eur}l8`Tm>c8l%gqHQ|@%oZK{?So%OropsFQQKx1q7f-IB>GHtv zsM=~vy1nZCi{C%J{o{?P+AAyLd%XAX?g{y7)!Oa{tM;#hpPpUa-8isn+LQ^E70btl z_KqKTsP_buvhZn)N3<#&3|#?>WUa^<`R4Q)!Kx=me@8v<~X?ZskK{c z_Z~aY>*DE66`xg9z=KCGUO!d>@wMumYp&1I>c2@g+o!Dgp!S0ek1hY<+>nUJ zA}>{ky-;>&UY$*IKyBN<^>l~Ay?ahg+g!G8rFFx?KABrCo>yP~c5cb~k*`Kv8NcLx zCUw``{YMW@I(_!EwXbCq_BdYh$imIfU!7L_Qqd(H~ z@yh46`}MmG{@--`cRHC~aRXX!|Lc?r$^Q2VJn7#X3xS^Oe~rF*{9muuO8dWj0=NC| z-tCc3a3BXF!;j#Rfp6m|OOEIU7#Xvfu#g~2h`#|N3sJf&5S4`sTS6en;vp&m-RI<4 zfTUPx6aq#lrx@Q8f`)kzedj2#A}d1z7CPf_KO|tr&sHw z{a-%8FVw%8;CN+QdqJ!9uTp4~YDxdTK&$lMMq|L^{IAwGoBvg6wG{vN32rw3iwbW# z{l_^Mc=o?qQBeGD*n5Cu+|O$p7^g)Hn;y(T4DZ|`2Xue zJpYl<(s>pYj?01@ZTZQF8=f4F(#!-e#0CT(To6crMw(!uxRu1&Ly-4QvB)iFgvCND z!ExeJA^K`Z-hRCU&Iy@?OduLyVm@iO@I6|=e^t0RxVL^S&=ddF`uhFHN1(&}Vi)H}S&J-){hsG+JRy8m>#WM`#V|bOo8JrN*a5=tiWc>xPe|pCl}#J#7>d zE!Y8mr}wTc{YcTx|4@bf`KY*>lKm58Kj8SYTPD9fI80+6^3}7&HTWQYRZ($T*F7J+ zri)+D{`h=t%!!h!Z#Mqp?3{NN2KvP=g=_B#8r!dKa^1XBL*EJ;5wc?A?r}9mPX#WG z$=$zymSW=ikmGM{=wH3;(^sdQEX6-@6h^H4uKXv>pV_Y?H=P(;-Ah)TXbkJFN|_&o z_XcD7f3jtQq4T513l+8z(@HxWnsoh{B|kg*e{rSo?{&|dFAp*vJQ0K*)N!O}Z>C?T zJN)AB5_sZ&Lrk~rb+p0%Qwsc-{J&oxzg+*#BI&KD!_)Y$Q>vQTe``h8bg=`*WbQW-Q`ECnKu76Z6TBGW30h*i3loto`e&nGC}wS$^6qbEcy zaS|p{jYl{)QM;DVBEbYqZlEl3j)u^Rg<%nh0@%bmWczyJe;ZxCCh)|6g+|kS{YRyh z`0o>l{-3bGDy+u}UD*}?!OZq>XBUvXvfndW@?SXEf^&H}-mAkC|FsS4zpmeZLzmL| zPoE%aV1b!-ANq;Lgfm0~V`NcC{{SUexJYyrjk(T0<>%+)`D&bDbL1+dH#thfoMN{W z5obSVX$3T8$-R-VG9n^EE~a9Qk0Ci*1oA18H$`JAtqwyIK9ytQU0*0N8bc-mkHw%| zQ9`&nCegKlL+Hm*a`BdsCTvF$#j`0E$%6t^0tW2jUsv%OMMLR2be&DnbTnom^6Z$r zX&D?ug_B|-O08Im#zQGAB!xnvgclNX7mcVb`R@&nuPIu;{)?;tjpYCN0=LqC{Z=X7 zdRu3KJ==fH&;ROmdMW-za0w`V9Evj@UhfyrdZ5E3^B z)JKRgaS#y?2D;KD|M70d&3^xbW{kPss>9>@pP~i-RT{m-e_sIc|2OwD6C{;`T)s#& x%AjG3BBk*~f&>W?BuJ1TL4pJc5+q2FAVGoz2@)hokRYKE{tus-sa61Z0036V1Lgn# literal 0 HcmV?d00001 diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/.helmignore b/pkg/chart/loader/testdata/frobnitz_with_bom/.helmignore new file mode 100644 index 000000000..7a4b92da2 --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/.helmignore @@ -0,0 +1 @@ +ignore/ diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/Chart.lock b/pkg/chart/loader/testdata/frobnitz_with_bom/Chart.lock new file mode 100644 index 000000000..ed43b227f --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/Chart.lock @@ -0,0 +1,8 @@ +dependencies: + - name: alpine + version: "0.1.0" + repository: https://example.com/charts + - name: mariner + version: "4.3.2" + repository: https://example.com/charts +digest: invalid diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/Chart.yaml b/pkg/chart/loader/testdata/frobnitz_with_bom/Chart.yaml new file mode 100644 index 000000000..21b21f0b5 --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/Chart.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +name: frobnitz +description: This is a frobnitz. +version: "1.2.3" +keywords: + - frobnitz + - sprocket + - dodad +maintainers: + - name: The Helm Team + email: helm@example.com + - name: Someone Else + email: nobody@example.com +sources: + - https://example.com/foo/bar +home: http://example.com +icon: https://example.com/64x64.png +annotations: + extrakey: extravalue + anotherkey: anothervalue +dependencies: + - name: alpine + version: "0.1.0" + repository: https://example.com/charts + - name: mariner + version: "4.3.2" + repository: https://example.com/charts diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/INSTALL.txt b/pkg/chart/loader/testdata/frobnitz_with_bom/INSTALL.txt new file mode 100644 index 000000000..77c4e724a --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/INSTALL.txt @@ -0,0 +1 @@ +This is an install document. The client may display this. diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/LICENSE b/pkg/chart/loader/testdata/frobnitz_with_bom/LICENSE new file mode 100644 index 000000000..c27b00bf2 --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/LICENSE @@ -0,0 +1 @@ +LICENSE placeholder. diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/README.md b/pkg/chart/loader/testdata/frobnitz_with_bom/README.md new file mode 100644 index 000000000..e9c40031b --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/README.md @@ -0,0 +1,11 @@ +# Frobnitz + +This is an example chart. + +## Usage + +This is an example. It has no usage. + +## Development + +For developer info, see the top-level repository. diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/charts/_ignore_me b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/_ignore_me new file mode 100644 index 000000000..a7e3a38b7 --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/_ignore_me @@ -0,0 +1 @@ +This should be ignored by the loader, but may be included in a chart. diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/Chart.yaml b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/Chart.yaml new file mode 100644 index 000000000..adb9853c6 --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +name: alpine +description: Deploy a basic Alpine Linux pod +version: 0.1.0 +home: https://helm.sh/helm diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/README.md b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/README.md new file mode 100644 index 000000000..ea7526bee --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/README.md @@ -0,0 +1,9 @@ +This example was generated using the command `helm create alpine`. + +The `templates/` directory contains a very simple pod resource with a +couple of parameters. + +The `values.toml` file contains the default values for the +`alpine-pod.yaml` template. + +You can install this example using `helm install ./alpine`. diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/charts/mast1/Chart.yaml b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/charts/mast1/Chart.yaml new file mode 100644 index 000000000..1ad84b346 --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/charts/mast1/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +name: mast1 +description: A Helm chart for Kubernetes +version: 0.1.0 +home: "" diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/charts/mast1/values.yaml b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/charts/mast1/values.yaml new file mode 100644 index 000000000..f690d53c4 --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/charts/mast1/values.yaml @@ -0,0 +1,4 @@ +# Default values for mast1. +# This is a YAML-formatted file. +# Declare name/value pairs to be passed into your templates. +# name = "value" diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/charts/mast2-0.1.0.tgz b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/charts/mast2-0.1.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..61cb62051110b55f3d08213dc81dcf0b1c2d8e53 GIT binary patch literal 252 zcmVDc zVQyr3R8em|NM&qo0PNJUs=_c72H?(liabH@pWIst-7YSIyL+rhEHrIN(t?QZE=F{y zgNRfS&$pa5Ly`mMk2OB%pV`*9knW7FlL-Joo@KED7*{C$d;N~z z37$S{+}wvSU9}|VtF|fRpv9Ve>8dWo|9?5B+RE}Y9CFh-x#(Bq8Vck^V=NUiPLCKa z8z5CF#JgK!4>;$4Fm+FUst4d+{(+nP|0&J+e}(;l^U4@w-{=?s0RR8vgVbLD3;+OM Cs&R<` literal 0 HcmV?d00001 diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/templates/alpine-pod.yaml b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/templates/alpine-pod.yaml new file mode 100644 index 000000000..f3e662a28 --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/templates/alpine-pod.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Pod +metadata: + name: {{.Release.Name}}-{{.Chart.Name}} + labels: + app.kubernetes.io/managed-by: {{.Release.Service}} + app.kubernetes.io/name: {{.Chart.Name}} + helm.sh/chart: "{{.Chart.Name}}-{{.Chart.Version}}" +spec: + restartPolicy: {{default "Never" .restart_policy}} + containers: + - name: waiter + image: "alpine:3.9" + command: ["/bin/sleep","9000"] diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/values.yaml b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/values.yaml new file mode 100644 index 000000000..6b7cb2596 --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/alpine/values.yaml @@ -0,0 +1,2 @@ +# The pod name +name: "my-alpine" diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/charts/mariner-4.3.2.tgz b/pkg/chart/loader/testdata/frobnitz_with_bom/charts/mariner-4.3.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..3190136b050e62c628b3c817fd963ac9dc4a9e25 GIT binary patch literal 967 zcmV;&133I2iwFR+9h6)E1MQb_y%a`Bd>#= zhbqf2w!b6}wZ9@rvIhtwzm?~C&+QLm+G2!l%`$_aUgS(@pdjdX3a%E}VXVc7`)dg( zL%IRN2}c1D3xoMi2w@WuWOMZ?5i&3FelBVyq_Ce_8fREdP%NDf<&d!wu3{&VUQNs{N%vK$Ha~k^gB2!0bO7r0ic0 zbqCp*X#j?=|H@GNONsuE)&Idbh>2MX(Z}|+=@*sLod*wS?A8Ugp#mMPuMO0NnZmos9_rr z3xpDL+otj~lRh?B4hHFTl+d5-8NBXmUXB~EyF^bx7m*+!*g>obczvGF|8xkWsHN8; z%#+wiWP{=2pC*98@$VNzzsll&G#D7&11-;D>HT0x|DV2?6}a~*p46@R|2l??e_8dX z@Bb>D3t~VC_*wjq2Dy!6J-_5ME%%J+xmsbK5a#qO>ZV?Wt`d|TDdrB^B&LqFr@lYdUA zs&4-JAg3&uc4dA0gv*bXU9QePa9^8wR{HovA)j@)JOAIkak0Jl)aKqA_3XLM#?H=V z-{tlG=xy^os=1Z><53;&+C4=zp|%rwv!)UyY=%k_t%Y|wNRQl`C6N_Z&S;S+~wb1=)2Uh_4I81`y>DO zoLPSt=btB&x{CUK`0DA&){efW_O36RxnsYZNT0r;JbTLR{H4M3C$8(Cee==aQ~Gbq p$`5v3?NB{4-j0XQHf literal 0 HcmV?d00001 diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/docs/README.md b/pkg/chart/loader/testdata/frobnitz_with_bom/docs/README.md new file mode 100644 index 000000000..816c3e431 --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/docs/README.md @@ -0,0 +1 @@ +This is a placeholder for documentation. diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/icon.svg b/pkg/chart/loader/testdata/frobnitz_with_bom/icon.svg new file mode 100644 index 000000000..892130606 --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/icon.svg @@ -0,0 +1,8 @@ + + + Example icon + + + diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/ignore/me.txt b/pkg/chart/loader/testdata/frobnitz_with_bom/ignore/me.txt new file mode 100644 index 000000000..e69de29bb diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/templates/template.tpl b/pkg/chart/loader/testdata/frobnitz_with_bom/templates/template.tpl new file mode 100644 index 000000000..bb29c5491 --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/templates/template.tpl @@ -0,0 +1 @@ +Hello {{.Name | default "world"}} diff --git a/pkg/chart/loader/testdata/frobnitz_with_bom/values.yaml b/pkg/chart/loader/testdata/frobnitz_with_bom/values.yaml new file mode 100644 index 000000000..c24ceadf9 --- /dev/null +++ b/pkg/chart/loader/testdata/frobnitz_with_bom/values.yaml @@ -0,0 +1,6 @@ +# A values file contains configuration. + +name: "Some Name" + +section: + name: "Name in a section" From 4a0dfbe53b2191e09a7034ce97e4caf84989d6db Mon Sep 17 00:00:00 2001 From: Adam Reese Date: Thu, 23 Apr 2020 12:20:14 -0700 Subject: [PATCH 015/159] fix(pkg/cli): ensure correct configuration from kubeconfig file Bind Helm flags to Kubernetes configuration loader to get a merged config with kubeconfig. Fixes: #7539 Signed-off-by: Adam Reese --- cmd/helm/helm.go | 21 ++++++------- pkg/cli/environment.go | 53 +++++++++++++-------------------- pkg/getter/getter_test.go | 14 +++++---- pkg/getter/httpgetter_test.go | 2 +- pkg/getter/plugingetter_test.go | 17 +++++------ pkg/kube/config.go | 2 ++ pkg/plugin/plugin_test.go | 5 ++-- 7 files changed, 53 insertions(+), 61 deletions(-) diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 7e1fcb6e1..fcc7315f5 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -43,9 +43,7 @@ import ( // FeatureGateOCI is the feature gate for checking if `helm chart` and `helm registry` commands should work const FeatureGateOCI = gates.Gate("HELM_EXPERIMENTAL_OCI") -var ( - settings = cli.New() -) +var settings = cli.New() func init() { log.SetFlags(log.Lshortfile) @@ -72,13 +70,16 @@ func main() { actionConfig := new(action.Configuration) cmd := newRootCmd(actionConfig, os.Stdout, os.Args[1:]) - helmDriver := os.Getenv("HELM_DRIVER") - if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), helmDriver, debug); err != nil { - log.Fatal(err) - } - if helmDriver == "memory" { - loadReleasesInMemory(actionConfig) - } + // run when each command's execute method is called + cobra.OnInitialize(func() { + helmDriver := os.Getenv("HELM_DRIVER") + if err := actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), helmDriver, debug); err != nil { + log.Fatal(err) + } + if helmDriver == "memory" { + loadReleasesInMemory(actionConfig) + } + }) if err := cmd.Execute(); err != nil { debug("%+v", err) diff --git a/pkg/cli/environment.go b/pkg/cli/environment.go index e279331b0..2e64e0810 100644 --- a/pkg/cli/environment.go +++ b/pkg/cli/environment.go @@ -26,21 +26,17 @@ import ( "fmt" "os" "strconv" - "sync" "github.com/spf13/pflag" - "k8s.io/cli-runtime/pkg/genericclioptions" "helm.sh/helm/v3/pkg/helmpath" - "helm.sh/helm/v3/pkg/kube" ) // EnvSettings describes all of the environment settings. type EnvSettings struct { - namespace string - config genericclioptions.RESTClientGetter - configOnce sync.Once + namespace string + config *genericclioptions.ConfigFlags // KubeConfig is the path to the kubeconfig file KubeConfig string @@ -63,8 +59,7 @@ type EnvSettings struct { } func New() *EnvSettings { - - env := EnvSettings{ + env := &EnvSettings{ namespace: os.Getenv("HELM_NAMESPACE"), KubeContext: os.Getenv("HELM_KUBECONTEXT"), KubeToken: os.Getenv("HELM_KUBETOKEN"), @@ -75,7 +70,16 @@ func New() *EnvSettings { RepositoryCache: envOr("HELM_REPOSITORY_CACHE", helmpath.CachePath("repository")), } env.Debug, _ = strconv.ParseBool(os.Getenv("HELM_DEBUG")) - return &env + + // bind to kubernetes config flags + env.config = &genericclioptions.ConfigFlags{ + Namespace: &env.namespace, + Context: &env.KubeContext, + BearerToken: &env.KubeToken, + APIServer: &env.KubeAPIServer, + KubeConfig: &env.KubeConfig, + } + return env } // AddFlags binds flags to the given flagset. @@ -107,42 +111,27 @@ func (s *EnvSettings) EnvVars() map[string]string { "HELM_REPOSITORY_CACHE": s.RepositoryCache, "HELM_REPOSITORY_CONFIG": s.RepositoryConfig, "HELM_NAMESPACE": s.Namespace(), - "HELM_KUBECONTEXT": s.KubeContext, - "HELM_KUBETOKEN": s.KubeToken, - "HELM_KUBEAPISERVER": s.KubeAPIServer, - } + // broken, these are populated from helm flags and not kubeconfig. + "HELM_KUBECONTEXT": s.KubeContext, + "HELM_KUBETOKEN": s.KubeToken, + "HELM_KUBEAPISERVER": s.KubeAPIServer, + } if s.KubeConfig != "" { envvars["KUBECONFIG"] = s.KubeConfig } - return envvars } -//Namespace gets the namespace from the configuration +// Namespace gets the namespace from the configuration func (s *EnvSettings) Namespace() string { - if s.namespace != "" { - return s.namespace - } - - if ns, _, err := s.RESTClientGetter().ToRawKubeConfigLoader().Namespace(); err == nil { + if ns, _, err := s.config.ToRawKubeConfigLoader().Namespace(); err == nil { return ns } return "default" } -//RESTClientGetter gets the kubeconfig from EnvSettings +// RESTClientGetter gets the kubeconfig from EnvSettings func (s *EnvSettings) RESTClientGetter() genericclioptions.RESTClientGetter { - s.configOnce.Do(func() { - clientConfig := kube.GetConfig(s.KubeConfig, s.KubeContext, s.namespace) - if s.KubeToken != "" { - clientConfig.BearerToken = &s.KubeToken - } - if s.KubeAPIServer != "" { - clientConfig.APIServer = &s.KubeAPIServer - } - - s.config = clientConfig - }) return s.config } diff --git a/pkg/getter/getter_test.go b/pkg/getter/getter_test.go index 60eb4738e..79a3338e9 100644 --- a/pkg/getter/getter_test.go +++ b/pkg/getter/getter_test.go @@ -53,9 +53,10 @@ func TestProviders(t *testing.T) { } func TestAll(t *testing.T) { - all := All(&cli.EnvSettings{ - PluginsDirectory: pluginDir, - }) + env := cli.New() + env.PluginsDirectory = pluginDir + + all := All(env) if len(all) != 3 { t.Errorf("expected 3 providers (default plus two plugins), got %d", len(all)) } @@ -66,9 +67,10 @@ func TestAll(t *testing.T) { } func TestByScheme(t *testing.T) { - g := All(&cli.EnvSettings{ - PluginsDirectory: pluginDir, - }) + env := cli.New() + env.PluginsDirectory = pluginDir + + g := All(env) if _, err := g.ByScheme("test"); err != nil { t.Error(err) } diff --git a/pkg/getter/httpgetter_test.go b/pkg/getter/httpgetter_test.go index a1288bf47..4d7ada852 100644 --- a/pkg/getter/httpgetter_test.go +++ b/pkg/getter/httpgetter_test.go @@ -122,7 +122,7 @@ func TestDownload(t *testing.T) { })) defer srv.Close() - g, err := All(new(cli.EnvSettings)).ByScheme("http") + g, err := All(cli.New()).ByScheme("http") if err != nil { t.Fatal(err) } diff --git a/pkg/getter/plugingetter_test.go b/pkg/getter/plugingetter_test.go index 71563e169..a18fa302b 100644 --- a/pkg/getter/plugingetter_test.go +++ b/pkg/getter/plugingetter_test.go @@ -24,9 +24,9 @@ import ( ) func TestCollectPlugins(t *testing.T) { - env := &cli.EnvSettings{ - PluginsDirectory: pluginDir, - } + env := cli.New() + env.PluginsDirectory = pluginDir + p, err := collectPlugins(env) if err != nil { t.Fatal(err) @@ -54,9 +54,8 @@ func TestPluginGetter(t *testing.T) { t.Skip("TODO: refactor this test to work on windows") } - env := &cli.EnvSettings{ - PluginsDirectory: pluginDir, - } + env := cli.New() + env.PluginsDirectory = pluginDir pg := NewPluginGetter("echo", env, "test", ".") g, err := pg() if err != nil { @@ -80,9 +79,9 @@ func TestPluginSubCommands(t *testing.T) { t.Skip("TODO: refactor this test to work on windows") } - env := &cli.EnvSettings{ - PluginsDirectory: pluginDir, - } + env := cli.New() + env.PluginsDirectory = pluginDir + pg := NewPluginGetter("echo -n", env, "test", ".") g, err := pg() if err != nil { diff --git a/pkg/kube/config.go b/pkg/kube/config.go index 624c4a1f7..e00c9acb1 100644 --- a/pkg/kube/config.go +++ b/pkg/kube/config.go @@ -19,6 +19,8 @@ package kube // import "helm.sh/helm/v3/pkg/kube" import "k8s.io/cli-runtime/pkg/genericclioptions" // GetConfig returns a Kubernetes client config. +// +// Deprecated func GetConfig(kubeconfig, context, namespace string) *genericclioptions.ConfigFlags { cf := genericclioptions.NewConfigFlags(true) cf.Namespace = &namespace diff --git a/pkg/plugin/plugin_test.go b/pkg/plugin/plugin_test.go index a869255c4..af0b61846 100644 --- a/pkg/plugin/plugin_test.go +++ b/pkg/plugin/plugin_test.go @@ -305,9 +305,8 @@ func TestSetupEnv(t *testing.T) { name := "pequod" base := filepath.Join("testdata/helmhome/helm/plugins", name) - s := &cli.EnvSettings{ - PluginsDirectory: "testdata/helmhome/helm/plugins", - } + s := cli.New() + s.PluginsDirectory = "testdata/helmhome/helm/plugins" SetupPluginEnv(s, name, base) for _, tt := range []struct { From c422e51ca13b9f213d5f7ed42c187d401ffec245 Mon Sep 17 00:00:00 2001 From: Thomas FREYSS Date: Fri, 24 Apr 2020 11:09:27 +0200 Subject: [PATCH 016/159] test: add test for bom test data integrity Signed-off-by: Thomas FREYSS --- pkg/chart/loader/load_test.go | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/pkg/chart/loader/load_test.go b/pkg/chart/loader/load_test.go index 3fa6bba0d..40b86dec2 100644 --- a/pkg/chart/loader/load_test.go +++ b/pkg/chart/loader/load_test.go @@ -20,6 +20,7 @@ import ( "archive/tar" "bytes" "compress/gzip" + "io" "io/ioutil" "os" "path/filepath" @@ -85,6 +86,54 @@ func TestLoadDirWithSymlink(t *testing.T) { verifyDependenciesLock(t, c) } +func TestBomTestData(t *testing.T) { + testFiles := []string{"frobnitz_with_bom/.helmignore", "frobnitz_with_bom/templates/template.tpl", "frobnitz_with_bom/Chart.yaml"} + for _, file := range testFiles { + data, err := ioutil.ReadFile("testdata/" + file) + if err != nil || !bytes.HasPrefix(data, utf8bom) { + t.Errorf("Test file has no BOM or is invalid: testdata/%s", file) + } + } + + archive, err := ioutil.ReadFile("testdata/frobnitz_with_bom.tgz") + if err != nil { + t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) + } + unzipped, err := gzip.NewReader(bytes.NewReader(archive)) + if err != nil { + t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) + } + defer unzipped.Close() + for _, testFile := range testFiles { + data := make([]byte, 3) + err := unzipped.Reset(bytes.NewReader(archive)) + if err != nil { + t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) + } + tr := tar.NewReader(unzipped) + for { + file, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) + } + if file != nil && strings.EqualFold(file.Name, testFile) { + _, err := tr.Read(data) + if err != nil { + t.Fatalf("Error reading archive frobnitz_with_bom.tgz: %s", err) + } else { + break + } + } + } + if !bytes.Equal(data, utf8bom) { + t.Fatalf("Test file has no BOM or is invalid: frobnitz_with_bom.tgz/%s", testFile) + } + } +} + func TestLoadDirWithUTFBOM(t *testing.T) { l, err := Loader("testdata/frobnitz_with_bom") if err != nil { From 984d2ac7676874ae78a7617f7417513a7a9b5ef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl?= Date: Fri, 24 Apr 2020 23:03:47 +0200 Subject: [PATCH 017/159] fix: write index.yaml file atomically (#7954) * fix: write index.yaml file atomically This refactors the already-existing `AtomicWriteFile` utility to a central location and uses it to write index files atomically. This is done to avoid having half-written index files break client requests. Drive-bys: - Add test for AtomicWriteFile. - Add test IndexFile.WriteFile. Signed-off-by: rabadin * Review fix: use RenameWithFallback instead of os.Rename Signed-off-by: rabadin Co-authored-by: rabadin --- internal/fileutil/fileutil.go | 51 ++++++++++++++++++++++++ internal/fileutil/fileutil_test.go | 62 ++++++++++++++++++++++++++++++ pkg/downloader/chart_downloader.go | 31 ++------------- pkg/repo/index.go | 4 +- pkg/repo/index_test.go | 20 ++++++++++ 5 files changed, 139 insertions(+), 29 deletions(-) create mode 100644 internal/fileutil/fileutil.go create mode 100644 internal/fileutil/fileutil_test.go diff --git a/internal/fileutil/fileutil.go b/internal/fileutil/fileutil.go new file mode 100644 index 000000000..739093f3b --- /dev/null +++ b/internal/fileutil/fileutil.go @@ -0,0 +1,51 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fileutil + +import ( + "io" + "io/ioutil" + "os" + "path/filepath" + + "helm.sh/helm/v3/internal/third_party/dep/fs" +) + +// AtomicWriteFile atomically (as atomic as os.Rename allows) writes a file to a +// disk. +func AtomicWriteFile(filename string, reader io.Reader, mode os.FileMode) error { + tempFile, err := ioutil.TempFile(filepath.Split(filename)) + if err != nil { + return err + } + tempName := tempFile.Name() + + if _, err := io.Copy(tempFile, reader); err != nil { + tempFile.Close() // return value is ignored as we are already on error path + return err + } + + if err := tempFile.Close(); err != nil { + return err + } + + if err := os.Chmod(tempName, mode); err != nil { + return err + } + + return fs.RenameWithFallback(tempName, filename) +} diff --git a/internal/fileutil/fileutil_test.go b/internal/fileutil/fileutil_test.go new file mode 100644 index 000000000..9a4bc32c9 --- /dev/null +++ b/internal/fileutil/fileutil_test.go @@ -0,0 +1,62 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fileutil + +import ( + "bytes" + "io/ioutil" + "os" + "path/filepath" + "testing" +) + +func TestAtomicWriteFile(t *testing.T) { + dir, err := ioutil.TempDir("", "helm-tmp") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + testpath := filepath.Join(dir, "test") + stringContent := "Test content" + reader := bytes.NewReader([]byte(stringContent)) + mode := os.FileMode(0644) + + err = AtomicWriteFile(testpath, reader, mode) + if err != nil { + t.Errorf("AtomicWriteFile error: %s", err) + } + + got, err := ioutil.ReadFile(testpath) + if err != nil { + t.Fatal(err) + } + + if stringContent != string(got) { + t.Fatalf("expected: %s, got: %s", stringContent, string(got)) + } + + gotinfo, err := os.Stat(testpath) + if err != nil { + t.Fatal(err) + } + + if mode != gotinfo.Mode() { + t.Fatalf("expected %s: to be the same mode as %s", + mode, gotinfo.Mode()) + } +} diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go index 0013dbdf0..ef26f3348 100644 --- a/pkg/downloader/chart_downloader.go +++ b/pkg/downloader/chart_downloader.go @@ -18,7 +18,6 @@ package downloader import ( "fmt" "io" - "io/ioutil" "net/url" "os" "path/filepath" @@ -26,6 +25,7 @@ import ( "github.com/pkg/errors" + "helm.sh/helm/v3/internal/fileutil" "helm.sh/helm/v3/internal/urlutil" "helm.sh/helm/v3/pkg/getter" "helm.sh/helm/v3/pkg/helmpath" @@ -72,31 +72,6 @@ type ChartDownloader struct { RepositoryCache string } -// atomicWriteFile atomically (as atomic as os.Rename allows) writes a file to a -// disk. -func atomicWriteFile(filename string, body io.Reader, mode os.FileMode) error { - tempFile, err := ioutil.TempFile(filepath.Split(filename)) - if err != nil { - return err - } - tempName := tempFile.Name() - - if _, err := io.Copy(tempFile, body); err != nil { - tempFile.Close() // return value is ignored as we are already on error path - return err - } - - if err := tempFile.Close(); err != nil { - return err - } - - if err := os.Chmod(tempName, mode); err != nil { - return err - } - - return os.Rename(tempName, filename) -} - // DownloadTo retrieves a chart. Depending on the settings, it may also download a provenance file. // // If Verify is set to VerifyNever, the verification will be nil. @@ -126,7 +101,7 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven name := filepath.Base(u.Path) destfile := filepath.Join(dest, name) - if err := atomicWriteFile(destfile, data, 0644); err != nil { + if err := fileutil.AtomicWriteFile(destfile, data, 0644); err != nil { return destfile, nil, err } @@ -142,7 +117,7 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven return destfile, ver, nil } provfile := destfile + ".prov" - if err := atomicWriteFile(provfile, body, 0644); err != nil { + if err := fileutil.AtomicWriteFile(provfile, body, 0644); err != nil { return destfile, nil, err } diff --git a/pkg/repo/index.go b/pkg/repo/index.go index 36386665e..6ef2cf8b5 100644 --- a/pkg/repo/index.go +++ b/pkg/repo/index.go @@ -17,6 +17,7 @@ limitations under the License. package repo import ( + "bytes" "io/ioutil" "os" "path" @@ -29,6 +30,7 @@ import ( "github.com/pkg/errors" "sigs.k8s.io/yaml" + "helm.sh/helm/v3/internal/fileutil" "helm.sh/helm/v3/internal/urlutil" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" @@ -197,7 +199,7 @@ func (i IndexFile) WriteFile(dest string, mode os.FileMode) error { if err != nil { return err } - return ioutil.WriteFile(dest, b, mode) + return fileutil.AtomicWriteFile(dest, bytes.NewReader(b), mode) } // Merge merges the given index file into this index. diff --git a/pkg/repo/index_test.go b/pkg/repo/index_test.go index 5dbd5e551..466a2c306 100644 --- a/pkg/repo/index_test.go +++ b/pkg/repo/index_test.go @@ -428,3 +428,23 @@ func TestIndexAdd(t *testing.T) { t.Errorf("Expected http://example.com/charts/deis-0.1.0.tgz, got %s", i.Entries["deis"][0].URLs[0]) } } + +func TestIndexWrite(t *testing.T) { + i := NewIndexFile() + i.Add(&chart.Metadata{Name: "clipper", Version: "0.1.0"}, "clipper-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890") + dir, err := ioutil.TempDir("", "helm-tmp") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + testpath := filepath.Join(dir, "test") + i.WriteFile(testpath, 0600) + + got, err := ioutil.ReadFile(testpath) + if err != nil { + t.Fatal(err) + } + if !strings.Contains(string(got), "clipper-0.1.0.tgz") { + t.Fatal("Index files doesn't contain expected content") + } +} From 6bc4a948be0ef1e32f6a605b655cc8cd5f0c2f06 Mon Sep 17 00:00:00 2001 From: Hu Shuai Date: Mon, 27 Apr 2020 14:19:02 +0800 Subject: [PATCH 018/159] Add unit test for pkg/chart/chart.go Signed-off-by: Hu Shuai --- pkg/chart/chart_test.go | 50 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/pkg/chart/chart_test.go b/pkg/chart/chart_test.go index 1b8669ac8..ef8cec3ad 100644 --- a/pkg/chart/chart_test.go +++ b/pkg/chart/chart_test.go @@ -159,3 +159,53 @@ func TestChartFullPath(t *testing.T) { is.Equal("foo/charts/", chrt1.ChartFullPath()) is.Equal("foo", chrt2.ChartFullPath()) } + +func TestCRDObjects(t *testing.T) { + chrt := Chart{ + Files: []*File{ + { + Name: "crds/foo.yaml", + Data: []byte("hello"), + }, + { + Name: "bar.yaml", + Data: []byte("hello"), + }, + { + Name: "crds/foo/bar/baz.yaml", + Data: []byte("hello"), + }, + { + Name: "crdsfoo/bar/baz.yaml", + Data: []byte("hello"), + }, + { + Name: "crds/README.md", + Data: []byte("# hello"), + }, + }, + } + + expected := []CRD{ + { + Name: "crds/foo.yaml", + Filename: "crds/foo.yaml", + File: &File{ + Name: "crds/foo.yaml", + Data: []byte("hello"), + }, + }, + { + Name: "crds/foo/bar/baz.yaml", + Filename: "crds/foo/bar/baz.yaml", + File: &File{ + Name: "crds/foo/bar/baz.yaml", + Data: []byte("hello"), + }, + }, + } + + is := assert.New(t) + crds := chrt.CRDObjects() + is.Equal(expected, crds) +} From f7d1bfd0063a0d43aaef0764222a819fe3472056 Mon Sep 17 00:00:00 2001 From: Bridget Kromhout Date: Mon, 27 Apr 2020 09:02:14 -0500 Subject: [PATCH 019/159] Adding PR template from dev-v2 branch Signed-off-by: Bridget Kromhout --- .github/pull_request_template.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..595b50218 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,12 @@ + + +**What this PR does / why we need it**: + +**Special notes for your reviewer**: + +**If applicable**: +- [ ] this PR contains documentation +- [ ] this PR contains unit tests +- [ ] this PR has been tested for backwards compatibility From 0a318beba32626997abb6af915ebad9399430103 Mon Sep 17 00:00:00 2001 From: Bridget Kromhout Date: Mon, 27 Apr 2020 09:17:09 -0500 Subject: [PATCH 020/159] Updating CONTRIBUTING to match current practice Signed-off-by: Bridget Kromhout --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 63780365e..a637f9255 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -184,9 +184,9 @@ contributing to Helm. All issue types follow the same general lifecycle. Differe ## How to Contribute a Patch -1. If you haven't already done so, sign a Contributor License Agreement (see details above). -2. Fork the desired repo, develop and test your code changes. -3. Submit a pull request. +1. Identify or create the related issue. +2. Fork the desired repo; develop and test your code changes. +3. Submit a pull request, making sure to sign your work and link the related issue. Coding conventions and standards are explained in the [official developer docs](https://helm.sh/docs/developers/). From cd50d0c3621ad91b3848f14b7ef3a8d6aa29d2c9 Mon Sep 17 00:00:00 2001 From: Anshul Verma Date: Tue, 28 Apr 2020 01:41:47 +0530 Subject: [PATCH 021/159] Fix : Prints empty list in json/yaml is no repositories are present (#7949) * Prints empty repolist in json/yaml if there are no repos and output format is given as json/yaml rather that printing the error msg "no repositories to show" Signed-off-by: Anshul Verma * Prints empty repolist in json/yaml if there are no repos and output format is given as json/yaml rather that printing the error msg "no repositories to show" Signed-off-by: Anshul Verma --- cmd/helm/repo_list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/repo_list.go b/cmd/helm/repo_list.go index 51b4f0d58..ed1c9573c 100644 --- a/cmd/helm/repo_list.go +++ b/cmd/helm/repo_list.go @@ -38,7 +38,7 @@ func newRepoListCmd(out io.Writer) *cobra.Command { Args: require.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { f, err := repo.LoadFile(settings.RepositoryConfig) - if isNotExist(err) || len(f.Repositories) == 0 { + if isNotExist(err) || (len(f.Repositories) == 0 && !(outfmt == output.JSON || outfmt == output.YAML)) { return errors.New("no repositories to show") } From 2334195a01a6e47d597940890890a1369f8bcba4 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Thu, 23 Apr 2020 14:50:31 -0400 Subject: [PATCH 022/159] Adding Helm env vars where XDG exposed Helm had been exposing XDG based variables to end users. This lead to confusion. For example, if a user wanted to change the cache location Helm used should they change the XDG variable? Since this would be like changing the HOME environment variable the answer is no. This change adds HELM_*_HOME environment variables to be used in addition to XDG ones of the same name. Helm will now look for the Helm specific variable. If not set, Helm will fall back to XDG locations. If those are not set a default location will be used. This keeps XDG in use as a default when present, provides users with the ability to set the location, and removes XDG from being exposed to end users to avoid confusion. Closes #7919 Signed-off-by: Matt Farina --- cmd/helm/root.go | 14 +++++++------- cmd/helm/root_test.go | 18 ++++++++++++++++++ internal/test/ensure/ensure.go | 4 ++++ pkg/cli/environment.go | 3 +++ pkg/helmpath/lazypath.go | 33 ++++++++++++++++++++++++++++----- 5 files changed, 60 insertions(+), 12 deletions(-) diff --git a/cmd/helm/root.go b/cmd/helm/root.go index 2c66d3a09..e9bc26fe4 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -46,20 +46,20 @@ Environment variables: +------------------+--------------------------------------------------------------------------------------------------------+ | Name | Description | +------------------+--------------------------------------------------------------------------------------------------------+ -| $XDG_CACHE_HOME | set an alternative location for storing cached files. | -| $XDG_CONFIG_HOME | set an alternative location for storing Helm configuration. | -| $XDG_DATA_HOME | set an alternative location for storing Helm data. | +| $HELM_CACHE_HOME | set an alternative location for storing cached files. | +| $HELM_CONFIG_HOME | set an alternative location for storing Helm configuration. | +| $HELM_DATA_HOME | set an alternative location for storing Helm data. | | $HELM_DRIVER | set the backend storage driver. Values are: configmap, secret, memory, postgres | | $HELM_DRIVER_SQL_CONNECTION_STRING | set the connection string the SQL storage driver should use. | | $HELM_NO_PLUGINS | disable plugins. Set HELM_NO_PLUGINS=1 to disable plugins. | | $KUBECONFIG | set an alternative Kubernetes configuration file (default "~/.kube/config") | +------------------+--------------------------------------------------------------------------------------------------------+ -Helm stores configuration based on the XDG base directory specification, so +Helm stores cache, configuration, and data based on the following configuration order: -- cached files are stored in $XDG_CACHE_HOME/helm -- configuration is stored in $XDG_CONFIG_HOME/helm -- data is stored in $XDG_DATA_HOME/helm +- If a HELM_*_HOME environment variable is set, it will be used +- Otherwise, on systems supporting the XDG base directory specification, the XDG variables will be used +- When no other location is set a default location will be used based on the operating system By default, the default directories depend on the Operating System. The defaults are listed below: diff --git a/cmd/helm/root_test.go b/cmd/helm/root_test.go index e1fa1fc27..891bb698e 100644 --- a/cmd/helm/root_test.go +++ b/cmd/helm/root_test.go @@ -55,6 +55,24 @@ func TestRootCmd(t *testing.T) { envvars: map[string]string{xdg.DataHomeEnvVar: "/bar"}, dataPath: "/bar/helm", }, + { + name: "with $HELM_CACHE_HOME set", + args: "env", + envvars: map[string]string{helmpath.CacheHomeEnvVar: "/foo/helm"}, + cachePath: "/foo/helm", + }, + { + name: "with $HELM_CONFIG_HOME set", + args: "env", + envvars: map[string]string{helmpath.ConfigHomeEnvVar: "/foo/helm"}, + configPath: "/foo/helm", + }, + { + name: "with $HELM_DATA_HOME set", + args: "env", + envvars: map[string]string{helmpath.DataHomeEnvVar: "/foo/helm"}, + dataPath: "/foo/helm", + }, } for _, tt := range tests { diff --git a/internal/test/ensure/ensure.go b/internal/test/ensure/ensure.go index b4775df80..6219ad626 100644 --- a/internal/test/ensure/ensure.go +++ b/internal/test/ensure/ensure.go @@ -21,6 +21,7 @@ import ( "os" "testing" + "helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v3/pkg/helmpath/xdg" ) @@ -31,6 +32,9 @@ func HelmHome(t *testing.T) func() { os.Setenv(xdg.CacheHomeEnvVar, base) os.Setenv(xdg.ConfigHomeEnvVar, base) os.Setenv(xdg.DataHomeEnvVar, base) + os.Setenv(helmpath.CacheHomeEnvVar, "") + os.Setenv(helmpath.ConfigHomeEnvVar, "") + os.Setenv(helmpath.DataHomeEnvVar, "") return func() { os.RemoveAll(base) } diff --git a/pkg/cli/environment.go b/pkg/cli/environment.go index e279331b0..8e8f4ce8d 100644 --- a/pkg/cli/environment.go +++ b/pkg/cli/environment.go @@ -101,6 +101,9 @@ func envOr(name, def string) string { func (s *EnvSettings) EnvVars() map[string]string { envvars := map[string]string{ "HELM_BIN": os.Args[0], + "HELM_CACHE_HOME": helmpath.CachePath(""), + "HELM_CONFIG_HOME": helmpath.ConfigPath(""), + "HELM_DATA_HOME": helmpath.DataPath(""), "HELM_DEBUG": fmt.Sprint(s.Debug), "HELM_PLUGINS": s.PluginsDirectory, "HELM_REGISTRY_CONFIG": s.RegistryConfig, diff --git a/pkg/helmpath/lazypath.go b/pkg/helmpath/lazypath.go index 0b9068671..a8a64bfab 100644 --- a/pkg/helmpath/lazypath.go +++ b/pkg/helmpath/lazypath.go @@ -20,11 +20,34 @@ import ( "helm.sh/helm/v3/pkg/helmpath/xdg" ) +const ( + // CacheHomeEnvVar is the environment variable used by Helm + // for the cache directory. When no value is set a default is used. + CacheHomeEnvVar = "HELM_CACHE_HOME" + + // ConfigHomeEnvVar is the environment variable used by Helm + // for the config directory. When no value is set a default is used. + ConfigHomeEnvVar = "HELM_CONFIG_HOME" + + // DataHomeEnvVar is the environment variable used by Helm + // for the data directory. When no value is set a default is used. + DataHomeEnvVar = "HELM_DATA_HOME" +) + // lazypath is an lazy-loaded path buffer for the XDG base directory specification. type lazypath string -func (l lazypath) path(envVar string, defaultFn func() string, elem ...string) string { - base := os.Getenv(envVar) +func (l lazypath) path(helmEnvVar, XDGEnvVar string, defaultFn func() string, elem ...string) string { + + // There is an order to checking for a path. + // 1. See if a Helm specific environment variable has been set. + // 2. Check if an XDG environment variable is set + // 3. Fall back to a default + base := os.Getenv(helmEnvVar) + if base != "" { + return filepath.Join(base, filepath.Join(elem...)) + } + base = os.Getenv(XDGEnvVar) if base == "" { base = defaultFn() } @@ -34,16 +57,16 @@ func (l lazypath) path(envVar string, defaultFn func() string, elem ...string) s // cachePath defines the base directory relative to which user specific non-essential data files // should be stored. func (l lazypath) cachePath(elem ...string) string { - return l.path(xdg.CacheHomeEnvVar, cacheHome, filepath.Join(elem...)) + return l.path(CacheHomeEnvVar, xdg.CacheHomeEnvVar, cacheHome, filepath.Join(elem...)) } // configPath defines the base directory relative to which user specific configuration files should // be stored. func (l lazypath) configPath(elem ...string) string { - return l.path(xdg.ConfigHomeEnvVar, configHome, filepath.Join(elem...)) + return l.path(ConfigHomeEnvVar, xdg.ConfigHomeEnvVar, configHome, filepath.Join(elem...)) } // dataPath defines the base directory relative to which user specific data files should be stored. func (l lazypath) dataPath(elem ...string) string { - return l.path(xdg.DataHomeEnvVar, dataHome, filepath.Join(elem...)) + return l.path(DataHomeEnvVar, xdg.DataHomeEnvVar, dataHome, filepath.Join(elem...)) } From 6fc93530569813580c1b6554a7154f4ec0fda0b4 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Tue, 28 Apr 2020 17:12:14 -0600 Subject: [PATCH 023/159] feat: lint the names of templated resources (#8011) Signed-off-by: Matt Butcher --- pkg/lint/lint_test.go | 8 ++- pkg/lint/rules/template.go | 53 ++++++++++++++----- pkg/lint/rules/template_test.go | 29 ++++++++++ .../testdata/goodone/templates/goodone.yaml | 2 +- pkg/lint/rules/testdata/goodone/values.yaml | 2 +- 5 files changed, 78 insertions(+), 16 deletions(-) diff --git a/pkg/lint/lint_test.go b/pkg/lint/lint_test.go index 2c110009d..e7ff4cd7a 100644 --- a/pkg/lint/lint_test.go +++ b/pkg/lint/lint_test.go @@ -104,7 +104,10 @@ func TestBadValues(t *testing.T) { func TestGoodChart(t *testing.T) { m := All(goodChartDir, values, namespace, strict).Messages if len(m) != 0 { - t.Errorf("All failed but shouldn't have: %#v", m) + t.Error("All returned linter messages when it shouldn't have") + for i, msg := range m { + t.Logf("Message %d: %s", i, msg) + } } } @@ -130,6 +133,9 @@ func TestHelmCreateChart(t *testing.T) { m := All(createdChart, values, namespace, true).Messages if ll := len(m); ll != 1 { t.Errorf("All should have had exactly 1 error. Got %d", ll) + for i, msg := range m { + t.Logf("Message %d: %s", i, msg.Error()) + } } else if msg := m[0].Err.Error(); !strings.Contains(msg, "icon is recommended") { t.Errorf("Unexpected lint error: %s", msg) } diff --git a/pkg/lint/rules/template.go b/pkg/lint/rules/template.go index 3d388f81b..e27c6a345 100644 --- a/pkg/lint/rules/template.go +++ b/pkg/lint/rules/template.go @@ -17,9 +17,11 @@ limitations under the License. package rules import ( + "fmt" "os" "path/filepath" "regexp" + "strings" "github.com/pkg/errors" "sigs.k8s.io/yaml" @@ -35,6 +37,14 @@ var ( releaseTimeSearch = regexp.MustCompile(`\.Release\.Time`) ) +// validName is a regular expression for names. +// +// This is different than action.ValidName. It conforms to the regular expression +// `kubectl` says it uses, plus it disallows empty names. +// +// For details, see https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names +var validName = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`) + // Templates lints the templates in the Linter. func Templates(linter *support.Linter, values map[string]interface{}, namespace string, strict bool) { path := "templates/" @@ -57,7 +67,7 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace } options := chartutil.ReleaseOptions{ - Name: "testRelease", + Name: "test-release", Namespace: namespace, } @@ -111,14 +121,17 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace // linter.RunLinterRule(support.WarningSev, path, validateQuotes(string(preExecutedTemplate))) renderedContent := renderedContentMap[filepath.Join(chart.Name(), fileName)] - var yamlStruct K8sYamlStruct - // Even though K8sYamlStruct only defines Metadata namespace, an error in any other - // key will be raised as well - err := yaml.Unmarshal([]byte(renderedContent), &yamlStruct) - - // If YAML linting fails, we sill progress. So we don't capture the returned state - // on this linter run. - linter.RunLinterRule(support.ErrorSev, path, validateYamlContent(err)) + if strings.TrimSpace(renderedContent) != "" { + var yamlStruct K8sYamlStruct + // Even though K8sYamlStruct only defines a few fields, an error in any other + // key will be raised as well + err := yaml.Unmarshal([]byte(renderedContent), &yamlStruct) + + // If YAML linting fails, we sill progress. So we don't capture the returned state + // on this linter run. + linter.RunLinterRule(support.ErrorSev, path, validateYamlContent(err)) + linter.RunLinterRule(support.ErrorSev, path, validateMetadataName(&yamlStruct)) + } } } @@ -149,6 +162,15 @@ func validateYamlContent(err error) error { return errors.Wrap(err, "unable to parse YAML") } +func validateMetadataName(obj *K8sYamlStruct) error { + // This will return an error if the characters do not abide by the standard OR if the + // name is left empty. + if validName.MatchString(obj.Metadata.Name) { + return nil + } + return fmt.Errorf("object name does not conform to Kubernetes naming requirements: %q", obj.Metadata.Name) +} + func validateNoCRDHooks(manifest []byte) error { if crdHookSearch.Match(manifest) { return errors.New("manifest is a crd-install hook. This hook is no longer supported in v3 and all CRDs should also exist the crds/ directory at the top level of the chart") @@ -164,9 +186,14 @@ func validateNoReleaseTime(manifest []byte) error { } // K8sYamlStruct stubs a Kubernetes YAML file. -// Need to access for now to Namespace only +// +// DEPRECATED: In Helm 4, this will be made a private type, as it is for use only within +// the rules package. type K8sYamlStruct struct { - Metadata struct { - Namespace string - } + Metadata k8sYamlMetadata +} + +type k8sYamlMetadata struct { + Namespace string + Name string } diff --git a/pkg/lint/rules/template_test.go b/pkg/lint/rules/template_test.go index ddb46aba0..c924de0e7 100644 --- a/pkg/lint/rules/template_test.go +++ b/pkg/lint/rules/template_test.go @@ -101,3 +101,32 @@ func TestV3Fail(t *testing.T) { t.Errorf("Unexpected error: %s", res[2].Err) } } + +func TestValidateMetadataName(t *testing.T) { + names := map[string]bool{ + "": false, + "foo": true, + "foo.bar1234baz.seventyone": true, + "FOO": false, + "123baz": true, + "foo.BAR.baz": false, + "one-two": true, + "-two": false, + "one_two": false, + "a..b": false, + "%^&#$%*@^*@&#^": false, + } + for input, expectPass := range names { + obj := K8sYamlStruct{Metadata: k8sYamlMetadata{Name: input}} + if err := validateMetadataName(&obj); (err == nil) != expectPass { + st := "fail" + if expectPass { + st = "succeed" + } + t.Errorf("Expected %q to %s", input, st) + if err != nil { + t.Log(err) + } + } + } +} diff --git a/pkg/lint/rules/testdata/goodone/templates/goodone.yaml b/pkg/lint/rules/testdata/goodone/templates/goodone.yaml index 0e77f46f2..cd46f62c7 100644 --- a/pkg/lint/rules/testdata/goodone/templates/goodone.yaml +++ b/pkg/lint/rules/testdata/goodone/templates/goodone.yaml @@ -1,2 +1,2 @@ metadata: - name: {{.Values.name | default "foo" | title}} + name: {{ .Values.name | default "foo" | lower }} diff --git a/pkg/lint/rules/testdata/goodone/values.yaml b/pkg/lint/rules/testdata/goodone/values.yaml index fe9abd983..92c3d9bb9 100644 --- a/pkg/lint/rules/testdata/goodone/values.yaml +++ b/pkg/lint/rules/testdata/goodone/values.yaml @@ -1 +1 @@ -name: "goodone here" +name: "goodone-here" From fb829c2c843df01ad1dd5ffd13c4e923be4ab9e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BCchinger=20Dominic?= Date: Wed, 29 Apr 2020 09:14:22 +0200 Subject: [PATCH 024/159] Fix markdown table in helm command doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tables aren't rendered correctly because the syntax was wrong. Fixed it by applying the https://www.markdownguide.org/extended-syntax/#tables table syntax. See https://helm.sh/docs/helm/helm/#synopsis for the wrong rendering. ![Broken table in html](https://imgur.com/bniKxO6) Fix for helm/helm-www#575 Signed-off-by: Lüchinger Dominic --- cmd/helm/root.go | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/cmd/helm/root.go b/cmd/helm/root.go index 2c66d3a09..ea66a061a 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -43,17 +43,15 @@ Common actions for Helm: Environment variables: -+------------------+--------------------------------------------------------------------------------------------------------+ -| Name | Description | -+------------------+--------------------------------------------------------------------------------------------------------+ -| $XDG_CACHE_HOME | set an alternative location for storing cached files. | -| $XDG_CONFIG_HOME | set an alternative location for storing Helm configuration. | -| $XDG_DATA_HOME | set an alternative location for storing Helm data. | -| $HELM_DRIVER | set the backend storage driver. Values are: configmap, secret, memory, postgres | -| $HELM_DRIVER_SQL_CONNECTION_STRING | set the connection string the SQL storage driver should use. | -| $HELM_NO_PLUGINS | disable plugins. Set HELM_NO_PLUGINS=1 to disable plugins. | -| $KUBECONFIG | set an alternative Kubernetes configuration file (default "~/.kube/config") | -+------------------+--------------------------------------------------------------------------------------------------------+ +| Name | Description | +|------------------------------------|-----------------------------------------------------------------------------------| +| $XDG_CACHE_HOME | set an alternative location for storing cached files. | +| $XDG_CONFIG_HOME | set an alternative location for storing Helm configuration. | +| $XDG_DATA_HOME | set an alternative location for storing Helm data. | +| $HELM_DRIVER | set the backend storage driver. Values are: configmap, secret, memory, postgres | +| $HELM_DRIVER_SQL_CONNECTION_STRING | set the connection string the SQL storage driver should use. | +| $HELM_NO_PLUGINS | disable plugins. Set HELM_NO_PLUGINS=1 to disable plugins. | +| $KUBECONFIG | set an alternative Kubernetes configuration file (default "~/.kube/config") | Helm stores configuration based on the XDG base directory specification, so @@ -63,13 +61,11 @@ Helm stores configuration based on the XDG base directory specification, so By default, the default directories depend on the Operating System. The defaults are listed below: -+------------------+---------------------------+--------------------------------+-------------------------+ | Operating System | Cache Path | Configuration Path | Data Path | -+------------------+---------------------------+--------------------------------+-------------------------+ +|------------------|---------------------------|--------------------------------|-------------------------| | Linux | $HOME/.cache/helm | $HOME/.config/helm | $HOME/.local/share/helm | | macOS | $HOME/Library/Caches/helm | $HOME/Library/Preferences/helm | $HOME/Library/helm | | Windows | %TEMP%\helm | %APPDATA%\helm | %APPDATA%\helm | -+------------------+---------------------------+--------------------------------+-------------------------+ ` func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string) *cobra.Command { From ff3ed53b7c0c07aab2bc8cc59344d18063e8a719 Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Thu, 30 Apr 2020 17:31:27 +0800 Subject: [PATCH 025/159] polish to keep the same log style Signed-off-by: Liu Ming --- pkg/kube/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 8a4831ffb..c1de2b299 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -439,7 +439,7 @@ func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, if err != nil { return errors.Wrap(err, "failed to replace object") } - c.Log("Replaced %q with kind %s for kind %s\n", target.Name, currentObj.GetObjectKind().GroupVersionKind().Kind, kind) + c.Log("Replaced %q with kind %s for kind %s", target.Name, currentObj.GetObjectKind().GroupVersionKind().Kind, kind) } else { // send patch to server obj, err = helper.Patch(target.Namespace, target.Name, patchType, patch, nil) From 918deeef181f20ea640bc562cef69d209493cbab Mon Sep 17 00:00:00 2001 From: Matthias Riegler Date: Fri, 1 May 2020 13:21:44 +0200 Subject: [PATCH 026/159] added option --insecure-skip-tls-verify for helm pull, addresses #7875 Signed-off-by: Matthias Riegler --- cmd/helm/flags.go | 1 + pkg/action/install.go | 19 ++++++++++--------- pkg/action/pull.go | 1 + 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/cmd/helm/flags.go b/cmd/helm/flags.go index 246cb0dd5..d35a05fec 100644 --- a/cmd/helm/flags.go +++ b/cmd/helm/flags.go @@ -49,6 +49,7 @@ func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) { f.StringVar(&c.Password, "password", "", "chart repository password where to locate the requested chart") f.StringVar(&c.CertFile, "cert-file", "", "identify HTTPS client using this SSL certificate file") f.StringVar(&c.KeyFile, "key-file", "", "identify HTTPS client using this SSL key file") + f.BoolVar(&c.InsecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart download") f.StringVar(&c.CaFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") } diff --git a/pkg/action/install.go b/pkg/action/install.go index 10a9644dd..cb5318965 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -104,15 +104,16 @@ type Install struct { // ChartPathOptions captures common options used for controlling chart paths type ChartPathOptions struct { - CaFile string // --ca-file - CertFile string // --cert-file - KeyFile string // --key-file - Keyring string // --keyring - Password string // --password - RepoURL string // --repo - Username string // --username - Verify bool // --verify - Version string // --version + CaFile string // --ca-file + CertFile string // --cert-file + KeyFile string // --key-file + InsecureSkipTLSverify bool // --insecure-skip-verify + Keyring string // --keyring + Password string // --password + RepoURL string // --repo + Username string // --username + Verify bool // --verify + Version string // --version } // NewInstall creates a new Install object with the given configuration. diff --git a/pkg/action/pull.go b/pkg/action/pull.go index ee20bbe83..a46e98bae 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -64,6 +64,7 @@ func (p *Pull) Run(chartRef string) (string, error) { Options: []getter.Option{ getter.WithBasicAuth(p.Username, p.Password), getter.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile), + getter.WithInsecureSkipVerifyTLS(p.InsecureSkipTLSverify), }, RepositoryConfig: p.Settings.RepositoryConfig, RepositoryCache: p.Settings.RepositoryCache, From 8ff7801e0c3d902a5fc4129aaaf60aa97c7ba4fd Mon Sep 17 00:00:00 2001 From: Matthias Riegler Date: Fri, 1 May 2020 14:57:36 +0200 Subject: [PATCH 027/159] added option --insecure-skip-tls-verify for helm install, addresses #7875 Signed-off-by: Matthias Riegler --- pkg/action/install.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/action/install.go b/pkg/action/install.go index cb5318965..4a8bf1835 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -641,6 +641,7 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) ( Options: []getter.Option{ getter.WithBasicAuth(c.Username, c.Password), getter.WithTLSClientConfig(c.CertFile, c.KeyFile, c.CaFile), + getter.WithInsecureSkipVerifyTLS(c.InsecureSkipTLSverify), }, RepositoryConfig: settings.RepositoryConfig, RepositoryCache: settings.RepositoryCache, From bf9d629dc02e759a1ba09ff8f6784dd0fb585cf3 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Fri, 1 May 2020 14:01:15 -0600 Subject: [PATCH 028/159] feat: implement deprecation warnings in helm lint (#7986) * feat: implement deprecation warnings in helm lint Signed-off-by: Matt Butcher * added more deprecated APIs Signed-off-by: Matt Butcher --- pkg/chartutil/save.go | 3 ++ pkg/lint/rules/deprecations.go | 64 +++++++++++++++++++++++++++++ pkg/lint/rules/deprecations_test.go | 42 +++++++++++++++++++ pkg/lint/rules/template.go | 5 ++- pkg/lint/rules/template_test.go | 44 ++++++++++++++++++++ 5 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 pkg/lint/rules/deprecations.go create mode 100644 pkg/lint/rules/deprecations_test.go diff --git a/pkg/chartutil/save.go b/pkg/chartutil/save.go index be5d151d7..1011436b5 100644 --- a/pkg/chartutil/save.go +++ b/pkg/chartutil/save.go @@ -34,6 +34,9 @@ import ( var headerBytes = []byte("+aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=") // SaveDir saves a chart as files in a directory. +// +// This takes the chart name, and creates a new subdirectory inside of the given dest +// directory, writing the chart's contents to that subdirectory. func SaveDir(c *chart.Chart, dest string) error { // Create the chart directory outdir := filepath.Join(dest, c.Name()) diff --git a/pkg/lint/rules/deprecations.go b/pkg/lint/rules/deprecations.go new file mode 100644 index 000000000..c14fedec6 --- /dev/null +++ b/pkg/lint/rules/deprecations.go @@ -0,0 +1,64 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package rules // import "helm.sh/helm/v3/pkg/lint/rules" + +import "fmt" + +// deprecatedAPIs lists APIs that are deprecated (left) with suggested alternatives (right). +// +// An empty rvalue indicates that the API is completely deprecated. +var deprecatedAPIs = map[string]string{ + "extensions/v1 Deployment": "apps/v1 Deployment", + "extensions/v1 DaemonSet": "apps/v1 DaemonSet", + "extensions/v1 ReplicaSet": "apps/v1 ReplicaSet", + "extensions/v1beta1 PodSecurityPolicy": "policy/v1beta1 PodSecurityPolicy", + "extensions/v1beta1 NetworkPolicy": "networking.k8s.io/v1beta1 NetworkPolicy", + "extensions/v1beta1 Ingress": "networking.k8s.io/v1beta1 Ingress", + "apps/v1beta1 Deployment": "apps/v1 Deployment", + "apps/v1beta1 StatefulSet": "apps/v1 StatefulSet", + "apps/v1beta1 DaemonSet": "apps/v1 DaemonSet", + "apps/v1beta1 ReplicaSet": "apps/v1 ReplicaSet", + "apps/v1beta2 Deployment": "apps/v1 Deployment", + "apps/v1beta2 StatefulSet": "apps/v1 StatefulSet", + "apps/v1beta2 DaemonSet": "apps/v1 DaemonSet", + "apps/v1beta2 ReplicaSet": "apps/v1 ReplicaSet", +} + +// deprecatedAPIError indicates than an API is deprecated in Kubernetes +type deprecatedAPIError struct { + Deprecated string + Alternative string +} + +func (e deprecatedAPIError) Error() string { + msg := fmt.Sprintf("the kind %q is deprecated", e.Deprecated) + if e.Alternative != "" { + msg += fmt.Sprintf(" in favor of %q", e.Alternative) + } + return msg +} + +func validateNoDeprecations(resource *K8sYamlStruct) error { + gvk := fmt.Sprintf("%s %s", resource.APIVersion, resource.Kind) + if alt, ok := deprecatedAPIs[gvk]; ok { + return deprecatedAPIError{ + Deprecated: gvk, + Alternative: alt, + } + } + return nil +} diff --git a/pkg/lint/rules/deprecations_test.go b/pkg/lint/rules/deprecations_test.go new file mode 100644 index 000000000..f85d58a0c --- /dev/null +++ b/pkg/lint/rules/deprecations_test.go @@ -0,0 +1,42 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package rules // import "helm.sh/helm/v3/pkg/lint/rules" + +import "testing" + +func TestValidateNoDeprecations(t *testing.T) { + deprecated := &K8sYamlStruct{ + APIVersion: "extensions/v1", + Kind: "Deployment", + } + err := validateNoDeprecations(deprecated) + if err == nil { + t.Fatal("Expected deprecated extension to be flagged") + } + + depErr := err.(deprecatedAPIError) + if depErr.Alternative != "apps/v1 Deployment" { + t.Errorf("Expected %q to be replaced by %q", depErr.Deprecated, depErr.Alternative) + } + + if err := validateNoDeprecations(&K8sYamlStruct{ + APIVersion: "v1", + Kind: "Pod", + }); err != nil { + t.Errorf("Expected a v1 Pod to not be deprecated") + } +} diff --git a/pkg/lint/rules/template.go b/pkg/lint/rules/template.go index e27c6a345..b76e4260a 100644 --- a/pkg/lint/rules/template.go +++ b/pkg/lint/rules/template.go @@ -131,6 +131,7 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace // on this linter run. linter.RunLinterRule(support.ErrorSev, path, validateYamlContent(err)) linter.RunLinterRule(support.ErrorSev, path, validateMetadataName(&yamlStruct)) + linter.RunLinterRule(support.ErrorSev, path, validateNoDeprecations(&yamlStruct)) } } } @@ -190,7 +191,9 @@ func validateNoReleaseTime(manifest []byte) error { // DEPRECATED: In Helm 4, this will be made a private type, as it is for use only within // the rules package. type K8sYamlStruct struct { - Metadata k8sYamlMetadata + APIVersion string `json:"apiVersion"` + Kind string + Metadata k8sYamlMetadata } type k8sYamlMetadata struct { diff --git a/pkg/lint/rules/template_test.go b/pkg/lint/rules/template_test.go index c924de0e7..1a047edf2 100644 --- a/pkg/lint/rules/template_test.go +++ b/pkg/lint/rules/template_test.go @@ -22,6 +22,9 @@ import ( "strings" "testing" + "helm.sh/helm/v3/internal/test/ensure" + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/lint/support" ) @@ -130,3 +133,44 @@ func TestValidateMetadataName(t *testing.T) { } } } + +func TestDeprecatedAPIFails(t *testing.T) { + mychart := chart.Chart{ + Metadata: &chart.Metadata{ + APIVersion: "v2", + Name: "failapi", + Version: "0.1.0", + Icon: "satisfy-the-linting-gods.gif", + }, + Templates: []*chart.File{ + { + Name: "templates/baddeployment.yaml", + Data: []byte("apiVersion: apps/v1beta1\nkind: Deployment\nmetadata:\n name: baddep"), + }, + { + Name: "templates/goodsecret.yaml", + Data: []byte("apiVersion: v1\nkind: Secret\nmetadata:\n name: goodsecret"), + }, + }, + } + tmpdir := ensure.TempDir(t) + defer os.RemoveAll(tmpdir) + + if err := chartutil.SaveDir(&mychart, tmpdir); err != nil { + t.Fatal(err) + } + + linter := support.Linter{ChartDir: filepath.Join(tmpdir, mychart.Name())} + Templates(&linter, values, namespace, strict) + if l := len(linter.Messages); l != 1 { + for i, msg := range linter.Messages { + t.Logf("Message %d: %s", i, msg) + } + t.Fatalf("Expected 1 lint error, got %d", l) + } + + err := linter.Messages[0].Err.(deprecatedAPIError) + if err.Deprecated != "apps/v1beta1 Deployment" { + t.Errorf("Surprised to learn that %q is deprecated", err.Deprecated) + } +} From 524150c662f9c030d2caa9ad8f79d2ff9521c431 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Fri, 1 May 2020 14:02:47 -0600 Subject: [PATCH 029/159] fix: use correct regular expression for Kubernetes names (#8013) Signed-off-by: Matt Butcher --- pkg/action/action.go | 13 +++++++------ pkg/action/action_test.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/pkg/action/action.go b/pkg/action/action.go index a8437d729..bb9ef5f71 100644 --- a/pkg/action/action.go +++ b/pkg/action/action.go @@ -62,16 +62,17 @@ var ( errInvalidName = errors.New("invalid release name, must match regex ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+$ and the length must not longer than 53") ) -// ValidName is a regular expression for names. +// ValidName is a regular expression for resource names. // // According to the Kubernetes help text, the regular expression it uses is: // -// (([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])? +// [a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)* // -// We modified that. First, we added start and end delimiters. Second, we changed -// the final ? to + to require that the pattern match at least once. This modification -// prevents an empty string from matching. -var ValidName = regexp.MustCompile("^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+$") +// This follows the above regular expression (but requires a full string match, not partial). +// +// The Kubernetes documentation is here, though it is not entirely correct: +// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names +var ValidName = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`) // Configuration injects the dependencies that all actions share. type Configuration struct { diff --git a/pkg/action/action_test.go b/pkg/action/action_test.go index 36ef261a3..0cbdb162b 100644 --- a/pkg/action/action_test.go +++ b/pkg/action/action_test.go @@ -316,3 +316,40 @@ func TestGetVersionSet(t *testing.T) { t.Error("Non-existent version is reported found.") } } + +// TestValidName is a regression test for ValidName +// +// Kubernetes has strict naming conventions for resource names. This test represents +// those conventions. +// +// See https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names +// +// NOTE: At the time of this writing, the docs above say that names cannot begin with +// digits. However, `kubectl`'s regular expression explicit allows this, and +// Kubernetes (at least as of 1.18) also accepts resources whose names begin with digits. +func TestValidName(t *testing.T) { + names := map[string]bool{ + "": false, + "foo": true, + "foo.bar1234baz.seventyone": true, + "FOO": false, + "123baz": true, + "foo.BAR.baz": false, + "one-two": true, + "-two": false, + "one_two": false, + "a..b": false, + "%^&#$%*@^*@&#^": false, + "example:com": false, + "example%%com": false, + } + for input, expectPass := range names { + if ValidName.MatchString(input) != expectPass { + st := "fail" + if expectPass { + st = "succeed" + } + t.Errorf("Expected %q to %s", input, st) + } + } +} From 47abe66fd29162a71627ee4c9d26a9c3712e24e1 Mon Sep 17 00:00:00 2001 From: Vibhav Bobade Date: Thu, 16 Apr 2020 03:51:55 +0530 Subject: [PATCH 030/159] Add checking of length of resourceList before creating of deleting A chart being installed which only contains CRDs and not any templates tries to install the resources by default. The resourceList which is used in this case does not check if there are resources present in it or not. This commit adds checks to those particular places where we need to check if the size of resourceList > 0 during installation and deletion. Signed-off-by: Vibhav Bobade --- cmd/helm/install_test.go | 5 +++ .../chart-with-only-crds/.helmignore | 23 ++++++++++++ .../chart-with-only-crds/Chart.yaml | 21 +++++++++++ .../chart-with-only-crds/crds/test-crd.yaml | 19 ++++++++++ pkg/action/install.go | 36 ++++++++++--------- pkg/action/uninstall.go | 7 ++-- 6 files changed, 93 insertions(+), 18 deletions(-) create mode 100644 cmd/helm/testdata/testcharts/chart-with-only-crds/.helmignore create mode 100644 cmd/helm/testdata/testcharts/chart-with-only-crds/Chart.yaml create mode 100644 cmd/helm/testdata/testcharts/chart-with-only-crds/crds/test-crd.yaml diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go index 57972024f..4e1584e90 100644 --- a/cmd/helm/install_test.go +++ b/cmd/helm/install_test.go @@ -189,6 +189,11 @@ func TestInstall(t *testing.T) { cmd: "install aeneas testdata/testcharts/deprecated --namespace default", golden: "output/deprecated-chart.txt", }, + // Install chart with only crds + { + name: "install chart with only crds", + cmd: "install crd-test testdata/testcharts/chart-with-only-crds --namespace default", + }, } runTestActionCmd(t, tests) diff --git a/cmd/helm/testdata/testcharts/chart-with-only-crds/.helmignore b/cmd/helm/testdata/testcharts/chart-with-only-crds/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/cmd/helm/testdata/testcharts/chart-with-only-crds/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/cmd/helm/testdata/testcharts/chart-with-only-crds/Chart.yaml b/cmd/helm/testdata/testcharts/chart-with-only-crds/Chart.yaml new file mode 100644 index 000000000..a8b4c2022 --- /dev/null +++ b/cmd/helm/testdata/testcharts/chart-with-only-crds/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: crd-test +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.16.0 diff --git a/cmd/helm/testdata/testcharts/chart-with-only-crds/crds/test-crd.yaml b/cmd/helm/testdata/testcharts/chart-with-only-crds/crds/test-crd.yaml new file mode 100644 index 000000000..1d7350f1d --- /dev/null +++ b/cmd/helm/testdata/testcharts/chart-with-only-crds/crds/test-crd.yaml @@ -0,0 +1,19 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: tests.test.io +spec: + group: test.io + names: + kind: Test + listKind: TestList + plural: tests + singular: test + scope: Namespaced + versions: + - name : v1alpha2 + served: true + storage: true + - name : v1alpha1 + served: true + storage: false diff --git a/pkg/action/install.go b/pkg/action/install.go index 4b4dd9214..38e86d4cc 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -145,20 +145,24 @@ func (i *Install) installCRDs(crds []chart.CRD) error { } totalItems = append(totalItems, res...) } - // Invalidate the local cache, since it will not have the new CRDs - // present. - discoveryClient, err := i.cfg.RESTClientGetter.ToDiscoveryClient() - if err != nil { - return err - } - i.cfg.Log("Clearing discovery cache") - discoveryClient.Invalidate() - // Give time for the CRD to be recognized. - if err := i.cfg.KubeClient.Wait(totalItems, 60*time.Second); err != nil { - return err + if len(totalItems) > 0 { + // Invalidate the local cache, since it will not have the new CRDs + // present. + discoveryClient, err := i.cfg.RESTClientGetter.ToDiscoveryClient() + if err != nil { + return err + } + i.cfg.Log("Clearing discovery cache") + discoveryClient.Invalidate() + // Give time for the CRD to be recognized. + + if err := i.cfg.KubeClient.Wait(totalItems, 60*time.Second); err != nil { + return err + } + + // Make sure to force a rebuild of the cache. + discoveryClient.ServerGroups() } - // Make sure to force a rebuild of the cache. - discoveryClient.ServerGroups() return nil } @@ -265,7 +269,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. // we'll end up in a state where we will delete those resources upon // deleting the release because the manifest will be pointing at that // resource - if !i.ClientOnly && !isUpgrade { + if !i.ClientOnly && !isUpgrade && len(resources) > 0 { toBeAdopted, err = existingResourceConflict(resources, rel.Name, rel.Namespace) if err != nil { return nil, errors.Wrap(err, "rendered manifests contain a resource that already exists. Unable to continue with install") @@ -330,11 +334,11 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. // At this point, we can do the install. Note that before we were detecting whether to // do an update, but it's not clear whether we WANT to do an update if the re-use is set // to true, since that is basically an upgrade operation. - if len(toBeAdopted) == 0 { + if len(toBeAdopted) == 0 && len(resources) > 0 { if _, err := i.cfg.KubeClient.Create(resources); err != nil { return i.failRelease(rel, err) } - } else { + } else if len(resources) > 0 { if _, err := i.cfg.KubeClient.Update(toBeAdopted, resources, false); err != nil { return i.failRelease(rel, err) } diff --git a/pkg/action/uninstall.go b/pkg/action/uninstall.go index dfaa98472..a51a283d6 100644 --- a/pkg/action/uninstall.go +++ b/pkg/action/uninstall.go @@ -169,6 +169,7 @@ func joinErrors(errs []error) string { // deleteRelease deletes the release and returns manifests that were kept in the deletion process func (u *Uninstall) deleteRelease(rel *release.Release) (string, []error) { + var errs []error caps, err := u.cfg.getCapabilities() if err != nil { return rel.Manifest, []error{errors.Wrap(err, "could not get apiVersions from Kubernetes")} @@ -194,11 +195,13 @@ func (u *Uninstall) deleteRelease(rel *release.Release) (string, []error) { for _, file := range filesToDelete { builder.WriteString("\n---\n" + file.Content) } + resources, err := u.cfg.KubeClient.Build(strings.NewReader(builder.String()), false) if err != nil { return "", []error{errors.Wrap(err, "unable to build kubernetes objects for delete")} } - - _, errs := u.cfg.KubeClient.Delete(resources) + if len(resources) > 0 { + _, errs = u.cfg.KubeClient.Delete(resources) + } return kept, errs } From 08e546f169ff3d5694863f0766c3132da2f095b7 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Mon, 4 May 2020 13:55:42 -0600 Subject: [PATCH 031/159] fix: removed strict template errors in linter (#8017) Signed-off-by: Matt Butcher --- pkg/lint/rules/template.go | 1 - pkg/lint/rules/template_test.go | 52 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/pkg/lint/rules/template.go b/pkg/lint/rules/template.go index b76e4260a..787c5b26a 100644 --- a/pkg/lint/rules/template.go +++ b/pkg/lint/rules/template.go @@ -81,7 +81,6 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace return } var e engine.Engine - e.Strict = strict e.LintMode = true renderedContentMap, err := e.Render(chart, valuesToRender) diff --git a/pkg/lint/rules/template_test.go b/pkg/lint/rules/template_test.go index 1a047edf2..991c6c2f6 100644 --- a/pkg/lint/rules/template_test.go +++ b/pkg/lint/rules/template_test.go @@ -174,3 +174,55 @@ func TestDeprecatedAPIFails(t *testing.T) { t.Errorf("Surprised to learn that %q is deprecated", err.Deprecated) } } + +const manifest = `apiVersion: v1 +kind: ConfigMap +metadata: + name: foo +data: + myval1: {{default "val" .Values.mymap.key1 }} + myval2: {{default "val" .Values.mymap.key2 }} +` + +// TestSTrictTemplatePrasingMapError is a regression test. +// +// The template engine should not produce an error when a map in values.yaml does +// not contain all possible keys. +// +// See https://github.com/helm/helm/issues/7483 +func TestStrictTemplateParsingMapError(t *testing.T) { + + ch := chart.Chart{ + Metadata: &chart.Metadata{ + Name: "regression7483", + APIVersion: "v2", + Version: "0.1.0", + }, + Values: map[string]interface{}{ + "mymap": map[string]string{ + "key1": "val1", + }, + }, + Templates: []*chart.File{ + { + Name: "templates/configmap.yaml", + Data: []byte(manifest), + }, + }, + } + dir := ensure.TempDir(t) + defer os.RemoveAll(dir) + if err := chartutil.SaveDir(&ch, dir); err != nil { + t.Fatal(err) + } + linter := &support.Linter{ + ChartDir: filepath.Join(dir, ch.Metadata.Name), + } + Templates(linter, ch.Values, namespace, strict) + if len(linter.Messages) != 0 { + t.Errorf("expected zero messages, got %d", len(linter.Messages)) + for i, msg := range linter.Messages { + t.Logf("Message %d: %q", i, msg) + } + } +} From 8316a403ed16c76c35ce673e163c0ee30b1e8871 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Thu, 16 Apr 2020 15:51:31 -0600 Subject: [PATCH 032/159] bump version to v3.2 Signed-off-by: Matt Butcher (cherry picked from commit 7bffac813db894e06d17bac91d14ea819b5c2310) --- cmd/helm/testdata/output/version-client-shorthand.txt | 2 +- cmd/helm/testdata/output/version-client.txt | 2 +- cmd/helm/testdata/output/version-short.txt | 2 +- cmd/helm/testdata/output/version-template.txt | 2 +- cmd/helm/testdata/output/version.txt | 2 +- internal/version/version.go | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/helm/testdata/output/version-client-shorthand.txt b/cmd/helm/testdata/output/version-client-shorthand.txt index 8f9ed6136..d613309fe 100644 --- a/cmd/helm/testdata/output/version-client-shorthand.txt +++ b/cmd/helm/testdata/output/version-client-shorthand.txt @@ -1 +1 @@ -version.BuildInfo{Version:"v3.1", GitCommit:"", GitTreeState:"", GoVersion:""} +version.BuildInfo{Version:"v3.2", GitCommit:"", GitTreeState:"", GoVersion:""} diff --git a/cmd/helm/testdata/output/version-client.txt b/cmd/helm/testdata/output/version-client.txt index 8f9ed6136..d613309fe 100644 --- a/cmd/helm/testdata/output/version-client.txt +++ b/cmd/helm/testdata/output/version-client.txt @@ -1 +1 @@ -version.BuildInfo{Version:"v3.1", GitCommit:"", GitTreeState:"", GoVersion:""} +version.BuildInfo{Version:"v3.2", GitCommit:"", GitTreeState:"", GoVersion:""} diff --git a/cmd/helm/testdata/output/version-short.txt b/cmd/helm/testdata/output/version-short.txt index 861668947..4d5034cea 100644 --- a/cmd/helm/testdata/output/version-short.txt +++ b/cmd/helm/testdata/output/version-short.txt @@ -1 +1 @@ -v3.1 +v3.2 diff --git a/cmd/helm/testdata/output/version-template.txt b/cmd/helm/testdata/output/version-template.txt index e5a779bbf..7c09e8d57 100644 --- a/cmd/helm/testdata/output/version-template.txt +++ b/cmd/helm/testdata/output/version-template.txt @@ -1 +1 @@ -Version: v3.1 \ No newline at end of file +Version: v3.2 \ No newline at end of file diff --git a/cmd/helm/testdata/output/version.txt b/cmd/helm/testdata/output/version.txt index 8f9ed6136..d613309fe 100644 --- a/cmd/helm/testdata/output/version.txt +++ b/cmd/helm/testdata/output/version.txt @@ -1 +1 @@ -version.BuildInfo{Version:"v3.1", GitCommit:"", GitTreeState:"", GoVersion:""} +version.BuildInfo{Version:"v3.2", GitCommit:"", GitTreeState:"", GoVersion:""} diff --git a/internal/version/version.go b/internal/version/version.go index fd0616920..baa65a028 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -30,7 +30,7 @@ var ( // Increment major number for new feature additions and behavioral changes. // Increment minor number for bug fixes and performance enhancements. // Increment patch number for critical fixes to existing releases. - version = "v3.1" + version = "v3.2" // metadata is extra build time data metadata = "" From bc515991f8fb7c3294e7f7809778fd360751d5cb Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Tue, 5 May 2020 14:01:21 +0800 Subject: [PATCH 033/159] docs: fix capitalization in a few help messages 1. fixed capitalization in a few help messages 2. use no thrid-person verb. ref #7898 Signed-off-by: Liu Ming --- cmd/helm/docs.go | 2 +- cmd/helm/lint.go | 2 +- cmd/helm/show.go | 8 ++++---- cmd/helm/status.go | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd/helm/docs.go b/cmd/helm/docs.go index 2c9020fb9..c974d4014 100644 --- a/cmd/helm/docs.go +++ b/cmd/helm/docs.go @@ -48,7 +48,7 @@ func newDocsCmd(out io.Writer) *cobra.Command { cmd := &cobra.Command{ Use: "docs", - Short: "Generate documentation as markdown or man pages", + Short: "generate documentation as markdown or man pages", Long: docsDesc, Hidden: true, Args: require.NoArgs, diff --git a/cmd/helm/lint.go b/cmd/helm/lint.go index fe39a5741..a7aac172a 100644 --- a/cmd/helm/lint.go +++ b/cmd/helm/lint.go @@ -46,7 +46,7 @@ func newLintCmd(out io.Writer) *cobra.Command { cmd := &cobra.Command{ Use: "lint PATH", - Short: "examines a chart for possible issues", + Short: "examine a chart for possible issues", Long: longLintHelp, RunE: func(cmd *cobra.Command, args []string) error { paths := []string{"."} diff --git a/cmd/helm/show.go b/cmd/helm/show.go index ac38ed5af..b335c5f76 100644 --- a/cmd/helm/show.go +++ b/cmd/helm/show.go @@ -72,7 +72,7 @@ func newShowCmd(out io.Writer) *cobra.Command { all := &cobra.Command{ Use: "all [CHART]", - Short: "shows all information of the chart", + Short: "show all information of the chart", Long: showAllDesc, Args: require.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { @@ -88,7 +88,7 @@ func newShowCmd(out io.Writer) *cobra.Command { valuesSubCmd := &cobra.Command{ Use: "values [CHART]", - Short: "shows the chart's values", + Short: "show the chart's values", Long: showValuesDesc, Args: require.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { @@ -104,7 +104,7 @@ func newShowCmd(out io.Writer) *cobra.Command { chartSubCmd := &cobra.Command{ Use: "chart [CHART]", - Short: "shows the chart's definition", + Short: "show the chart's definition", Long: showChartDesc, Args: require.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { @@ -120,7 +120,7 @@ func newShowCmd(out io.Writer) *cobra.Command { readmeSubCmd := &cobra.Command{ Use: "readme [CHART]", - Short: "shows the chart's README", + Short: "show the chart's README", Long: readmeChartDesc, Args: require.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/helm/status.go b/cmd/helm/status.go index 34543c6cb..6313b3975 100644 --- a/cmd/helm/status.go +++ b/cmd/helm/status.go @@ -50,7 +50,7 @@ func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { cmd := &cobra.Command{ Use: "status RELEASE_NAME", - Short: "displays the status of the named release", + Short: "display the status of the named release", Long: statusHelp, Args: require.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { From be38084eb4d6e0bfb79566083833413947f8bfc8 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Tue, 5 May 2020 10:27:47 -0400 Subject: [PATCH 034/159] Fixing argument to be lower case Signed-off-by: Matt Farina --- pkg/helmpath/lazypath.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/helmpath/lazypath.go b/pkg/helmpath/lazypath.go index a8a64bfab..22d7bf0a1 100644 --- a/pkg/helmpath/lazypath.go +++ b/pkg/helmpath/lazypath.go @@ -37,7 +37,7 @@ const ( // lazypath is an lazy-loaded path buffer for the XDG base directory specification. type lazypath string -func (l lazypath) path(helmEnvVar, XDGEnvVar string, defaultFn func() string, elem ...string) string { +func (l lazypath) path(helmEnvVar, xdgEnvVar string, defaultFn func() string, elem ...string) string { // There is an order to checking for a path. // 1. See if a Helm specific environment variable has been set. @@ -47,7 +47,7 @@ func (l lazypath) path(helmEnvVar, XDGEnvVar string, defaultFn func() string, el if base != "" { return filepath.Join(base, filepath.Join(elem...)) } - base = os.Getenv(XDGEnvVar) + base = os.Getenv(xdgEnvVar) if base == "" { base = defaultFn() } From e1aaf995a6c238f04eb8449f67feb5f2cb95028f Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Tue, 5 May 2020 17:44:47 +0800 Subject: [PATCH 035/159] refactor: alter constant `pluginFileName` to `PluginFileName` in order to reuse the "plugin.yaml" value in installer package and avoid magic value in installer.go Signed-off-by: Liu Ming --- pkg/plugin/installer/installer.go | 4 +++- pkg/plugin/plugin.go | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/plugin/installer/installer.go b/pkg/plugin/installer/installer.go index 65c61cd7d..61b49ab3b 100644 --- a/pkg/plugin/installer/installer.go +++ b/pkg/plugin/installer/installer.go @@ -23,6 +23,8 @@ import ( "strings" "github.com/pkg/errors" + + "helm.sh/helm/v3/pkg/plugin" ) // ErrMissingMetadata indicates that plugin.yaml is missing. @@ -100,7 +102,7 @@ func isRemoteHTTPArchive(source string) bool { // isPlugin checks if the directory contains a plugin.yaml file. func isPlugin(dirname string) bool { - _, err := os.Stat(filepath.Join(dirname, "plugin.yaml")) + _, err := os.Stat(filepath.Join(dirname, plugin.PluginFileName)) return err == nil } diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index 2eb354fca..caa34fbd3 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -28,7 +28,7 @@ import ( "helm.sh/helm/v3/pkg/cli" ) -const pluginFileName = "plugin.yaml" +const PluginFileName = "plugin.yaml" // Downloaders represents the plugins capability if it can retrieve // charts from special sources @@ -159,7 +159,7 @@ func (p *Plugin) PrepareCommand(extraArgs []string) (string, []string, error) { // LoadDir loads a plugin from the given directory. func LoadDir(dirname string) (*Plugin, error) { - data, err := ioutil.ReadFile(filepath.Join(dirname, pluginFileName)) + data, err := ioutil.ReadFile(filepath.Join(dirname, PluginFileName)) if err != nil { return nil, err } @@ -177,7 +177,7 @@ func LoadDir(dirname string) (*Plugin, error) { func LoadAll(basedir string) ([]*Plugin, error) { plugins := []*Plugin{} // We want basedir/*/plugin.yaml - scanpath := filepath.Join(basedir, "*", pluginFileName) + scanpath := filepath.Join(basedir, "*", PluginFileName) matches, err := filepath.Glob(scanpath) if err != nil { return plugins, err From e4768e646095204c16a124b8176c2c6542561a08 Mon Sep 17 00:00:00 2001 From: Martin Hickey Date: Tue, 5 May 2020 21:04:14 +0000 Subject: [PATCH 036/159] Update lint deprecation list Add api group: - apiextensions.k8s.io/v1beta1 - rbac.authorization.k8s.io/v1alpha1 Also, some kinds moved from extensions/v1 to extensions/v1beta1 Signed-off-by: Martin Hickey --- pkg/lint/rules/deprecations.go | 44 ++++++++++++++++++++--------- pkg/lint/rules/deprecations_test.go | 2 +- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/pkg/lint/rules/deprecations.go b/pkg/lint/rules/deprecations.go index c14fedec6..88921408d 100644 --- a/pkg/lint/rules/deprecations.go +++ b/pkg/lint/rules/deprecations.go @@ -22,20 +22,36 @@ import "fmt" // // An empty rvalue indicates that the API is completely deprecated. var deprecatedAPIs = map[string]string{ - "extensions/v1 Deployment": "apps/v1 Deployment", - "extensions/v1 DaemonSet": "apps/v1 DaemonSet", - "extensions/v1 ReplicaSet": "apps/v1 ReplicaSet", - "extensions/v1beta1 PodSecurityPolicy": "policy/v1beta1 PodSecurityPolicy", - "extensions/v1beta1 NetworkPolicy": "networking.k8s.io/v1beta1 NetworkPolicy", - "extensions/v1beta1 Ingress": "networking.k8s.io/v1beta1 Ingress", - "apps/v1beta1 Deployment": "apps/v1 Deployment", - "apps/v1beta1 StatefulSet": "apps/v1 StatefulSet", - "apps/v1beta1 DaemonSet": "apps/v1 DaemonSet", - "apps/v1beta1 ReplicaSet": "apps/v1 ReplicaSet", - "apps/v1beta2 Deployment": "apps/v1 Deployment", - "apps/v1beta2 StatefulSet": "apps/v1 StatefulSet", - "apps/v1beta2 DaemonSet": "apps/v1 DaemonSet", - "apps/v1beta2 ReplicaSet": "apps/v1 ReplicaSet", + "extensions/v1beta1 Deployment": "apps/v1 Deployment", + "extensions/v1beta1 DaemonSet": "apps/v1 DaemonSet", + "extensions/v1beta1 ReplicaSet": "apps/v1 ReplicaSet", + "extensions/v1beta1 PodSecurityPolicy": "policy/v1beta1 PodSecurityPolicy", + "extensions/v1beta1 NetworkPolicy": "networking.k8s.io/v1beta1 NetworkPolicy", + "extensions/v1beta1 Ingress": "networking.k8s.io/v1beta1 Ingress", + "apps/v1beta1 Deployment": "apps/v1 Deployment", + "apps/v1beta1 StatefulSet": "apps/v1 StatefulSet", + "apps/v1beta1 ReplicaSet": "apps/v1 ReplicaSet", + "apps/v1beta2 Deployment": "apps/v1 Deployment", + "apps/v1beta2 StatefulSet": "apps/v1 StatefulSet", + "apps/v1beta2 DaemonSet": "apps/v1 DaemonSet", + "apps/v1beta2 ReplicaSet": "apps/v1 ReplicaSet", + "apiextensions.k8s.io/v1beta1 CustomResourceDefinition": "apiextensions.k8s.io/v1 CustomResourceDefinition", + "rbac.authorization.k8s.io/v1alpha1 ClusterRole": "rbac.authorization.k8s.io/v1 ClusterRole", + "rbac.authorization.k8s.io/v1alpha1 ClusterRoleList": "rbac.authorization.k8s.io/v1 ClusterRoleList", + "rbac.authorization.k8s.io/v1alpha1 ClusterRoleBinding": "rbac.authorization.k8s.io/v1 ClusterRoleBinding", + "rbac.authorization.k8s.io/v1alpha1 ClusterRoleBindingList": "rbac.authorization.k8s.io/v1 ClusterRoleBindingList", + "rbac.authorization.k8s.io/v1alpha1 Role": "rbac.authorization.k8s.io/v1 Role", + "rbac.authorization.k8s.io/v1alpha1 RoleList": "rbac.authorization.k8s.io/v1 RoleList", + "rbac.authorization.k8s.io/v1alpha1 RoleBinding": "rbac.authorization.k8s.io/v1 RoleBinding", + "rbac.authorization.k8s.io/v1alpha1 RoleBindingList": "rbac.authorization.k8s.io/v1 RoleBindingList", + "rbac.authorization.k8s.io/v1beta1 ClusterRole": "rbac.authorization.k8s.io/v1 ClusterRole", + "rbac.authorization.k8s.io/v1beta1 ClusterRoleList": "rbac.authorization.k8s.io/v1 ClusterRoleList", + "rbac.authorization.k8s.io/v1beta1 ClusterRoleBinding": "rbac.authorization.k8s.io/v1 ClusterRoleBinding", + "rbac.authorization.k8s.io/v1beta1 ClusterRoleBindingList": "rbac.authorization.k8s.io/v1 ClusterRoleBindingList", + "rbac.authorization.k8s.io/v1beta1 Role": "rbac.authorization.k8s.io/v1 Role", + "rbac.authorization.k8s.io/v1beta1 RoleList": "rbac.authorization.k8s.io/v1 RoleList", + "rbac.authorization.k8s.io/v1beta1 RoleBinding": "rbac.authorization.k8s.io/v1 RoleBinding", + "rbac.authorization.k8s.io/v1beta1 RoleBindingList": "rbac.authorization.k8s.io/v1 RoleBindingList", } // deprecatedAPIError indicates than an API is deprecated in Kubernetes diff --git a/pkg/lint/rules/deprecations_test.go b/pkg/lint/rules/deprecations_test.go index f85d58a0c..1e8d34702 100644 --- a/pkg/lint/rules/deprecations_test.go +++ b/pkg/lint/rules/deprecations_test.go @@ -20,7 +20,7 @@ import "testing" func TestValidateNoDeprecations(t *testing.T) { deprecated := &K8sYamlStruct{ - APIVersion: "extensions/v1", + APIVersion: "extensions/v1beta1", Kind: "Deployment", } err := validateNoDeprecations(deprecated) From 93b0eee0dff2849081f16b47f4693fd8b25115bc Mon Sep 17 00:00:00 2001 From: Idan Elhalwani Date: Thu, 7 May 2020 12:11:24 +0300 Subject: [PATCH 037/159] Set DisableCompression to true to disable unwanted httpclient transformation Signed-off-by: Idan Elhalwani --- pkg/getter/httpgetter.go | 29 +++++++++------------ pkg/getter/httpgetter_test.go | 39 ++++++++++++++++++++++++++++ pkg/getter/testdata/empty-0.0.1.tgz | Bin 0 -> 130 bytes 3 files changed, 51 insertions(+), 17 deletions(-) create mode 100644 pkg/getter/testdata/empty-0.0.1.tgz diff --git a/pkg/getter/httpgetter.go b/pkg/getter/httpgetter.go index 695a87743..46c817a9c 100644 --- a/pkg/getter/httpgetter.go +++ b/pkg/getter/httpgetter.go @@ -90,6 +90,10 @@ func NewHTTPGetter(options ...Option) (Getter, error) { } func (g *HTTPGetter) httpClient() (*http.Client, error) { + transport := &http.Transport{ + DisableCompression: true, + Proxy: http.ProxyFromEnvironment, + } if (g.opts.certFile != "" && g.opts.keyFile != "") || g.opts.caFile != "" { tlsConf, err := tlsutil.NewClientTLS(g.opts.certFile, g.opts.keyFile, g.opts.caFile) if err != nil { @@ -103,28 +107,19 @@ func (g *HTTPGetter) httpClient() (*http.Client, error) { } tlsConf.ServerName = sni - client := &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: tlsConf, - Proxy: http.ProxyFromEnvironment, - }, - } - - return client, nil + transport.TLSClientConfig = tlsConf } if g.opts.insecureSkipVerifyTLS { - client := &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - Proxy: http.ProxyFromEnvironment, - }, + transport.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: true, } - return client, nil } - return http.DefaultClient, nil + client := &http.Client{ + Transport: transport, + } + + return client, nil } diff --git a/pkg/getter/httpgetter_test.go b/pkg/getter/httpgetter_test.go index 4d7ada852..0e157eccd 100644 --- a/pkg/getter/httpgetter_test.go +++ b/pkg/getter/httpgetter_test.go @@ -17,10 +17,13 @@ package getter import ( "fmt" + "io" "net/http" "net/http/httptest" "net/url" + "os" "path/filepath" + "strconv" "strings" "testing" @@ -248,3 +251,39 @@ func TestDownloadInsecureSkipTLSVerify(t *testing.T) { } } + +func TestHTTPGetterTarDownload(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + f, _ := os.Open("testdata/empty-0.0.1.tgz") + defer f.Close() + + b := make([]byte, 512) + f.Read(b) + //Get the file size + FileStat, _ := f.Stat() + FileSize := strconv.FormatInt(FileStat.Size(), 10) + + //Simulating improper header values from bitbucket + w.Header().Set("Content-Type", "application/x-tar") + w.Header().Set("Content-Encoding", "gzip") + w.Header().Set("Content-Length", FileSize) + + f.Seek(0, 0) + io.Copy(w, f) + })) + + defer srv.Close() + + g, err := NewHTTPGetter(WithURL(srv.URL)) + if err != nil { + t.Fatal(err) + } + + data, _ := g.Get(srv.URL) + mimeType := http.DetectContentType(data.Bytes()) + + expectedMimeType := "application/x-gzip" + if mimeType != expectedMimeType { + t.Fatalf("Expected response with MIME type %s, but got %s", expectedMimeType, mimeType) + } +} \ No newline at end of file diff --git a/pkg/getter/testdata/empty-0.0.1.tgz b/pkg/getter/testdata/empty-0.0.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..6c4c3d20597f344826ec27c18aeca1ae585392b7 GIT binary patch literal 130 zcmb2|=3v-$Wpf+@^V Date: Sat, 9 May 2020 16:57:16 +0530 Subject: [PATCH 038/159] Fixes repo parsing Signed-off-by: Juned Memon --- internal/experimental/registry/reference.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/internal/experimental/registry/reference.go b/internal/experimental/registry/reference.go index ced6cf33a..73c409ba2 100644 --- a/internal/experimental/registry/reference.go +++ b/internal/experimental/registry/reference.go @@ -34,6 +34,10 @@ var ( referenceDelimiter = regexp.MustCompile(`[:]`) errEmptyRepo = errors.New("parsed repo was empty") errTooManyColons = errors.New("ref may only contain a single colon character (:) unless specifying a port number") + // ErrInvalid is returned when there is an invalid reference + ErrInvalid = errors.New("invalid reference") + // ErrHostnameRequired is returned when the hostname is required + ErrHostnameRequired = errors.New("hostname required") ) type ( @@ -86,6 +90,7 @@ func (ref *Reference) FullName() string { // validate makes sure the ref meets our criteria func (ref *Reference) validate() error { + err := ref.validateRepo() if err != nil { return err @@ -100,7 +105,15 @@ func (ref *Reference) validateRepo() error { } // Makes sure the repo results in a parsable URL (similar to what is done // with containerd reference parsing) - _, err := url.Parse(ref.Repo) + u, err := url.Parse("dummy://" + ref.Repo) + + if u.Scheme != "dummy" { + return ErrInvalid + } + + if u.Host == "" { + return ErrHostnameRequired + } return err } From 8cb9ab7095c885e1f8d9bea3a28229f58ba59a5e Mon Sep 17 00:00:00 2001 From: Juned Memon Date: Sat, 9 May 2020 18:05:28 +0530 Subject: [PATCH 039/159] Fixes repo parsing Signed-off-by: Juned Memon --- internal/experimental/registry/reference.go | 14 +------------- internal/experimental/registry/reference_test.go | 7 +++++++ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/internal/experimental/registry/reference.go b/internal/experimental/registry/reference.go index 73c409ba2..13d3d046f 100644 --- a/internal/experimental/registry/reference.go +++ b/internal/experimental/registry/reference.go @@ -34,10 +34,6 @@ var ( referenceDelimiter = regexp.MustCompile(`[:]`) errEmptyRepo = errors.New("parsed repo was empty") errTooManyColons = errors.New("ref may only contain a single colon character (:) unless specifying a port number") - // ErrInvalid is returned when there is an invalid reference - ErrInvalid = errors.New("invalid reference") - // ErrHostnameRequired is returned when the hostname is required - ErrHostnameRequired = errors.New("hostname required") ) type ( @@ -105,15 +101,7 @@ func (ref *Reference) validateRepo() error { } // Makes sure the repo results in a parsable URL (similar to what is done // with containerd reference parsing) - u, err := url.Parse("dummy://" + ref.Repo) - - if u.Scheme != "dummy" { - return ErrInvalid - } - - if u.Host == "" { - return ErrHostnameRequired - } + _, err := url.Parse("dummy://" + ref.Repo) return err } diff --git a/internal/experimental/registry/reference_test.go b/internal/experimental/registry/reference_test.go index bb53ebab8..aae03ad99 100644 --- a/internal/experimental/registry/reference_test.go +++ b/internal/experimental/registry/reference_test.go @@ -81,6 +81,13 @@ func TestParseReference(t *testing.T) { is.Equal("1.5.0", ref.Tag) is.Equal("myrepo:5001/mychart:1.5.0", ref.FullName()) + s = "127.0.0.1:5001/mychart:1.5.0" + ref, err = ParseReference(s) + is.NoError(err) + is.Equal("127.0.0.1:5001/mychart", ref.Repo) + is.Equal("1.5.0", ref.Tag) + is.Equal("127.0.0.1:5001/mychart:1.5.0", ref.FullName()) + s = "localhost:5000/mychart:latest" ref, err = ParseReference(s) is.NoError(err) From 95e9e18ab585ce3e67c373841efae378886189ee Mon Sep 17 00:00:00 2001 From: Juned Memon Date: Mon, 11 May 2020 07:51:45 +0530 Subject: [PATCH 040/159] Removed scheme Signed-off-by: Juned Memon --- internal/experimental/registry/reference.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/experimental/registry/reference.go b/internal/experimental/registry/reference.go index 13d3d046f..ebab29a7e 100644 --- a/internal/experimental/registry/reference.go +++ b/internal/experimental/registry/reference.go @@ -101,7 +101,7 @@ func (ref *Reference) validateRepo() error { } // Makes sure the repo results in a parsable URL (similar to what is done // with containerd reference parsing) - _, err := url.Parse("dummy://" + ref.Repo) + _, err := url.Parse("//" + ref.Repo) return err } From 59eed4e81f840bfa8a5aa69fc6c92471413609eb Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Tue, 12 May 2020 14:23:25 -0600 Subject: [PATCH 041/159] feat: make the linter coalesce the passed-in values before running values tests (#7984) * fix: make the linter coalesce the passed-in values before running values tests Signed-off-by: Matt Butcher * fixed typo Signed-off-by: Matt Butcher --- internal/test/ensure/ensure.go | 19 +++++++ pkg/lint/lint.go | 2 +- pkg/lint/rules/values.go | 23 +++++++- pkg/lint/rules/values_test.go | 97 ++++++++++++++++++++++++++++++++-- 4 files changed, 135 insertions(+), 6 deletions(-) diff --git a/internal/test/ensure/ensure.go b/internal/test/ensure/ensure.go index 6219ad626..3c0e4575c 100644 --- a/internal/test/ensure/ensure.go +++ b/internal/test/ensure/ensure.go @@ -19,6 +19,7 @@ package ensure import ( "io/ioutil" "os" + "path/filepath" "testing" "helm.sh/helm/v3/pkg/helmpath" @@ -49,3 +50,21 @@ func TempDir(t *testing.T) string { } return d } + +// TempFile ensures a temp file for unit testing purposes. +// +// It returns the path to the directory (to which you will still need to join the filename) +// +// You must clean up the directory that is returned. +// +// tempdir := TempFile(t, "foo", []byte("bar")) +// defer os.RemoveAll(tempdir) +// filename := filepath.Join(tempdir, "foo") +func TempFile(t *testing.T, name string, data []byte) string { + path := TempDir(t) + filename := filepath.Join(path, name) + if err := ioutil.WriteFile(filename, data, 0755); err != nil { + t.Fatal(err) + } + return path +} diff --git a/pkg/lint/lint.go b/pkg/lint/lint.go index d47951671..223ead75a 100644 --- a/pkg/lint/lint.go +++ b/pkg/lint/lint.go @@ -30,7 +30,7 @@ func All(basedir string, values map[string]interface{}, namespace string, strict linter := support.Linter{ChartDir: chartDir} rules.Chartfile(&linter) - rules.Values(&linter) + rules.ValuesWithOverrides(&linter, values) rules.Templates(&linter, values, namespace, strict) return linter } diff --git a/pkg/lint/rules/values.go b/pkg/lint/rules/values.go index 0f202f475..c596687c5 100644 --- a/pkg/lint/rules/values.go +++ b/pkg/lint/rules/values.go @@ -28,7 +28,19 @@ import ( ) // Values lints a chart's values.yaml file. +// +// This function is deprecated and will be removed in Helm 4. func Values(linter *support.Linter) { + ValuesWithOverrides(linter, map[string]interface{}{}) +} + +// ValuesWithOverrides tests the values.yaml file. +// +// If a schema is present in the chart, values are tested against that. Otherwise, +// they are only tested for well-formedness. +// +// If additional values are supplied, they are coalesced into the values in values.yaml. +func ValuesWithOverrides(linter *support.Linter, values map[string]interface{}) { file := "values.yaml" vf := filepath.Join(linter.ChartDir, file) fileExists := linter.RunLinterRule(support.InfoSev, file, validateValuesFileExistence(vf)) @@ -37,7 +49,7 @@ func Values(linter *support.Linter) { return } - linter.RunLinterRule(support.ErrorSev, file, validateValuesFile(vf)) + linter.RunLinterRule(support.ErrorSev, file, validateValuesFile(vf, values)) } func validateValuesFileExistence(valuesPath string) error { @@ -48,12 +60,19 @@ func validateValuesFileExistence(valuesPath string) error { return nil } -func validateValuesFile(valuesPath string) error { +func validateValuesFile(valuesPath string, overrides map[string]interface{}) error { values, err := chartutil.ReadValuesFile(valuesPath) if err != nil { return errors.Wrap(err, "unable to parse YAML") } + // Helm 3.0.0 carried over the values linting from Helm 2.x, which only tests the top + // level values against the top-level expectations. Subchart values are not linted. + // We could change that. For now, though, we retain that strategy, and thus can + // coalesce tables (like reuse-values does) instead of doing the full chart + // CoalesceValues. + values = chartutil.CoalesceTables(values, overrides) + ext := filepath.Ext(valuesPath) schemaPath := valuesPath[:len(valuesPath)-len(ext)] + ".schema.json" schema, err := ioutil.ReadFile(schemaPath) diff --git a/pkg/lint/rules/values_test.go b/pkg/lint/rules/values_test.go index 901a739fd..6d93d630e 100644 --- a/pkg/lint/rules/values_test.go +++ b/pkg/lint/rules/values_test.go @@ -17,15 +17,41 @@ limitations under the License. package rules import ( + "io/ioutil" "os" "path/filepath" "testing" -) -var ( - nonExistingValuesFilePath = filepath.Join("/fake/dir", "values.yaml") + "github.com/stretchr/testify/assert" + + "helm.sh/helm/v3/internal/test/ensure" ) +var nonExistingValuesFilePath = filepath.Join("/fake/dir", "values.yaml") + +const testSchema = ` +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "helm values test schema", + "type": "object", + "additionalProperties": false, + "required": [ + "username", + "password" + ], + "properties": { + "username": { + "description": "Your username", + "type": "string" + }, + "password": { + "description": "Your password", + "type": "string" + } + } +} +` + func TestValidateValuesYamlNotDirectory(t *testing.T) { _ = os.Mkdir(nonExistingValuesFilePath, os.ModePerm) defer os.Remove(nonExistingValuesFilePath) @@ -35,3 +61,68 @@ func TestValidateValuesYamlNotDirectory(t *testing.T) { t.Errorf("validateValuesFileExistence to return a linter error, got no error") } } + +func TestValidateValuesFileWellFormed(t *testing.T) { + badYaml := ` + not:well[]{}formed + ` + tmpdir := ensure.TempFile(t, "values.yaml", []byte(badYaml)) + defer os.RemoveAll(tmpdir) + valfile := filepath.Join(tmpdir, "values.yaml") + if err := validateValuesFile(valfile, map[string]interface{}{}); err == nil { + t.Fatal("expected values file to fail parsing") + } +} + +func TestValidateValuesFileSchema(t *testing.T) { + yaml := "username: admin\npassword: swordfish" + tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml)) + defer os.RemoveAll(tmpdir) + createTestingSchema(t, tmpdir) + + valfile := filepath.Join(tmpdir, "values.yaml") + if err := validateValuesFile(valfile, map[string]interface{}{}); err != nil { + t.Fatalf("Failed validation with %s", err) + } +} + +func TestValidateValuesFileSchemaFailure(t *testing.T) { + // 1234 is an int, not a string. This should fail. + yaml := "username: 1234\npassword: swordfish" + tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml)) + defer os.RemoveAll(tmpdir) + createTestingSchema(t, tmpdir) + + valfile := filepath.Join(tmpdir, "values.yaml") + + err := validateValuesFile(valfile, map[string]interface{}{}) + if err == nil { + t.Fatal("expected values file to fail parsing") + } + + assert.Contains(t, err.Error(), "Expected: string, given: integer", "integer should be caught by schema") +} + +func TestValidateValuesFileSchemaOverrides(t *testing.T) { + yaml := "username: admin" + overrides := map[string]interface{}{ + "password": "swordfish", + } + tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml)) + defer os.RemoveAll(tmpdir) + createTestingSchema(t, tmpdir) + + valfile := filepath.Join(tmpdir, "values.yaml") + if err := validateValuesFile(valfile, overrides); err != nil { + t.Fatalf("Failed validation with %s", err) + } +} + +func createTestingSchema(t *testing.T, dir string) string { + t.Helper() + schemafile := filepath.Join(dir, "values.schema.json") + if err := ioutil.WriteFile(schemafile, []byte(testSchema), 0700); err != nil { + t.Fatalf("Failed to write schema to tmpdir: %s", err) + } + return schemafile +} From bf12ae39344aef012927ab391eb26ddd3a30ae30 Mon Sep 17 00:00:00 2001 From: Niels de Vos Date: Wed, 13 May 2020 01:08:53 +0200 Subject: [PATCH 042/159] scripts: do not use optional 'which' command in get-helm installation (#8048) When installing Helm, the following warning gets printed on the console: Downloading https://get.helm.sh/helm-v2.16.6-linux-amd64.tar.gz Preparing to install helm and tiller into /usr/local/bin helm installed into /usr/local/bin/helm tiller installed into /usr/local/bin/tiller main: line 178: which: command not found Run 'helm init' to configure helm. The 'which' command is optional, and not always installed on all environments (like a Fedora container). Instead, use 'command -v' to detect if the executable is in the $PATH. Signed-off-by: Niels de Vos --- scripts/get | 2 +- scripts/get-helm-3 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/get b/scripts/get index afa02bbb1..094892346 100755 --- a/scripts/get +++ b/scripts/get @@ -175,7 +175,7 @@ fail_trap() { # testVersion tests the installed client to make sure it is working. testVersion() { set +e - HELM="$(which $PROJECT_NAME)" + HELM="$(command -v $PROJECT_NAME)" if [ "$?" = "1" ]; then echo "$PROJECT_NAME not found. Is $HELM_INSTALL_DIR on your "'$PATH?' exit 1 diff --git a/scripts/get-helm-3 b/scripts/get-helm-3 index 201065717..1d0b3502e 100755 --- a/scripts/get-helm-3 +++ b/scripts/get-helm-3 @@ -165,7 +165,7 @@ fail_trap() { # testVersion tests the installed client to make sure it is working. testVersion() { set +e - HELM="$(which $BINARY_NAME)" + HELM="$(command -v $BINARY_NAME)" if [ "$?" = "1" ]; then echo "$BINARY_NAME not found. Is $HELM_INSTALL_DIR on your "'$PATH?' exit 1 From 75aa425bfcfdffdbdd285a03fb0fceab8e28c778 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Wed, 13 May 2020 08:36:47 -0700 Subject: [PATCH 043/159] bump to kubernetes 1.18.2 Signed-off-by: Matthew Fisher --- go.mod | 12 ++++++------ go.sum | 43 +++++++++++++++++-------------------------- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/go.mod b/go.mod index 64ebfe307..f23d152a2 100644 --- a/go.mod +++ b/go.mod @@ -34,13 +34,13 @@ require ( github.com/stretchr/testify v1.5.1 github.com/xeipuuv/gojsonschema v1.1.0 golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 - k8s.io/api v0.18.0 - k8s.io/apiextensions-apiserver v0.18.0 - k8s.io/apimachinery v0.18.0 - k8s.io/cli-runtime v0.18.0 - k8s.io/client-go v0.18.0 + k8s.io/api v0.18.2 + k8s.io/apiextensions-apiserver v0.18.2 + k8s.io/apimachinery v0.18.2 + k8s.io/cli-runtime v0.18.2 + k8s.io/client-go v0.18.2 k8s.io/klog v1.0.0 - k8s.io/kubectl v0.18.0 + k8s.io/kubectl v0.18.2 sigs.k8s.io/yaml v1.2.0 ) diff --git a/go.sum b/go.sum index 0a51a72e8..2908f3eb8 100644 --- a/go.sum +++ b/go.sum @@ -29,8 +29,6 @@ github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.0.3 h1:znjIyLfpXEDQjOIEWh+ehwpTU14UzUPub3c3sm36u14= -github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.1.0 h1:Y2lUDsFKVRSYGojLJ1yLxSXdMmMYTYls0rCvoqmMUQk= github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/sprig/v3 v3.1.0 h1:j7GpgZ7PdFqNsmncycTHsLmVPf5/3wJtlgW9TNDYD9Y= @@ -155,8 +153,6 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QL github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e h1:p1yVGRW3nmb85p1Sh1ZJSDm4A4iKLS5QNbvUHMgGu/M= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= @@ -321,13 +317,9 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0= -github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= -github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= @@ -587,7 +579,6 @@ golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo= @@ -737,20 +728,20 @@ gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.18.0 h1:lwYk8Vt7rsVTwjRU6pzEsa9YNhThbmbocQlKvNBB4EQ= -k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8= -k8s.io/apiextensions-apiserver v0.18.0 h1:HN4/P8vpGZFvB5SOMuPPH2Wt9Y/ryX+KRvIyAkchu1Q= -k8s.io/apiextensions-apiserver v0.18.0/go.mod h1:18Cwn1Xws4xnWQNC00FLq1E350b9lUF+aOdIWDOZxgo= -k8s.io/apimachinery v0.18.0 h1:fuPfYpk3cs1Okp/515pAf0dNhL66+8zk8RLbSX+EgAE= -k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= -k8s.io/apiserver v0.18.0/go.mod h1:3S2O6FeBBd6XTo0njUrLxiqk8GNy6wWOftjhJcXYnjw= -k8s.io/cli-runtime v0.18.0 h1:jG8XpSqQ5TrV0N+EZ3PFz6+gqlCk71dkggWCCq9Mq34= -k8s.io/cli-runtime v0.18.0/go.mod h1:1eXfmBsIJosjn9LjEBUd2WVPoPAY9XGTqTFcPMIBsUQ= -k8s.io/client-go v0.18.0 h1:yqKw4cTUQraZK3fcVCMeSa+lqKwcjZ5wtcOIPnxQno4= -k8s.io/client-go v0.18.0/go.mod h1:uQSYDYs4WhVZ9i6AIoEZuwUggLVEF64HOD37boKAtF8= -k8s.io/code-generator v0.18.0/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= -k8s.io/component-base v0.18.0 h1:I+lP0fNfsEdTDpHaL61bCAqTZLoiWjEEP304Mo5ZQgE= -k8s.io/component-base v0.18.0/go.mod h1:u3BCg0z1uskkzrnAKFzulmYaEpZF7XC9Pf/uFyb1v2c= +k8s.io/api v0.18.2 h1:wG5g5ZmSVgm5B+eHMIbI9EGATS2L8Z72rda19RIEgY8= +k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= +k8s.io/apiextensions-apiserver v0.18.2 h1:I4v3/jAuQC+89L3Z7dDgAiN4EOjN6sbm6iBqQwHTah8= +k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= +k8s.io/apimachinery v0.18.2 h1:44CmtbmkzVDAhCpRVSiP2R5PPrC2RtlIv/MoB8xpdRA= +k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= +k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= +k8s.io/cli-runtime v0.18.2 h1:JiTN5RgkFNTiMxHBRyrl6n26yKWAuNRlei1ZJALUmC8= +k8s.io/cli-runtime v0.18.2/go.mod h1:yfFR2sQQzDsV0VEKGZtrJwEy4hLZ2oj4ZIfodgxAHWQ= +k8s.io/client-go v0.18.2 h1:aLB0iaD4nmwh7arT2wIn+lMnAq7OswjaejkQ8p9bBYE= +k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= +k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= +k8s.io/component-base v0.18.2 h1:SJweNZAGcUvsypLGNPNGeJ9UgPZQ6+bW+gEHe8uyh/Y= +k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= @@ -759,10 +750,10 @@ k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c h1:/KUFqjjqAcY4Us6luF5RDNZ16KJtb49HfR3ZHB9qYXM= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/kubectl v0.18.0 h1:hu52Ndq/d099YW+3sS3VARxFz61Wheiq8K9S7oa82Dk= -k8s.io/kubectl v0.18.0/go.mod h1:LOkWx9Z5DXMEg5KtOjHhRiC1fqJPLyCr3KtQgEolCkU= +k8s.io/kubectl v0.18.2 h1:9jnGSOC2DDVZmMUTMi0D1aed438mfQcgqa5TAzVjA1k= +k8s.io/kubectl v0.18.2/go.mod h1:OdgFa3AlsPKRpFFYE7ICTwulXOcMGXHTc+UKhHKvrb4= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= -k8s.io/metrics v0.18.0/go.mod h1:8aYTW18koXqjLVKL7Ds05RPMX9ipJZI3mywYvBOxXd4= +k8s.io/metrics v0.18.2/go.mod h1:qga8E7QfYNR9Q89cSCAjinC9pTZ7yv1XSVGUB0vJypg= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= From bfb39c0c68b989eea6a0b648f36aa5c7f930a515 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Wed, 13 May 2020 11:10:47 -0700 Subject: [PATCH 044/159] bump DefaultCapabilities to 1.18 Signed-off-by: Matthew Fisher --- .../testdata/output/template-name-template.txt | 4 ++-- cmd/helm/testdata/output/template-set.txt | 4 ++-- .../output/template-show-only-multiple.txt | 4 ++-- .../testdata/output/template-show-only-one.txt | 4 ++-- cmd/helm/testdata/output/template-values-files.txt | 4 ++-- .../testdata/output/template-with-api-version.txt | 4 ++-- cmd/helm/testdata/output/template-with-crds.txt | 4 ++-- cmd/helm/testdata/output/template.txt | 4 ++-- pkg/chartutil/capabilities.go | 4 ++-- pkg/chartutil/capabilities_test.go | 14 +++++++------- 10 files changed, 25 insertions(+), 25 deletions(-) diff --git a/cmd/helm/testdata/output/template-name-template.txt b/cmd/helm/testdata/output/template-name-template.txt index 0130a2a92..24f2bb616 100644 --- a/cmd/helm/testdata/output/template-name-template.txt +++ b/cmd/helm/testdata/output/template-name-template.txt @@ -71,8 +71,8 @@ metadata: helm.sh/chart: "subchart1-0.1.0" app.kubernetes.io/instance: "foobar-YWJj-baz" kube-version/major: "1" - kube-version/minor: "16" - kube-version/version: "v1.16.0" + kube-version/minor: "18" + kube-version/version: "v1.18.0" spec: type: ClusterIP ports: diff --git a/cmd/helm/testdata/output/template-set.txt b/cmd/helm/testdata/output/template-set.txt index ddaa8886b..4c7f1f626 100644 --- a/cmd/helm/testdata/output/template-set.txt +++ b/cmd/helm/testdata/output/template-set.txt @@ -71,8 +71,8 @@ metadata: helm.sh/chart: "subchart1-0.1.0" app.kubernetes.io/instance: "RELEASE-NAME" kube-version/major: "1" - kube-version/minor: "16" - kube-version/version: "v1.16.0" + kube-version/minor: "18" + kube-version/version: "v1.18.0" spec: type: ClusterIP ports: diff --git a/cmd/helm/testdata/output/template-show-only-multiple.txt b/cmd/helm/testdata/output/template-show-only-multiple.txt index abb9a2e10..75b590e20 100644 --- a/cmd/helm/testdata/output/template-show-only-multiple.txt +++ b/cmd/helm/testdata/output/template-show-only-multiple.txt @@ -8,8 +8,8 @@ metadata: helm.sh/chart: "subchart1-0.1.0" app.kubernetes.io/instance: "RELEASE-NAME" kube-version/major: "1" - kube-version/minor: "16" - kube-version/version: "v1.16.0" + kube-version/minor: "18" + kube-version/version: "v1.18.0" kube-api-version/test: v1 spec: type: ClusterIP diff --git a/cmd/helm/testdata/output/template-show-only-one.txt b/cmd/helm/testdata/output/template-show-only-one.txt index f0dd0834e..ce61f481f 100644 --- a/cmd/helm/testdata/output/template-show-only-one.txt +++ b/cmd/helm/testdata/output/template-show-only-one.txt @@ -8,8 +8,8 @@ metadata: helm.sh/chart: "subchart1-0.1.0" app.kubernetes.io/instance: "RELEASE-NAME" kube-version/major: "1" - kube-version/minor: "16" - kube-version/version: "v1.16.0" + kube-version/minor: "18" + kube-version/version: "v1.18.0" kube-api-version/test: v1 spec: type: ClusterIP diff --git a/cmd/helm/testdata/output/template-values-files.txt b/cmd/helm/testdata/output/template-values-files.txt index ddaa8886b..4c7f1f626 100644 --- a/cmd/helm/testdata/output/template-values-files.txt +++ b/cmd/helm/testdata/output/template-values-files.txt @@ -71,8 +71,8 @@ metadata: helm.sh/chart: "subchart1-0.1.0" app.kubernetes.io/instance: "RELEASE-NAME" kube-version/major: "1" - kube-version/minor: "16" - kube-version/version: "v1.16.0" + kube-version/minor: "18" + kube-version/version: "v1.18.0" spec: type: ClusterIP ports: diff --git a/cmd/helm/testdata/output/template-with-api-version.txt b/cmd/helm/testdata/output/template-with-api-version.txt index 7a2a4d5bf..210dcc503 100644 --- a/cmd/helm/testdata/output/template-with-api-version.txt +++ b/cmd/helm/testdata/output/template-with-api-version.txt @@ -71,8 +71,8 @@ metadata: helm.sh/chart: "subchart1-0.1.0" app.kubernetes.io/instance: "RELEASE-NAME" kube-version/major: "1" - kube-version/minor: "16" - kube-version/version: "v1.16.0" + kube-version/minor: "18" + kube-version/version: "v1.18.0" kube-api-version/test: v1 spec: type: ClusterIP diff --git a/cmd/helm/testdata/output/template-with-crds.txt b/cmd/helm/testdata/output/template-with-crds.txt index b04a4d5d2..289eec291 100644 --- a/cmd/helm/testdata/output/template-with-crds.txt +++ b/cmd/helm/testdata/output/template-with-crds.txt @@ -87,8 +87,8 @@ metadata: helm.sh/chart: "subchart1-0.1.0" app.kubernetes.io/instance: "RELEASE-NAME" kube-version/major: "1" - kube-version/minor: "16" - kube-version/version: "v1.16.0" + kube-version/minor: "18" + kube-version/version: "v1.18.0" kube-api-version/test: v1 spec: type: ClusterIP diff --git a/cmd/helm/testdata/output/template.txt b/cmd/helm/testdata/output/template.txt index 8301c2231..82a21c5a1 100644 --- a/cmd/helm/testdata/output/template.txt +++ b/cmd/helm/testdata/output/template.txt @@ -71,8 +71,8 @@ metadata: helm.sh/chart: "subchart1-0.1.0" app.kubernetes.io/instance: "RELEASE-NAME" kube-version/major: "1" - kube-version/minor: "16" - kube-version/version: "v1.16.0" + kube-version/minor: "18" + kube-version/version: "v1.18.0" spec: type: ClusterIP ports: diff --git a/pkg/chartutil/capabilities.go b/pkg/chartutil/capabilities.go index f46350bb1..ce968c5d7 100644 --- a/pkg/chartutil/capabilities.go +++ b/pkg/chartutil/capabilities.go @@ -29,9 +29,9 @@ var ( // DefaultCapabilities is the default set of capabilities. DefaultCapabilities = &Capabilities{ KubeVersion: KubeVersion{ - Version: "v1.16.0", + Version: "v1.18.0", Major: "1", - Minor: "16", + Minor: "18", }, APIVersions: DefaultVersionSet, } diff --git a/pkg/chartutil/capabilities_test.go b/pkg/chartutil/capabilities_test.go index 3eeac76e2..416eea06d 100644 --- a/pkg/chartutil/capabilities_test.go +++ b/pkg/chartutil/capabilities_test.go @@ -42,19 +42,19 @@ func TestDefaultVersionSet(t *testing.T) { func TestDefaultCapabilities(t *testing.T) { kv := DefaultCapabilities.KubeVersion - if kv.String() != "v1.16.0" { - t.Errorf("Expected default KubeVersion.String() to be v1.16.0, got %q", kv.String()) + if kv.String() != "v1.18.0" { + t.Errorf("Expected default KubeVersion.String() to be v1.18.0, got %q", kv.String()) } - if kv.Version != "v1.16.0" { - t.Errorf("Expected default KubeVersion.Version to be v1.16.0, got %q", kv.Version) + if kv.Version != "v1.18.0" { + t.Errorf("Expected default KubeVersion.Version to be v1.18.0, got %q", kv.Version) } - if kv.GitVersion() != "v1.16.0" { - t.Errorf("Expected default KubeVersion.GitVersion() to be v1.16.0, got %q", kv.Version) + if kv.GitVersion() != "v1.18.0" { + t.Errorf("Expected default KubeVersion.GitVersion() to be v1.18.0, got %q", kv.Version) } if kv.Major != "1" { t.Errorf("Expected default KubeVersion.Major to be 1, got %q", kv.Major) } - if kv.Minor != "16" { + if kv.Minor != "18" { t.Errorf("Expected default KubeVersion.Minor to be 16, got %q", kv.Minor) } } From 2f39854d3f5da2f13cd749ccb08d61982cafef2f Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Wed, 13 May 2020 12:03:12 -0700 Subject: [PATCH 045/159] fix security mailing list address Signed-off-by: Matthew Fisher --- CONTRIBUTING.md | 206 +++++++++++++++++++++++++++--------------------- 1 file changed, 115 insertions(+), 91 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a637f9255..e27fa7d19 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,21 +1,22 @@ # Contributing Guidelines -The Helm project accepts contributions via GitHub pull requests. This document outlines the process to help get your contribution accepted. +The Helm project accepts contributions via GitHub pull requests. This document outlines the process +to help get your contribution accepted. ## Reporting a Security Issue -Most of the time, when you find a bug in Helm, it should be reported -using [GitHub issues](https://github.com/helm/helm/issues). However, if -you are reporting a _security vulnerability_, please email a report to -[cncf-kubernetes-helm-security@lists.cncf.io](mailto:cncf-kubernetes-helm-security@lists.cncf.io). This will give -us a chance to try to fix the issue before it is exploited in the wild. +Most of the time, when you find a bug in Helm, it should be reported using [GitHub +issues](https://github.com/helm/helm/issues). However, if you are reporting a _security +vulnerability_, please email a report to +[cncf-helm-security@lists.cncf.io](mailto:cncf-helm-security@lists.cncf.io). This will give us a +chance to try to fix the issue before it is exploited in the wild. ## Sign Your Work -The sign-off is a simple line at the end of the explanation for a commit. All -commits needs to be signed. Your signature certifies that you wrote the patch or -otherwise have the right to contribute the material. The rules are pretty simple, -if you can certify the below (from [developercertificate.org](https://developercertificate.org/)): +The sign-off is a simple line at the end of the explanation for a commit. All commits needs to be +signed. Your signature certifies that you wrote the patch or otherwise have the right to contribute +the material. The rules are pretty simple, if you can certify the below (from +[developercertificate.org](https://developercertificate.org/)): ``` Developer Certificate of Origin @@ -62,11 +63,11 @@ Then you just add a line to every git commit message: Use your real name (sorry, no pseudonyms or anonymous contributions.) -If you set your `user.name` and `user.email` git configs, you can sign your -commit automatically with `git commit -s`. +If you set your `user.name` and `user.email` git configs, you can sign your commit automatically +with `git commit -s`. -Note: If your git config information is set properly then viewing the - `git log` information for your commit will look something like this: +Note: If your git config information is set properly then viewing the `git log` information for your + commit will look something like this: ``` Author: Joe Smith @@ -77,8 +78,8 @@ Date: Thu Feb 2 11:41:15 2018 -0800 Signed-off-by: Joe Smith ``` -Notice the `Author` and `Signed-off-by` lines match. If they don't -your PR will be rejected by the automated DCO check. +Notice the `Author` and `Signed-off-by` lines match. If they don't your PR will be rejected by the +automated DCO check. ## Support Channels @@ -89,49 +90,69 @@ Whether you are a user or contributor, official support channels include: - User: [#helm-users](https://kubernetes.slack.com/messages/C0NH30761/details/) - Contributor: [#helm-dev](https://kubernetes.slack.com/messages/C51E88VDG/) -Before opening a new issue or submitting a new pull request, it's helpful to search the project - it's likely that another user has already reported the issue you're facing, or it's a known issue that we're already aware of. It is also worth asking on the Slack channels. +Before opening a new issue or submitting a new pull request, it's helpful to search the project - +it's likely that another user has already reported the issue you're facing, or it's a known issue +that we're already aware of. It is also worth asking on the Slack channels. ## Milestones -We use milestones to track progress of releases. There are also 2 special milestones -used for helping us keep work organized: `Upcoming - Minor` and `Upcoming - Major` +We use milestones to track progress of releases. There are also 2 special milestones used for +helping us keep work organized: `Upcoming - Minor` and `Upcoming - Major` -`Upcoming - Minor` is used for keeping track of issues that aren't assigned to a specific -release but could easily be addressed in a minor release. `Upcoming - Major` keeps track -of issues that will need to be addressed in a major release. For example, if the current -version is `3.2.0` an issue/PR could fall in to one of 4 different active milestones: -`3.2.1`, `3.3.0`, `Upcoming - Minor`, or `Upcoming - Major`. If an issue pertains to a -specific upcoming bug or minor release, it would go into `3.2.1` or `3.3.0`. If the issue/PR -does not have a specific milestone yet, but it is likely that it will land in a `3.X` release, -it should go into `Upcoming - Minor`. If the issue/PR is a large functionality add or change -and/or it breaks compatibility, then it should be added to the `Upcoming - Major` milestone. -An issue that we are not sure we will be doing will not be added to any milestone. +`Upcoming - Minor` is used for keeping track of issues that aren't assigned to a specific release +but could easily be addressed in a minor release. `Upcoming - Major` keeps track of issues that will +need to be addressed in a major release. For example, if the current version is `3.2.0` an issue/PR +could fall in to one of 4 different active milestones: `3.2.1`, `3.3.0`, `Upcoming - Minor`, or +`Upcoming - Major`. If an issue pertains to a specific upcoming bug or minor release, it would go +into `3.2.1` or `3.3.0`. If the issue/PR does not have a specific milestone yet, but it is likely +that it will land in a `3.X` release, it should go into `Upcoming - Minor`. If the issue/PR is a +large functionality add or change and/or it breaks compatibility, then it should be added to the +`Upcoming - Major` milestone. An issue that we are not sure we will be doing will not be added to +any milestone. -A milestone (and hence release) is considered done when all outstanding issues/PRs have been closed or moved to another milestone. +A milestone (and hence release) is considered done when all outstanding issues/PRs have been closed +or moved to another milestone. ## Semantic Versioning -Helm maintains a strong commitment to backward compatibility. All of our changes to protocols and formats are backward compatible from one major release to the next. No features, flags, or commands are removed or substantially modified (unless we need to fix a security issue). +Helm maintains a strong commitment to backward compatibility. All of our changes to protocols and +formats are backward compatible from one major release to the next. No features, flags, or commands +are removed or substantially modified (unless we need to fix a security issue). -We also try very hard to not change publicly accessible Go library definitions inside of the `pkg/` directory of our source code. +We also try very hard to not change publicly accessible Go library definitions inside of the `pkg/` +directory of our source code. For a quick summary of our backward compatibility guidelines for releases between 3.0 and 4.0: - Command line commands, flags, and arguments MUST be backward compatible - File formats (such as Chart.yaml) MUST be backward compatible -- Any chart that worked on a previous version of Helm 3 MUST work on a new version of Helm 3 (barring the cases where (a) Kubernetes itself changed, and (b) the chart worked because it exploited a bug) +- Any chart that worked on a previous version of Helm 3 MUST work on a new version of Helm 3 + (barring the cases where (a) Kubernetes itself changed, and (b) the chart worked because it + exploited a bug) - Chart repository functionality MUST be backward compatible -- Go libraries inside of `pkg/` SHOULD remain backward compatible, though code inside of `cmd/` and `internal/` may be changed from release to release without notice. +- Go libraries inside of `pkg/` SHOULD remain backward compatible, though code inside of `cmd/` and + `internal/` may be changed from release to release without notice. ## Support Contract for Helm 2 -With Helm 2's current release schedule, we want to take into account any migration issues for users due to the upcoming holiday shopping season and tax season. We also want to clarify what actions may occur after the support contract ends for Helm 2, so that users will not be surprised or caught off guard. +With Helm 2's current release schedule, we want to take into account any migration issues for users +due to the upcoming holiday shopping season and tax season. We also want to clarify what actions may +occur after the support contract ends for Helm 2, so that users will not be surprised or caught off +guard. -After Helm 2.15.0 is released, Helm 2 will go into "maintenance mode". We will continue to accept bug fixes and fix any security issues that arise, but no new features will be accepted for Helm 2. All feature development will be moved over to Helm 3. +After Helm 2.15.0 is released, Helm 2 will go into "maintenance mode". We will continue to accept +bug fixes and fix any security issues that arise, but no new features will be accepted for Helm 2. +All feature development will be moved over to Helm 3. -6 months after Helm 3.0.0's public release, Helm 2 will stop accepting bug fixes. Only security issues will be accepted. +6 months after Helm 3.0.0's public release, Helm 2 will stop accepting bug fixes. Only security +issues will be accepted. -12 months after Helm 3.0.0's public release, support for Helm 2 will formally end. Download links for the Helm 2 client through Google Cloud Storage, the Docker image for Tiller stored in Google Container Registry, and the Google Cloud buckets for the stable and incubator chart repositories may no longer work at any point. Client downloads through `get.helm.sh` will continue to work, and we will distribute a Tiller image that will be made available at an alternative location which can be updated with `helm init --tiller-image`. +12 months after Helm 3.0.0's public release, support for Helm 2 will formally end. Download links +for the Helm 2 client through Google Cloud Storage, the Docker image for Tiller stored in Google +Container Registry, and the Google Cloud buckets for the stable and incubator chart repositories may +no longer work at any point. Client downloads through `get.helm.sh` will continue to work, and we +will distribute a Tiller image that will be made available at an alternative location which can be +updated with `helm init --tiller-image`. ## Issues @@ -141,45 +162,46 @@ Issues are used as the primary method for tracking anything to do with the Helm There are 5 types of issues (each with their own corresponding [label](#labels)): -- `question/support`: These are support or functionality inquiries that we want to have a record of for -future reference. Generally these are questions that are too complex or large to store in the -Slack channel or have particular interest to the community as a whole. Depending on the discussion, -these can turn into `feature` or `bug` issues. +- `question/support`: These are support or functionality inquiries that we want to have a record of + for future reference. Generally these are questions that are too complex or large to store in the + Slack channel or have particular interest to the community as a whole. Depending on the + discussion, these can turn into `feature` or `bug` issues. - `proposal`: Used for items (like this one) that propose a new ideas or functionality that require -a larger community discussion. This allows for feedback from others in the community before a -feature is actually developed. This is not needed for small additions. Final word on whether or -not a feature needs a proposal is up to the core maintainers. All issues that are proposals should -both have a label and an issue title of "Proposal: [the rest of the title]." A proposal can become -a `feature` and does not require a milestone. -- `feature`: These track specific feature requests and ideas until they are complete. They can evolve -from a `proposal` or can be submitted individually depending on the size. + a larger community discussion. This allows for feedback from others in the community before a + feature is actually developed. This is not needed for small additions. Final word on whether or + not a feature needs a proposal is up to the core maintainers. All issues that are proposals should + both have a label and an issue title of "Proposal: [the rest of the title]." A proposal can become + a `feature` and does not require a milestone. +- `feature`: These track specific feature requests and ideas until they are complete. They can + evolve from a `proposal` or can be submitted individually depending on the size. - `bug`: These track bugs with the code - `docs`: These track problems with the documentation (i.e. missing or incomplete) ### Issue Lifecycle The issue lifecycle is mainly driven by the core maintainers, but is good information for those -contributing to Helm. All issue types follow the same general lifecycle. Differences are noted below. +contributing to Helm. All issue types follow the same general lifecycle. Differences are noted +below. 1. Issue creation 2. Triage - - The maintainer in charge of triaging will apply the proper labels for the issue. This - includes labels for priority, type, and metadata (such as `good first issue`). The only issue - priority we will be tracking is whether or not the issue is "critical." If additional - levels are needed in the future, we will add them. - - (If needed) Clean up the title to succinctly and clearly state the issue. Also ensure - that proposals are prefaced with "Proposal: [the rest of the title]". - - Add the issue to the correct milestone. If any questions come up, don't worry about - adding the issue to a milestone until the questions are answered. + - The maintainer in charge of triaging will apply the proper labels for the issue. This includes + labels for priority, type, and metadata (such as `good first issue`). The only issue priority + we will be tracking is whether or not the issue is "critical." If additional levels are needed + in the future, we will add them. + - (If needed) Clean up the title to succinctly and clearly state the issue. Also ensure that + proposals are prefaced with "Proposal: [the rest of the title]". + - Add the issue to the correct milestone. If any questions come up, don't worry about adding the + issue to a milestone until the questions are answered. - We attempt to do this process at least once per work day. 3. Discussion - issues that are labeled as `feature` or `bug` should be connected to the PR that resolves it. - - Whoever is working on a `feature` or `bug` issue (whether a maintainer or someone from - the community), should either assign the issue to themself or make a comment in the issue - saying that they are taking it. - - `proposal` and `support/question` issues should stay open until resolved or if they have not been - active for more than 30 days. This will help keep the issue queue to a manageable size and - reduce noise. Should the issue need to stay open, the `keep open` label can be added. + - Whoever is working on a `feature` or `bug` issue (whether a maintainer or someone from the + community), should either assign the issue to themself or make a comment in the issue saying + that they are taking it. + - `proposal` and `support/question` issues should stay open until resolved or if they have not + been active for more than 30 days. This will help keep the issue queue to a manageable size + and reduce noise. Should the issue need to stay open, the `keep open` label can be added. 4. Issue closure ## How to Contribute a Patch @@ -188,7 +210,8 @@ contributing to Helm. All issue types follow the same general lifecycle. Differe 2. Fork the desired repo; develop and test your code changes. 3. Submit a pull request, making sure to sign your work and link the related issue. -Coding conventions and standards are explained in the [official developer docs](https://helm.sh/docs/developers/). +Coding conventions and standards are explained in the [official developer +docs](https://helm.sh/docs/developers/). ## Pull Requests @@ -199,41 +222,42 @@ Like any good open source project, we use Pull Requests (PRs) to track code chan 1. PR creation - PRs are usually created to fix or else be a subset of other PRs that fix a particular issue. - We more than welcome PRs that are currently in progress. They are a great way to keep track of - important work that is in-flight, but useful for others to see. If a PR is a work in progress, - it **must** be prefaced with "WIP: [title]". Once the PR is ready for review, remove "WIP" from - the title. + important work that is in-flight, but useful for others to see. If a PR is a work in progress, + it **must** be prefaced with "WIP: [title]". Once the PR is ready for review, remove "WIP" + from the title. - It is preferred, but not required, to have a PR tied to a specific issue. There can be - circumstances where if it is a quick fix then an issue might be overkill. The details provided - in the PR description would suffice in this case. + circumstances where if it is a quick fix then an issue might be overkill. The details provided + in the PR description would suffice in this case. 2. Triage - The maintainer in charge of triaging will apply the proper labels for the issue. This should - include at least a size label, `bug` or `feature`, and `awaiting review` once all labels are applied. - See the [Labels section](#labels) for full details on the definitions of labels. + include at least a size label, `bug` or `feature`, and `awaiting review` once all labels are + applied. See the [Labels section](#labels) for full details on the definitions of labels. - Add the PR to the correct milestone. This should be the same as the issue the PR closes. 3. Assigning reviews - - Once a review has the `awaiting review` label, maintainers will review them as schedule permits. - The maintainer who takes the issue should self-request a review. - - Any PR with the `size/large` label requires 2 review approvals from maintainers before it can be - merged. Those with `size/medium` or `size/small` are per the judgement of the maintainers. + - Once a review has the `awaiting review` label, maintainers will review them as schedule + permits. The maintainer who takes the issue should self-request a review. + - Any PR with the `size/large` label requires 2 review approvals from maintainers before it can + be merged. Those with `size/medium` or `size/small` are per the judgement of the maintainers. 4. Reviewing/Discussion - All reviews will be completed using Github review tool. - A "Comment" review should be used when there are questions about the code that should be - answered, but that don't involve code changes. This type of review does not count as approval. - - A "Changes Requested" review indicates that changes to the code need to be made before they will be merged. + answered, but that don't involve code changes. This type of review does not count as approval. + - A "Changes Requested" review indicates that changes to the code need to be made before they + will be merged. - Reviewers should update labels as needed (such as `needs rebase`) 5. Address comments by answering questions or changing code 6. LGTM (Looks good to me) - - Once a Reviewer has completed a review and the code looks ready to merge, an "Approve" review is used - to signal to the contributor and to other maintainers that you have reviewed the code and feel that it is - ready to be merged. + - Once a Reviewer has completed a review and the code looks ready to merge, an "Approve" review + is used to signal to the contributor and to other maintainers that you have reviewed the code + and feel that it is ready to be merged. 7. Merge or close - - PRs should stay open until merged or if they have not been active for more than 30 days. - This will help keep the PR queue to a manageable size and reduce noise. Should the PR need - to stay open (like in the case of a WIP), the `keep open` label can be added. + - PRs should stay open until merged or if they have not been active for more than 30 days. This + will help keep the PR queue to a manageable size and reduce noise. Should the PR need to stay + open (like in the case of a WIP), the `keep open` label can be added. - Before merging a PR, refer to the topic on [Size Labels](#size-labels) below to determine if the PR requires more than one LGTM to merge. - If the owner of the PR is listed in the `OWNERS` file, that user **must** merge their own PRs - or explicitly request another OWNER do that for them. + or explicitly request another OWNER do that for them. - If the owner of a PR is _not_ listed in `OWNERS`, any core maintainer may merge the PR. #### Documentation PRs @@ -286,12 +310,12 @@ The following tables define all label types used for Helm. It is split up by cat #### Size labels -Size labels are used to indicate how "dangerous" a PR is. The guidelines below are used to assign the -labels, but ultimately this can be changed by the maintainers. For example, even if a PR only makes -30 lines of changes in 1 file, but it changes key functionality, it will likely be labeled as `size/L` -because it requires sign off from multiple people. Conversely, a PR that adds a small feature, but requires -another 150 lines of tests to cover all cases, could be labeled as `size/S` even though the number of -lines is greater than defined below. +Size labels are used to indicate how "dangerous" a PR is. The guidelines below are used to assign +the labels, but ultimately this can be changed by the maintainers. For example, even if a PR only +makes 30 lines of changes in 1 file, but it changes key functionality, it will likely be labeled as +`size/L` because it requires sign off from multiple people. Conversely, a PR that adds a small +feature, but requires another 150 lines of tests to cover all cases, could be labeled as `size/S` +even though the number of lines is greater than defined below. PRs submitted by a core maintainer, regardless of size, only requires approval from one additional maintainer. This ensures there are at least two maintainers who are aware of any significant PRs From ae738d7d87bbd5db7203db7441fb11e32b02df40 Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Wed, 13 May 2020 23:51:32 +0200 Subject: [PATCH 046/159] feat(getter): add timeout option (#7950) To allow finer grain control over the request when utilizing `getter` as a package. Signed-off-by: Hidde Beydals --- pkg/getter/getter.go | 9 +++++++++ pkg/getter/httpgetter.go | 1 + pkg/getter/httpgetter_test.go | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/pkg/getter/getter.go b/pkg/getter/getter.go index 4ccc74834..8ee08cb7f 100644 --- a/pkg/getter/getter.go +++ b/pkg/getter/getter.go @@ -18,6 +18,7 @@ package getter import ( "bytes" + "time" "github.com/pkg/errors" @@ -36,6 +37,7 @@ type options struct { username string password string userAgent string + timeout time.Duration } // Option allows specifying various settings configurable by the user for overriding the defaults @@ -81,6 +83,13 @@ func WithTLSClientConfig(certFile, keyFile, caFile string) Option { } } +// WithTimeout sets the timeout for requests +func WithTimeout(timeout time.Duration) Option { + return func(opts *options) { + opts.timeout = timeout + } +} + // Getter is an interface to support GET to the specified URL. type Getter interface { // Get file content by url string diff --git a/pkg/getter/httpgetter.go b/pkg/getter/httpgetter.go index 46c817a9c..858af91ac 100644 --- a/pkg/getter/httpgetter.go +++ b/pkg/getter/httpgetter.go @@ -119,6 +119,7 @@ func (g *HTTPGetter) httpClient() (*http.Client, error) { client := &http.Client{ Transport: transport, + Timeout: g.opts.timeout, } return client, nil diff --git a/pkg/getter/httpgetter_test.go b/pkg/getter/httpgetter_test.go index 0e157eccd..7973b5f85 100644 --- a/pkg/getter/httpgetter_test.go +++ b/pkg/getter/httpgetter_test.go @@ -26,6 +26,7 @@ import ( "strconv" "strings" "testing" + "time" "github.com/pkg/errors" @@ -48,6 +49,7 @@ func TestHTTPGetter(t *testing.T) { join := filepath.Join ca, pub, priv := join(cd, "rootca.crt"), join(cd, "crt.pem"), join(cd, "key.pem") insecure := false + timeout := time.Second * 5 // Test with options g, err = NewHTTPGetter( @@ -55,6 +57,7 @@ func TestHTTPGetter(t *testing.T) { WithUserAgent("Groot"), WithTLSClientConfig(pub, priv, ca), WithInsecureSkipVerifyTLS(insecure), + WithTimeout(timeout), ) if err != nil { t.Fatal(err) @@ -93,6 +96,10 @@ func TestHTTPGetter(t *testing.T) { t.Errorf("Expected NewHTTPGetter to contain %t as InsecureSkipVerifyTLs flag, got %t", false, hg.opts.insecureSkipVerifyTLS) } + if hg.opts.timeout != timeout { + t.Errorf("Expected NewHTTPGetter to contain %s as Timeout flag, got %s", timeout, hg.opts.timeout) + } + // Test if setting insecureSkipVerifyTLS is being passed to the ops insecure = true From decab8ea2e6ea4b31560aff50abb2676a67ec8ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=98=8E=E5=90=8C=E5=AD=A6?= <11614773+liuming-dev@users.noreply.github.com> Date: Thu, 14 May 2020 05:53:37 +0800 Subject: [PATCH 047/159] fix: upgrade using --force shoud not run patch logic (#8000) fix helm/helm#7999 Signed-off-by: Liu Ming --- pkg/kube/client.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index c1de2b299..4683d8033 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -418,29 +418,29 @@ func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, kind = target.Mapping.GroupVersionKind.Kind ) - patch, patchType, err := createPatch(target, currentObj) - if err != nil { - return errors.Wrap(err, "failed to create patch") - } - - if patch == nil || string(patch) == "{}" { - c.Log("Looks like there are no changes for %s %q", target.Mapping.GroupVersionKind.Kind, target.Name) - // This needs to happen to make sure that tiller has the latest info from the API - // Otherwise there will be no labels and other functions that use labels will panic - if err := target.Get(); err != nil { - return errors.Wrap(err, "failed to refresh resource information") - } - return nil - } - // if --force is applied, attempt to replace the existing resource with the new object. if force { + var err error obj, err = helper.Replace(target.Namespace, target.Name, true, target.Object) if err != nil { return errors.Wrap(err, "failed to replace object") } c.Log("Replaced %q with kind %s for kind %s", target.Name, currentObj.GetObjectKind().GroupVersionKind().Kind, kind) } else { + patch, patchType, err := createPatch(target, currentObj) + if err != nil { + return errors.Wrap(err, "failed to create patch") + } + + if patch == nil || string(patch) == "{}" { + c.Log("Looks like there are no changes for %s %q", target.Mapping.GroupVersionKind.Kind, target.Name) + // This needs to happen to make sure that tiller has the latest info from the API + // Otherwise there will be no labels and other functions that use labels will panic + if err := target.Get(); err != nil { + return errors.Wrap(err, "failed to refresh resource information") + } + return nil + } // send patch to server obj, err = helper.Patch(target.Namespace, target.Name, patchType, patch, nil) if err != nil { From 512544b9abbc75418348b76037fee3156ea1d3bd Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Wed, 13 May 2020 18:09:27 -0400 Subject: [PATCH 048/159] Fixing PAX Header handling (#8086) * Fixing issue with PAX headers in plugin archive PAX Headers can be added by some systems that create archives. Helm should ignore them when extracting. There are two PAX headers. One is global and the other is not. Both are ignored. The test adds only the PAX global header because the Go tar package is unable to write the header that is not global. Closes #8084 Signed-off-by: Matt Farina * Removing the PAX header test as it is not working The PAX header test was making a WriteHeader call and ignoring the error. When writing the type TypeXHeader it was causing an error that was being silently ignored. The Go tar package cannot write this type and produces an error when one tries to. The error reads "cannot manually encode TypeXHeader, TypeGNULongName, or TypeGNULongLink headers" Signed-off-by: Matt Farina * Adding check of returned error in test Adding a check for the returned error to make sure a non-nil value is not returned. Signed-off-by: Matt Farina --- pkg/chart/loader/archive_test.go | 34 +++++---------------- pkg/plugin/installer/http_installer.go | 3 ++ pkg/plugin/installer/http_installer_test.go | 13 ++++++++ 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/pkg/chart/loader/archive_test.go b/pkg/chart/loader/archive_test.go index 7d8c8b51e..41b0af1aa 100644 --- a/pkg/chart/loader/archive_test.go +++ b/pkg/chart/loader/archive_test.go @@ -43,46 +43,26 @@ func TestLoadArchiveFiles(t *testing.T) { generate: func(w *tar.Writer) { // simulate the presence of a `pax_global_header` file like you would get when // processing a GitHub release archive. - _ = w.WriteHeader(&tar.Header{ + err := w.WriteHeader(&tar.Header{ Typeflag: tar.TypeXGlobalHeader, Name: "pax_global_header", }) - - // we need to have at least one file, otherwise we'll get the "no files in chart archive" error - _ = w.WriteHeader(&tar.Header{ - Typeflag: tar.TypeReg, - Name: "dir/empty", - }) - }, - check: func(t *testing.T, files []*BufferedFile, err error) { if err != nil { - t.Fatalf(`got unwanted error [%#v] for tar file with pax_global_header content`, err) + t.Fatal(err) } - if len(files) != 1 { - t.Fatalf(`expected to get one file but got [%v]`, files) - } - }, - }, - { - name: "should ignore files with TypeXHeader type", - generate: func(w *tar.Writer) { - // simulate the presence of a `pax_header` file like you might get when - // processing a GitHub release archive. - _ = w.WriteHeader(&tar.Header{ - Typeflag: tar.TypeXHeader, - Name: "pax_header", - }) - // we need to have at least one file, otherwise we'll get the "no files in chart archive" error - _ = w.WriteHeader(&tar.Header{ + err = w.WriteHeader(&tar.Header{ Typeflag: tar.TypeReg, Name: "dir/empty", }) + if err != nil { + t.Fatal(err) + } }, check: func(t *testing.T, files []*BufferedFile, err error) { if err != nil { - t.Fatalf(`got unwanted error [%#v] for tar file with pax_header content`, err) + t.Fatalf(`got unwanted error [%#v] for tar file with pax_global_header content`, err) } if len(files) != 1 { diff --git a/pkg/plugin/installer/http_installer.go b/pkg/plugin/installer/http_installer.go index 629bbec39..c07cad80a 100644 --- a/pkg/plugin/installer/http_installer.go +++ b/pkg/plugin/installer/http_installer.go @@ -188,6 +188,9 @@ func (g *TarGzExtractor) Extract(buffer *bytes.Buffer, targetDir string) error { return err } outFile.Close() + // We don't want to process these extension header files. + case tar.TypeXGlobalHeader, tar.TypeXHeader: + continue default: return errors.Errorf("unknown type: %b in %s", header.Typeflag, header.Name) } diff --git a/pkg/plugin/installer/http_installer_test.go b/pkg/plugin/installer/http_installer_test.go index b496a1b01..99470ace6 100644 --- a/pkg/plugin/installer/http_installer_test.go +++ b/pkg/plugin/installer/http_installer_test.go @@ -222,6 +222,19 @@ func TestExtract(t *testing.T) { t.Fatal(err) } } + + // Add pax global headers. This should be ignored. + // Note the PAX header that isn't global cannot be written using WriteHeader. + // Details are in the internal Go function for the tar packaged named + // allowedFormats. For a TypeXHeader it will return a message stating + // "cannot manually encode TypeXHeader, TypeGNULongName, or TypeGNULongLink headers" + if err := tw.WriteHeader(&tar.Header{ + Name: "pax_global_header", + Typeflag: tar.TypeXGlobalHeader, + }); err != nil { + t.Fatal(err) + } + if err := tw.Close(); err != nil { t.Fatal(err) } From b18e7e201e55ba38fdecbcf81e4da512e55444b4 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Thu, 14 May 2020 08:06:18 -0400 Subject: [PATCH 049/159] chore(*): Fix formatting Signed-off-by: Marc Khouzam --- pkg/getter/httpgetter.go | 2 +- pkg/getter/httpgetter_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/getter/httpgetter.go b/pkg/getter/httpgetter.go index 858af91ac..c100b2cc0 100644 --- a/pkg/getter/httpgetter.go +++ b/pkg/getter/httpgetter.go @@ -92,7 +92,7 @@ func NewHTTPGetter(options ...Option) (Getter, error) { func (g *HTTPGetter) httpClient() (*http.Client, error) { transport := &http.Transport{ DisableCompression: true, - Proxy: http.ProxyFromEnvironment, + Proxy: http.ProxyFromEnvironment, } if (g.opts.certFile != "" && g.opts.keyFile != "") || g.opts.caFile != "" { tlsConf, err := tlsutil.NewClientTLS(g.opts.certFile, g.opts.keyFile, g.opts.caFile) diff --git a/pkg/getter/httpgetter_test.go b/pkg/getter/httpgetter_test.go index 7973b5f85..90578f7b7 100644 --- a/pkg/getter/httpgetter_test.go +++ b/pkg/getter/httpgetter_test.go @@ -293,4 +293,4 @@ func TestHTTPGetterTarDownload(t *testing.T) { if mimeType != expectedMimeType { t.Fatalf("Expected response with MIME type %s, but got %s", expectedMimeType, mimeType) } -} \ No newline at end of file +} From 88f6991ffff04c48dd8fd257d238aca48aef80df Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Thu, 14 May 2020 15:00:41 -0400 Subject: [PATCH 050/159] feat(test): Update golangci-lint to 1.27.0 Since we've moved to Go 1.14, golangci-lint has been silently failing. This commit updates to a compatible version. Signed-off-by: Marc Khouzam --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e6ce2e242..bf3b78179 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,7 +9,7 @@ jobs: environment: GOCACHE: "/tmp/go/cache" - GOLANGCI_LINT_VERSION: "1.21.0" + GOLANGCI_LINT_VERSION: "1.27.0" steps: - checkout From 0366f9970f0ff5c0b61b02521d139445bfaeba8f Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Fri, 10 Apr 2020 11:47:31 -0400 Subject: [PATCH 051/159] fix(comp): Prepare plugin completion for Cobra 1.0 Cobra 1.0.0 introduces support for Custom Go Completions. However, there is a small difference compared to helm's existing solution. The difference is that Cobra will not complete sub-commands if there are any dynamic completion functions registered. The way helm implemented plugin completions had the dynamic completion function associated with the root plugin command (e.g. 2to3); with Cobra, this prevents any of the sub-commands of the plugin to be completed (i.e., 2to3 will not show the static sub-commands). The solution is to only register the dynamic completion function for a plugin command that doesn't have any further sub-commands. This allows all sub-commands to be completed properly, and when there are no more levels of sub-commands, the dynamic completion is called. This commit had to make two changes to achieve this: 1- refactor the load_plugins.go file to extract the logic to call the plugin.complete executable (for dynamic completions), so that it could be added to each final sub-command. 2- load the static completion not only for the "completion" command like before, but also for the "__complete" command, so that when the __complete command is called for dynamic completion of a sub-command, it is aware of the sub-command in question. The second change is also valuable for the future support of completion for the Fish shell. Completion for the fish shell uses the __complete command not only for dynamic completions but also for basic command and flag completion. This implies that the __complete command must be aware of the plugins sub-commands, and therefore that the plugin's static completion be loaded. Signed-off-by: Marc Khouzam --- cmd/helm/load_plugins.go | 263 +++++++++++++++++++++------------------ 1 file changed, 142 insertions(+), 121 deletions(-) diff --git a/cmd/helm/load_plugins.go b/cmd/helm/load_plugins.go index a23a067fb..36de50135 100644 --- a/cmd/helm/load_plugins.go +++ b/cmd/helm/load_plugins.go @@ -64,21 +64,6 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) { return } - processParent := func(cmd *cobra.Command, args []string) ([]string, error) { - k, u := manuallyProcessArgs(args) - if err := cmd.Parent().ParseFlags(k); err != nil { - return nil, err - } - return u, nil - } - - // If we are dealing with the completion command, we try to load more details about the plugins - // if available, so as to allow for command and flag completion - if subCmd, _, err := baseCmd.Find(os.Args[1:]); err == nil && subCmd.Name() == "completion" { - loadPluginsForCompletion(baseCmd, found) - return - } - // Now we create commands for all of these. for _, plug := range found { plug := plug @@ -87,33 +72,6 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) { md.Usage = fmt.Sprintf("the %q plugin", md.Name) } - // This function is used to setup the environment for the plugin and then - // call the executable specified by the parameter 'main' - callPluginExecutable := func(cmd *cobra.Command, main string, argv []string, out io.Writer) error { - env := os.Environ() - for k, v := range settings.EnvVars() { - env = append(env, fmt.Sprintf("%s=%s", k, v)) - } - - prog := exec.Command(main, argv...) - prog.Env = env - prog.Stdin = os.Stdin - prog.Stdout = out - prog.Stderr = os.Stderr - if err := prog.Run(); err != nil { - if eerr, ok := err.(*exec.ExitError); ok { - os.Stderr.Write(eerr.Stderr) - status := eerr.Sys().(syscall.WaitStatus) - return pluginError{ - error: errors.Errorf("plugin %q exited with error", md.Name), - code: status.ExitStatus(), - } - } - return err - } - return nil - } - c := &cobra.Command{ Use: md.Name, Short: md.Usage, @@ -134,62 +92,59 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) { return errors.Errorf("plugin %q exited with error", md.Name) } - return callPluginExecutable(cmd, main, argv, out) + return callPluginExecutable(md.Name, main, argv, out) }, // This passes all the flags to the subcommand. DisableFlagParsing: true, } + // TODO: Make sure a command with this name does not already exist. + baseCmd.AddCommand(c) - // Setup dynamic completion for the plugin - completion.RegisterValidArgsFunc(c, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - u, err := processParent(cmd, args) - if err != nil { - return nil, completion.BashCompDirectiveError - } - - // We will call the dynamic completion script of the plugin - main := strings.Join([]string{plug.Dir, pluginDynamicCompletionExecutable}, string(filepath.Separator)) - - argv := []string{} - if !md.IgnoreFlags { - argv = append(argv, u...) - argv = append(argv, toComplete) - } - plugin.SetupPluginEnv(settings, md.Name, plug.Dir) + // For completion, we try to load more details about the plugins so as to allow for command and + // flag completion of the plugin itself. + // We only do this when necessary (for the "completion" and "__complete" commands) to avoid the + // risk of a rogue plugin affecting Helm's normal behavior. + subCmd, _, err := baseCmd.Find(os.Args[1:]) + if (err == nil && (subCmd.Name() == "completion" || subCmd.Name() == completion.CompRequestCmd)) || + /* for the tests */ subCmd == baseCmd.Root() { + loadCompletionForPlugin(c, plug) + } + } +} - completion.CompDebugln(fmt.Sprintf("calling %s with args %v", main, argv)) - buf := new(bytes.Buffer) - if err := callPluginExecutable(cmd, main, argv, buf); err != nil { - return nil, completion.BashCompDirectiveError - } +func processParent(cmd *cobra.Command, args []string) ([]string, error) { + k, u := manuallyProcessArgs(args) + if err := cmd.Parent().ParseFlags(k); err != nil { + return nil, err + } + return u, nil +} - var completions []string - for _, comp := range strings.Split(buf.String(), "\n") { - // Remove any empty lines - if len(comp) > 0 { - completions = append(completions, comp) - } - } +// This function is used to setup the environment for the plugin and then +// call the executable specified by the parameter 'main' +func callPluginExecutable(pluginName string, main string, argv []string, out io.Writer) error { + env := os.Environ() + for k, v := range settings.EnvVars() { + env = append(env, fmt.Sprintf("%s=%s", k, v)) + } - // Check if the last line of output is of the form :, which - // indicates the BashCompletionDirective. - directive := completion.BashCompDirectiveDefault - if len(completions) > 0 { - lastLine := completions[len(completions)-1] - if len(lastLine) > 1 && lastLine[0] == ':' { - if strInt, err := strconv.Atoi(lastLine[1:]); err == nil { - directive = completion.BashCompDirective(strInt) - completions = completions[:len(completions)-1] - } - } + prog := exec.Command(main, argv...) + prog.Env = env + prog.Stdin = os.Stdin + prog.Stdout = out + prog.Stderr = os.Stderr + if err := prog.Run(); err != nil { + if eerr, ok := err.(*exec.ExitError); ok { + os.Stderr.Write(eerr.Stderr) + status := eerr.Sys().(syscall.WaitStatus) + return pluginError{ + error: errors.Errorf("plugin %q exited with error", pluginName), + code: status.ExitStatus(), } - - return completions, directive - }) - - // TODO: Make sure a command with this name does not already exist. - baseCmd.AddCommand(c) + } + return err } + return nil } // manuallyProcessArgs processes an arg array, removing special args. @@ -246,35 +201,31 @@ type pluginCommand struct { Commands []pluginCommand `json:"commands"` } -// loadPluginsForCompletion will load and parse any completion.yaml provided by the plugins -func loadPluginsForCompletion(baseCmd *cobra.Command, plugins []*plugin.Plugin) { - for _, plug := range plugins { - // Parse the yaml file providing the plugin's subcmds and flags - cmds, err := loadFile(strings.Join( - []string{plug.Dir, pluginStaticCompletionFile}, string(filepath.Separator))) - - if err != nil { - // The file could be missing or invalid. Either way, we at least create the command - // for the plugin name. - if settings.Debug { - log.Output(2, fmt.Sprintf("[info] %s\n", err.Error())) - } - cmds = &pluginCommand{Name: plug.Metadata.Name} +// loadCompletionForPlugin will load and parse any completion.yaml provided by the plugin +// and add the dynamic completion hook to call the optional plugin.complete +func loadCompletionForPlugin(pluginCmd *cobra.Command, plugin *plugin.Plugin) { + // Parse the yaml file providing the plugin's sub-commands and flags + cmds, err := loadFile(strings.Join( + []string{plugin.Dir, pluginStaticCompletionFile}, string(filepath.Separator))) + + if err != nil { + // The file could be missing or invalid. No static completion for this plugin. + if settings.Debug { + log.Output(2, fmt.Sprintf("[info] %s\n", err.Error())) } + // Continue to setup dynamic completion. + cmds = &pluginCommand{} + } - // We know what the plugin name must be. - // Let's set it in case the Name field was not specified correctly in the file. - // This insures that we will at least get the plugin name to complete, even if - // there is a problem with the completion.yaml file - cmds.Name = plug.Metadata.Name + // Preserve the Usage string specified for the plugin + cmds.Name = pluginCmd.Use - addPluginCommands(baseCmd, cmds) - } + addPluginCommands(plugin, pluginCmd, cmds) } -// addPluginCommands is a recursive method that adds the different levels -// of sub-commands and flags for the plugins that provide such information -func addPluginCommands(baseCmd *cobra.Command, cmds *pluginCommand) { +// addPluginCommands is a recursive method that adds each different level +// of sub-commands and flags for the plugins that have provided such information +func addPluginCommands(plugin *plugin.Plugin, baseCmd *cobra.Command, cmds *pluginCommand) { if cmds == nil { return } @@ -287,14 +238,19 @@ func addPluginCommands(baseCmd *cobra.Command, cmds *pluginCommand) { return } - // Create a fake command just so the completion script will include it - c := &cobra.Command{ - Use: cmds.Name, - ValidArgs: cmds.ValidArgs, - // A Run is required for it to be a valid command without subcommands - Run: func(cmd *cobra.Command, args []string) {}, + baseCmd.Use = cmds.Name + baseCmd.ValidArgs = cmds.ValidArgs + // Setup the same dynamic completion for each plugin sub-command. + // This is because if dynamic completion is triggered, there is a single executable + // to call (plugin.complete), so every sub-commands calls it in the same fashion. + if cmds.Commands == nil { + // Only setup dynamic completion if there are no sub-commands. This avoids + // calling plugin.complete at every completion, which greatly simplifies + // development of plugin.complete for plugin developers. + completion.RegisterValidArgsFunc(baseCmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { + return pluginDynamicComp(plugin, cmd, args, toComplete) + }) } - baseCmd.AddCommand(c) // Create fake flags. if len(cmds.Flags) > 0 { @@ -314,7 +270,7 @@ func addPluginCommands(baseCmd *cobra.Command, cmds *pluginCommand) { } } - f := c.Flags() + f := baseCmd.Flags() if len(longs) >= len(shorts) { for i := range longs { if i < len(shorts) { @@ -338,7 +294,16 @@ func addPluginCommands(baseCmd *cobra.Command, cmds *pluginCommand) { // Recursively add any sub-commands for _, cmd := range cmds.Commands { - addPluginCommands(c, &cmd) + // Create a fake command so that completion can be done for the sub-commands of the plugin + subCmd := &cobra.Command{ + // This prevents Cobra from removing the flags. We want to keep the flags to pass them + // to the dynamic completion script of the plugin. + DisableFlagParsing: true, + // A Run is required for it to be a valid command without subcommands + Run: func(cmd *cobra.Command, args []string) {}, + } + baseCmd.AddCommand(subCmd) + addPluginCommands(plugin, subCmd, &cmd) } } @@ -353,3 +318,59 @@ func loadFile(path string) (*pluginCommand, error) { err = yaml.Unmarshal(b, cmds) return cmds, err } + +// pluginDynamicComp call the plugin.complete script of the plugin (if available) +// to obtain the dynamic completion choices. It must pass all the flags and sub-commands +// specified in the command-line to the plugin.complete executable (except helm's global flags) +func pluginDynamicComp(plug *plugin.Plugin, cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { + md := plug.Metadata + + u, err := processParent(cmd, args) + if err != nil { + return nil, completion.BashCompDirectiveError + } + + // We will call the dynamic completion script of the plugin + main := strings.Join([]string{plug.Dir, pluginDynamicCompletionExecutable}, string(filepath.Separator)) + + // We must include all sub-commands passed on the command-line. + // To do that, we pass-in the entire CommandPath, except the first two elements + // which are 'helm' and 'pluginName'. + argv := strings.Split(cmd.CommandPath(), " ")[2:] + if !md.IgnoreFlags { + argv = append(argv, u...) + argv = append(argv, toComplete) + } + plugin.SetupPluginEnv(settings, md.Name, plug.Dir) + + completion.CompDebugln(fmt.Sprintf("calling %s with args %v", main, argv)) + buf := new(bytes.Buffer) + if err := callPluginExecutable(md.Name, main, argv, buf); err != nil { + // The dynamic completion file is optional for a plugin, so this error is ok. + completion.CompDebugln(fmt.Sprintf("Unable to call %s: %v", main, err.Error())) + return nil, completion.BashCompDirectiveDefault + } + + var completions []string + for _, comp := range strings.Split(buf.String(), "\n") { + // Remove any empty lines + if len(comp) > 0 { + completions = append(completions, comp) + } + } + + // Check if the last line of output is of the form :, which + // indicates the BashCompletionDirective. + directive := completion.BashCompDirectiveDefault + if len(completions) > 0 { + lastLine := completions[len(completions)-1] + if len(lastLine) > 1 && lastLine[0] == ':' { + if strInt, err := strconv.Atoi(lastLine[1:]); err == nil { + directive = completion.BashCompDirective(strInt) + completions = completions[:len(completions)-1] + } + } + } + + return completions, directive +} From e6069769151b91c91a107bd4d79ca3a941658518 Mon Sep 17 00:00:00 2001 From: Maksim Kochkin Date: Fri, 15 May 2020 16:38:55 +0300 Subject: [PATCH 052/159] Add new line to fix code formatting in doc Signed-off-by: Maksim Kochkin --- cmd/helm/install.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 21a41b9f9..44f7336c0 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -60,6 +60,7 @@ or $ helm install --set-string long_int=1234567890 myredis ./redis or + $ helm install --set-file my_script=dothings.sh myredis ./redis You can specify the '--values'/'-f' flag multiple times. The priority will be given to the From 118d46eb3e2c8425ecdbb9c8f8270413060eda78 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Fri, 15 May 2020 12:08:15 -0600 Subject: [PATCH 053/159] feat: Detect missing selector during lint Signed-off-by: Matt Butcher --- pkg/lint/rules/template.go | 14 ++++++ pkg/lint/rules/template_test.go | 81 ++++++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/pkg/lint/rules/template.go b/pkg/lint/rules/template.go index 787c5b26a..0c8e872b7 100644 --- a/pkg/lint/rules/template.go +++ b/pkg/lint/rules/template.go @@ -131,6 +131,7 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace linter.RunLinterRule(support.ErrorSev, path, validateYamlContent(err)) linter.RunLinterRule(support.ErrorSev, path, validateMetadataName(&yamlStruct)) linter.RunLinterRule(support.ErrorSev, path, validateNoDeprecations(&yamlStruct)) + linter.RunLinterRule(support.ErrorSev, path, validateMatchSelector(&yamlStruct, renderedContent)) } } } @@ -185,6 +186,19 @@ func validateNoReleaseTime(manifest []byte) error { return nil } +// validateMatchSelector ensures that template specs have a selector declared. +// See https://github.com/helm/helm/issues/1990 +func validateMatchSelector(yamlStruct *K8sYamlStruct, manifest string) error { + switch yamlStruct.Kind { + case "Deployment", "ReplicaSet", "DaemonSet", "StatefulSet": + // verify that matchLabels or matchExpressions is present + if !(strings.Contains(manifest, "matchLabels") || strings.Contains(manifest, "matchExpressions")) { + return fmt.Errorf("a %s must contain matchLabels or matchExpressions, and %q does not", yamlStruct.Kind, yamlStruct.Metadata.Name) + } + } + return nil +} + // K8sYamlStruct stubs a Kubernetes YAML file. // // DEPRECATED: In Helm 4, this will be made a private type, as it is for use only within diff --git a/pkg/lint/rules/template_test.go b/pkg/lint/rules/template_test.go index 991c6c2f6..ae82c8922 100644 --- a/pkg/lint/rules/template_test.go +++ b/pkg/lint/rules/template_test.go @@ -145,7 +145,7 @@ func TestDeprecatedAPIFails(t *testing.T) { Templates: []*chart.File{ { Name: "templates/baddeployment.yaml", - Data: []byte("apiVersion: apps/v1beta1\nkind: Deployment\nmetadata:\n name: baddep"), + Data: []byte("apiVersion: apps/v1beta1\nkind: Deployment\nmetadata:\n name: baddep\nspec: {selector: {matchLabels: {foo: bar}}}"), }, { Name: "templates/goodsecret.yaml", @@ -226,3 +226,82 @@ func TestStrictTemplateParsingMapError(t *testing.T) { } } } + +func TestValidateMatchSelector(t *testing.T) { + md := &K8sYamlStruct{ + APIVersion: "apps/v1", + Kind: "Deployment", + Metadata: k8sYamlMetadata{ + Name: "mydeployment", + }, + } + manifest := ` + apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ` + if err := validateMatchSelector(md, manifest); err != nil { + t.Error(err) + } + manifest = ` + apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchExpressions: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ` + if err := validateMatchSelector(md, manifest); err != nil { + t.Error(err) + } + manifest = ` + apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ` + if err := validateMatchSelector(md, manifest); err == nil { + t.Error("expected Deployment with no selector to fail") + } +} From 3364265e78274577be049763b54adffb9913d75d Mon Sep 17 00:00:00 2001 From: Adam Reese Date: Fri, 15 May 2020 12:11:18 -0700 Subject: [PATCH 054/159] ref(pkg/chartutil): use minimal in-memory fixtures Signed-off-by: Adam Reese --- pkg/chartutil/coalesce_test.go | 43 +++++++++++++++++- pkg/chartutil/create_test.go | 2 +- .../frobnitz/charts/mariner-4.3.2.tgz | Bin 962 -> 0 bytes .../{ => frobnitz/charts}/mariner/Chart.yaml | 0 .../mariner/charts}/albatross/Chart.yaml | 0 .../mariner/charts}/albatross/values.yaml | 0 .../charts}/mariner/templates/placeholder.tpl | 0 .../{ => frobnitz/charts}/mariner/values.yaml | 0 .../testdata/frobnitz_backslash/.helmignore | 1 - .../testdata/frobnitz_backslash/Chart.lock | 8 ---- .../testdata/frobnitz_backslash/Chart.yaml | 27 ----------- .../testdata/frobnitz_backslash/INSTALL.txt | 1 - .../testdata/frobnitz_backslash/LICENSE | 1 - .../testdata/frobnitz_backslash/README.md | 11 ----- .../frobnitz_backslash/charts/_ignore_me | 1 - .../charts/alpine/Chart.yaml | 5 -- .../charts/alpine/README.md | 9 ---- .../charts/alpine/charts/mast1/Chart.yaml | 5 -- .../charts/alpine/charts/mast1/values.yaml | 4 -- .../charts/alpine/charts/mast2-0.1.0.tgz | Bin 252 -> 0 bytes .../charts/alpine/templates/alpine-pod.yaml | 14 ------ .../charts/alpine/values.yaml | 2 - .../charts/mariner-4.3.2.tgz | Bin 962 -> 0 bytes .../frobnitz_backslash/docs/README.md | 1 - .../testdata/frobnitz_backslash/icon.svg | 8 ---- .../testdata/frobnitz_backslash/ignore/me.txt | 0 .../frobnitz_backslash/templates/template.tpl | 1 - .../testdata/frobnitz_backslash/values.yaml | 6 --- .../mariner/charts/albatross-0.1.0.tgz | Bin 305 -> 0 bytes pkg/chartutil/testdata/moby/Chart.yaml | 4 -- .../testdata/moby/charts/pequod/Chart.yaml | 4 -- .../moby/charts/pequod/charts/ahab/Chart.yaml | 4 -- .../charts/pequod/charts/ahab/values.yaml | 6 --- .../testdata/moby/charts/pequod/values.yaml | 2 - .../testdata/moby/charts/spouter/Chart.yaml | 4 -- .../testdata/moby/charts/spouter/values.yaml | 1 - pkg/chartutil/testdata/moby/values.yaml | 11 ----- 37 files changed, 43 insertions(+), 143 deletions(-) delete mode 100644 pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz rename pkg/chartutil/testdata/{ => frobnitz/charts}/mariner/Chart.yaml (100%) rename pkg/chartutil/testdata/{ => frobnitz/charts/mariner/charts}/albatross/Chart.yaml (100%) rename pkg/chartutil/testdata/{ => frobnitz/charts/mariner/charts}/albatross/values.yaml (100%) rename pkg/chartutil/testdata/{ => frobnitz/charts}/mariner/templates/placeholder.tpl (100%) rename pkg/chartutil/testdata/{ => frobnitz/charts}/mariner/values.yaml (100%) delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/.helmignore delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/Chart.lock delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/Chart.yaml delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/INSTALL.txt delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/LICENSE delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/README.md delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/charts/_ignore_me delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/Chart.yaml delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/README.md delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/charts/mast1/Chart.yaml delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/charts/mast1/values.yaml delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/charts/mast2-0.1.0.tgz delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/templates/alpine-pod.yaml delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/values.yaml delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/charts/mariner-4.3.2.tgz delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/docs/README.md delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/icon.svg delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/ignore/me.txt delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/templates/template.tpl delete mode 100755 pkg/chartutil/testdata/frobnitz_backslash/values.yaml delete mode 100644 pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz delete mode 100644 pkg/chartutil/testdata/moby/Chart.yaml delete mode 100644 pkg/chartutil/testdata/moby/charts/pequod/Chart.yaml delete mode 100644 pkg/chartutil/testdata/moby/charts/pequod/charts/ahab/Chart.yaml delete mode 100644 pkg/chartutil/testdata/moby/charts/pequod/charts/ahab/values.yaml delete mode 100644 pkg/chartutil/testdata/moby/charts/pequod/values.yaml delete mode 100644 pkg/chartutil/testdata/moby/charts/spouter/Chart.yaml delete mode 100644 pkg/chartutil/testdata/moby/charts/spouter/values.yaml delete mode 100644 pkg/chartutil/testdata/moby/values.yaml diff --git a/pkg/chartutil/coalesce_test.go b/pkg/chartutil/coalesce_test.go index 2a3d848fa..5a4656d71 100644 --- a/pkg/chartutil/coalesce_test.go +++ b/pkg/chartutil/coalesce_test.go @@ -21,6 +21,8 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "helm.sh/helm/v3/pkg/chart" ) // ref: http://www.yaml.org/spec/1.2/spec.html#id2803362 @@ -55,9 +57,48 @@ pequod: bar: null `) +func withDeps(c *chart.Chart, deps ...*chart.Chart) *chart.Chart { + c.AddDependency(deps...) + return c +} + func TestCoalesceValues(t *testing.T) { is := assert.New(t) - c := loadChart(t, "testdata/moby") + + c := withDeps(&chart.Chart{ + Metadata: &chart.Metadata{Name: "moby"}, + Values: map[string]interface{}{ + "back": "exists", + "bottom": "exists", + "front": "exists", + "left": "exists", + "name": "moby", + "nested": map[string]interface{}{"boat": true}, + "override": "bad", + "right": "exists", + "scope": "moby", + "top": "nope", + }, + }, + withDeps(&chart.Chart{ + Metadata: &chart.Metadata{Name: "pequod"}, + Values: map[string]interface{}{"name": "pequod", "scope": "pequod"}, + }, + &chart.Chart{ + Metadata: &chart.Metadata{Name: "ahab"}, + Values: map[string]interface{}{ + "scope": "ahab", + "name": "ahab", + "boat": true, + "nested": map[string]interface{}{"foo": false, "bar": true}, + }, + }, + ), + &chart.Chart{ + Metadata: &chart.Metadata{Name: "spouter"}, + Values: map[string]interface{}{"scope": "spouter"}, + }, + ) vals, err := ReadValues(testCoalesceValuesYaml) if err != nil { diff --git a/pkg/chartutil/create_test.go b/pkg/chartutil/create_test.go index d2a3b0a20..a11c45140 100644 --- a/pkg/chartutil/create_test.go +++ b/pkg/chartutil/create_test.go @@ -81,7 +81,7 @@ func TestCreateFrom(t *testing.T) { Name: "foo", Version: "0.1.0", } - srcdir := "./testdata/mariner" + srcdir := "./testdata/frobnitz/charts/mariner" if err := CreateFrom(cf, tdir, srcdir); err != nil { t.Fatal(err) diff --git a/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz b/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz deleted file mode 100644 index 5648f6f6daa6b69765cb792f5926add825926dfc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 962 zcmV;z13mm7iwFRyACz1G1MQbxXcR{rzz+gJ7NkO|K16!MMWkA?*}eTZb5%on8bXs; zTaH9)Ax`e*a*O-b*|}hhHsC|6sZ=bjZ6z;NC>li(eXv3+5jBV+3c(J{0;`~^c-MiWUe|G+#V?eB#2v_+Eh#&|dMFHNZs@^CB!ACg%JQ@AFNsXB}MnCmDYVPVjaYD3sW1UXzsPK3-$e2`08u9QH43b2tGM`lbzPM8Cr z5@Z!Xy$upnd+ zU|nrfVubP<8g>A& zK%0B-I8>fy(#K9Kg+V?Yx%#s`L%@42z;TmS=k^qI5(xu>Q;0PIFV55XpAIpUwDdT_ zJh5jY8%!7fGyzPF{~$d93M~GM!Q|+kYVHx2e>ux{!2iuBzLL?w2J?(Cr*y-$73a2>tSQ$kP|LA{gIn*HE?W5Y zj@_dmb8q&p(t}G#WNgj2CH3gle_U$pZ9TOh^8Oq9`|B4EpT8o0+_e+;eQ;;zVB^N+ z$2txU^Uw7cTl<#JE7?$F5gKYuCv`%?GO@gtx8{{77>Z=Pt`_vw26fW;k4pXkZ( z{vrR!j)!}izo`2$xN@`k-GcJVy=NaioKyW_+2THXY5THyHCt;=jt0lOhS#r-Jn;Rx zw_8j5hi~kyPLIEPH*@Dc zVQyr3R8em|NM&qo0PNJUs=_c72H?(liabH@pWIst-7YSIyL+rhEHrIN(t?QZE=F{y zgNRfS&$pa5Ly`mMk2OB%pV`*9knW7FlL-Joo@KED7*{C$d;N~z z37$S{+}wvSU9}|VtF|fRpv9Ve>8dWo|9?5B+RE}Y9CFh-x#(Bq8Vck^V=NUiPLCKa z8z5CF#JgK!4>;$4Fm+FUst4d+{(+nP|0&J+e}(;l^U4@w-{=?s0RR8vgVbLD3;+OM Cs&R<` diff --git a/pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/templates/alpine-pod.yaml b/pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/templates/alpine-pod.yaml deleted file mode 100755 index 5bbae10af..000000000 --- a/pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/templates/alpine-pod.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: {{.Release.Name}}-{{.Chart.Name}} - labels: - app.kubernetes.io/managed-by: {{.Release.Service}} - chartName: {{.Chart.Name}} - chartVersion: {{.Chart.Version | quote}} -spec: - restartPolicy: {{default "Never" .restart_policy}} - containers: - - name: waiter - image: "alpine:3.3" - command: ["/bin/sleep","9000"] diff --git a/pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/values.yaml b/pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/values.yaml deleted file mode 100755 index 6c2aab7ba..000000000 --- a/pkg/chartutil/testdata/frobnitz_backslash/charts/alpine/values.yaml +++ /dev/null @@ -1,2 +0,0 @@ -# The pod name -name: "my-alpine" diff --git a/pkg/chartutil/testdata/frobnitz_backslash/charts/mariner-4.3.2.tgz b/pkg/chartutil/testdata/frobnitz_backslash/charts/mariner-4.3.2.tgz deleted file mode 100755 index 5648f6f6daa6b69765cb792f5926add825926dfc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 962 zcmV;z13mm7iwFRyACz1G1MQbxXcR{rzz+gJ7NkO|K16!MMWkA?*}eTZb5%on8bXs; zTaH9)Ax`e*a*O-b*|}hhHsC|6sZ=bjZ6z;NC>li(eXv3+5jBV+3c(J{0;`~^c-MiWUe|G+#V?eB#2v_+Eh#&|dMFHNZs@^CB!ACg%JQ@AFNsXB}MnCmDYVPVjaYD3sW1UXzsPK3-$e2`08u9QH43b2tGM`lbzPM8Cr z5@Z!Xy$upnd+ zU|nrfVubP<8g>A& zK%0B-I8>fy(#K9Kg+V?Yx%#s`L%@42z;TmS=k^qI5(xu>Q;0PIFV55XpAIpUwDdT_ zJh5jY8%!7fGyzPF{~$d93M~GM!Q|+kYVHx2e>ux{!2iuBzLL?w2J?(Cr*y-$73a2>tSQ$kP|LA{gIn*HE?W5Y zj@_dmb8q&p(t}G#WNgj2CH3gle_U$pZ9TOh^8Oq9`|B4EpT8o0+_e+;eQ;;zVB^N+ z$2txU^Uw7cTl<#JE7?$F5gKYuCv`%?GO@gtx8{{77>Z=Pt`_vw26fW;k4pXkZ( z{vrR!j)!}izo`2$xN@`k-GcJVy=NaioKyW_+2THXY5THyHCt;=jt0lOhS#r-Jn;Rx zw_8j5hi~kyPLIEPH*@ - - Example icon - - - diff --git a/pkg/chartutil/testdata/frobnitz_backslash/ignore/me.txt b/pkg/chartutil/testdata/frobnitz_backslash/ignore/me.txt deleted file mode 100755 index e69de29bb..000000000 diff --git a/pkg/chartutil/testdata/frobnitz_backslash/templates/template.tpl b/pkg/chartutil/testdata/frobnitz_backslash/templates/template.tpl deleted file mode 100755 index c651ee6a0..000000000 --- a/pkg/chartutil/testdata/frobnitz_backslash/templates/template.tpl +++ /dev/null @@ -1 +0,0 @@ -Hello {{.Name | default "world"}} diff --git a/pkg/chartutil/testdata/frobnitz_backslash/values.yaml b/pkg/chartutil/testdata/frobnitz_backslash/values.yaml deleted file mode 100755 index 61f501258..000000000 --- a/pkg/chartutil/testdata/frobnitz_backslash/values.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# A values file contains configuration. - -name: "Some Name" - -section: - name: "Name in a section" diff --git a/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz b/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz deleted file mode 100644 index 22c1fe57251c27c11d6e6b5c518fc998d62d5bfd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 305 zcmV-10nYv(iwFRyACz1G1MSpHZo)7S24L1c#fSq?8*C$GSFx$oefI_?B$A1d?I88` z4UYz?Ds)5oQ2%c;iflRK%uJkLx*S7F52L|IDd)z}F4@aL6Zy=4um7%o;h5^s6tq{Oaa%5^Zwj&Iw2JjEAJ-r0iT##Vhen|? zM0#$Q92?G@#QyydIZ+cSs&F`GJQhEFKe+8O|9j_KPDA_vzM6k&<{#(ZnmOkGJM{JM zrZvZw$3kp;SUO(_BG=|B#DW&VbF9}J#yA520000000000000000Q^R8xfQyO04M+e DGPIJ| diff --git a/pkg/chartutil/testdata/moby/Chart.yaml b/pkg/chartutil/testdata/moby/Chart.yaml deleted file mode 100644 index a5f992c61..000000000 --- a/pkg/chartutil/testdata/moby/Chart.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -description: A Helm chart for Kubernetes -name: moby -version: 0.1.0 diff --git a/pkg/chartutil/testdata/moby/charts/pequod/Chart.yaml b/pkg/chartutil/testdata/moby/charts/pequod/Chart.yaml deleted file mode 100644 index f1a8ef76b..000000000 --- a/pkg/chartutil/testdata/moby/charts/pequod/Chart.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -description: A Helm chart for Kubernetes -name: pequod -version: 0.1.0 diff --git a/pkg/chartutil/testdata/moby/charts/pequod/charts/ahab/Chart.yaml b/pkg/chartutil/testdata/moby/charts/pequod/charts/ahab/Chart.yaml deleted file mode 100644 index a7ee7bf90..000000000 --- a/pkg/chartutil/testdata/moby/charts/pequod/charts/ahab/Chart.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -description: A Helm chart for Kubernetes -name: ahab -version: 0.1.0 diff --git a/pkg/chartutil/testdata/moby/charts/pequod/charts/ahab/values.yaml b/pkg/chartutil/testdata/moby/charts/pequod/charts/ahab/values.yaml deleted file mode 100644 index eee6980fa..000000000 --- a/pkg/chartutil/testdata/moby/charts/pequod/charts/ahab/values.yaml +++ /dev/null @@ -1,6 +0,0 @@ -scope: ahab -name: ahab -boat: true -nested: - foo: false - bar: true diff --git a/pkg/chartutil/testdata/moby/charts/pequod/values.yaml b/pkg/chartutil/testdata/moby/charts/pequod/values.yaml deleted file mode 100644 index d6e34b274..000000000 --- a/pkg/chartutil/testdata/moby/charts/pequod/values.yaml +++ /dev/null @@ -1,2 +0,0 @@ -scope: pequod -name: pequod diff --git a/pkg/chartutil/testdata/moby/charts/spouter/Chart.yaml b/pkg/chartutil/testdata/moby/charts/spouter/Chart.yaml deleted file mode 100644 index 0525085b6..000000000 --- a/pkg/chartutil/testdata/moby/charts/spouter/Chart.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -description: A Helm chart for Kubernetes -name: spouter -version: 0.1.0 diff --git a/pkg/chartutil/testdata/moby/charts/spouter/values.yaml b/pkg/chartutil/testdata/moby/charts/spouter/values.yaml deleted file mode 100644 index f71d92a9f..000000000 --- a/pkg/chartutil/testdata/moby/charts/spouter/values.yaml +++ /dev/null @@ -1 +0,0 @@ -scope: spouter diff --git a/pkg/chartutil/testdata/moby/values.yaml b/pkg/chartutil/testdata/moby/values.yaml deleted file mode 100644 index 2169d7566..000000000 --- a/pkg/chartutil/testdata/moby/values.yaml +++ /dev/null @@ -1,11 +0,0 @@ -scope: moby -name: moby -override: bad -top: nope -bottom: exists -right: exists -left: exists -front: exists -back: exists -nested: - boat: true From bade6478fcdd537957f0ce8a2cc5e06a14940ea0 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Fri, 15 May 2020 13:23:10 -0400 Subject: [PATCH 055/159] Fixing error with strvals parsing Closes #8140 Signed-off-by: Matt Farina --- pkg/strvals/parser.go | 30 +++++++++++++++++++++------- pkg/strvals/parser_test.go | 41 +++++++++++++++++++++++++++++++++++--- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go index 03adbd3cb..db2fb60fe 100644 --- a/pkg/strvals/parser.go +++ b/pkg/strvals/parser.go @@ -17,6 +17,7 @@ package strvals import ( "bytes" + "fmt" "io" "strconv" "strings" @@ -230,14 +231,17 @@ func set(data map[string]interface{}, key string, val interface{}) { data[key] = val } -func setIndex(list []interface{}, index int, val interface{}) []interface{} { +func setIndex(list []interface{}, index int, val interface{}) ([]interface{}, error) { + if index < 0 { + return list, fmt.Errorf("negative %d index not allowed", index) + } if len(list) <= index { newlist := make([]interface{}, index+1) copy(newlist, list) list = newlist } list[index] = val - return list + return list, nil } func (t *parser) keyIndex() (int, error) { @@ -252,6 +256,9 @@ func (t *parser) keyIndex() (int, error) { } func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) { + if i < 0 { + return list, fmt.Errorf("negative %d index not allowed", i) + } stop := runeSet([]rune{'[', '.', '='}) switch k, last, err := runesUntil(t.sc, stop); { case len(k) > 0: @@ -262,16 +269,19 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) { vl, e := t.valList() switch e { case nil: - return setIndex(list, i, vl), nil + return setIndex(list, i, vl) case io.EOF: - return setIndex(list, i, ""), err + return setIndex(list, i, "") case ErrNotList: rs, e := t.val() if e != nil && e != io.EOF { return list, e } v, e := t.reader(rs) - return setIndex(list, i, v), e + if e != nil { + return list, e + } + return setIndex(list, i, v) default: return list, e } @@ -283,7 +293,10 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) { } // Now we need to get the value after the ]. list2, err := t.listItem(list, i) - return setIndex(list, i, list2), err + if err != nil { + return list, err + } + return setIndex(list, i, list2) case last == '.': // We have a nested object. Send to t.key inner := map[string]interface{}{} @@ -299,7 +312,10 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) { // Recurse e := t.key(inner) - return setIndex(list, i, inner), e + if e != nil { + return list, e + } + return setIndex(list, i, inner) default: return nil, errors.Errorf("parse error: unexpected token %v", last) } diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go index 44d317220..fb18980cf 100644 --- a/pkg/strvals/parser_test.go +++ b/pkg/strvals/parser_test.go @@ -28,6 +28,7 @@ func TestSetIndex(t *testing.T) { expect []interface{} add int val int + err bool }{ { name: "short", @@ -35,6 +36,7 @@ func TestSetIndex(t *testing.T) { expect: []interface{}{0, 1, 2}, add: 2, val: 2, + err: false, }, { name: "equal", @@ -42,6 +44,7 @@ func TestSetIndex(t *testing.T) { expect: []interface{}{0, 2}, add: 1, val: 2, + err: false, }, { name: "long", @@ -49,17 +52,41 @@ func TestSetIndex(t *testing.T) { expect: []interface{}{0, 1, 2, 4, 4, 5}, add: 3, val: 4, + err: false, + }, + { + name: "negative", + initial: []interface{}{0, 1, 2, 3, 4, 5}, + expect: []interface{}{0, 1, 2, 3, 4, 5}, + add: -1, + val: 4, + err: true, }, } for _, tt := range tests { - got := setIndex(tt.initial, tt.add, tt.val) + got, err := setIndex(tt.initial, tt.add, tt.val) + + if err != nil && tt.err == false { + t.Fatalf("%s: Expected no error but error returned", tt.name) + } else if err == nil && tt.err == true { + t.Fatalf("%s: Expected error but no error returned", tt.name) + } + if len(got) != len(tt.expect) { t.Fatalf("%s: Expected length %d, got %d", tt.name, len(tt.expect), len(got)) } - if gg := got[tt.add].(int); gg != tt.val { - t.Errorf("%s, Expected value %d, got %d", tt.name, tt.val, gg) + if !tt.err { + if gg := got[tt.add].(int); gg != tt.val { + t.Errorf("%s, Expected value %d, got %d", tt.name, tt.val, gg) + } + } + + for k, v := range got { + if v != tt.expect[k] { + t.Errorf("%s, Expected value %d, got %d", tt.name, tt.expect[k], v) + } } } } @@ -271,6 +298,10 @@ func TestParseSet(t *testing.T) { }, }, }, + { + str: "list[0].foo=bar,list[-30].hello=world", + err: true, + }, { str: "list[0]=foo,list[1]=bar", expect: map[string]interface{}{"list": []string{"foo", "bar"}}, @@ -283,6 +314,10 @@ func TestParseSet(t *testing.T) { str: "list[0]=foo,list[3]=bar", expect: map[string]interface{}{"list": []interface{}{"foo", nil, nil, "bar"}}, }, + { + str: "list[0]=foo,list[-20]=bar", + err: true, + }, { str: "illegal[0]name.foo=bar", err: true, From 8f1f0e0db2d96fa3d85c8b7a8e461f6bec7bced9 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Fri, 15 May 2020 16:00:57 -0400 Subject: [PATCH 056/159] Recovering from panic that can occur with make Signed-off-by: Matt Farina --- pkg/strvals/parser.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go index db2fb60fe..c52f38ab1 100644 --- a/pkg/strvals/parser.go +++ b/pkg/strvals/parser.go @@ -231,7 +231,16 @@ func set(data map[string]interface{}, key string, val interface{}) { data[key] = val } -func setIndex(list []interface{}, index int, val interface{}) ([]interface{}, error) { +func setIndex(list []interface{}, index int, val interface{}) (l2 []interface{}, err error) { + // There are possible index values that are out of range on a target system + // causing a panic. This will catch the panic and return an error instead. + // The value of the index that causes a panic varies from system to system. + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("error processing index %d: %s", index, r) + } + }() + if index < 0 { return list, fmt.Errorf("negative %d index not allowed", index) } From 6857da251edd416454827ac692c85de1ade6b5e6 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Fri, 15 May 2020 16:52:04 -0400 Subject: [PATCH 057/159] Catching a potential panic in strval parsing Signed-off-by: Matt Farina --- pkg/strvals/parser.go | 7 ++++++- pkg/strvals/parser_test.go | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go index c52f38ab1..c735412e9 100644 --- a/pkg/strvals/parser.go +++ b/pkg/strvals/parser.go @@ -150,7 +150,12 @@ func runeSet(r []rune) map[rune]bool { return s } -func (t *parser) key(data map[string]interface{}) error { +func (t *parser) key(data map[string]interface{}) (reterr error) { + defer func() { + if r := recover(); r != nil { + reterr = fmt.Errorf("unable to parse key: %s", r) + } + }() stop := runeSet([]rune{'=', '[', ',', '.'}) for { switch k, last, err := runesUntil(t.sc, stop); { diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go index fb18980cf..742256153 100644 --- a/pkg/strvals/parser_test.go +++ b/pkg/strvals/parser_test.go @@ -362,6 +362,10 @@ func TestParseSet(t *testing.T) { }, }, }, + { + str: "]={}].", + err: true, + }, } for _, tt := range tests { From 1a46c3495ab2aa101e31fe9dfbe10802bb7d0a63 Mon Sep 17 00:00:00 2001 From: Alan Zhu Date: Mon, 18 May 2020 09:25:19 +0800 Subject: [PATCH 058/159] Revert "group command for easy read" Signed-off-by: Alan Zhu --- cmd/helm/root.go | 63 ++++++++++++++++++------------------------------ 1 file changed, 23 insertions(+), 40 deletions(-) diff --git a/cmd/helm/root.go b/cmd/helm/root.go index ff4a01ad7..143745f29 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -26,7 +26,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/clientcmd" - "k8s.io/kubectl/pkg/util/templates" "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/internal/experimental/registry" @@ -133,47 +132,31 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string flags.ParseErrorsWhitelist.UnknownFlags = true flags.Parse(args) - commandGroups := templates.CommandGroups{ - { - Message: "Release Management Commands:", - Commands: []*cobra.Command{ - newInstallCmd(actionConfig, out), - newListCmd(actionConfig, out), - newGetCmd(actionConfig, out), - newStatusCmd(actionConfig, out), - newUpgradeCmd(actionConfig, out), - newHistoryCmd(actionConfig, out), - newRollbackCmd(actionConfig, out), - newReleaseTestCmd(actionConfig, out), - newUninstallCmd(actionConfig, out), - }, - }, - { - Message: "Chart Commands:", - Commands: []*cobra.Command{ - newCreateCmd(out), - newDependencyCmd(out), - newPackageCmd(out), - newTemplateCmd(actionConfig, out), - newLintCmd(out), - newVerifyCmd(out), - }, - }, - { - Message: "Chart Repository Commands:", - Commands: []*cobra.Command{ - newRepoCmd(out), - newSearchCmd(out), - newPullCmd(out), - newShowCmd(out), - }, - }, - } - commandGroups.Add(cmd) - templates.ActsAsRootCommand(cmd, []string{"options"}, commandGroups...) - // Add subcommands cmd.AddCommand( + // chart commands + newCreateCmd(out), + newDependencyCmd(out), + newPullCmd(out), + newShowCmd(out), + newLintCmd(out), + newPackageCmd(out), + newRepoCmd(out), + newSearchCmd(out), + newVerifyCmd(out), + + // release commands + newGetCmd(actionConfig, out), + newHistoryCmd(actionConfig, out), + newInstallCmd(actionConfig, out), + newListCmd(actionConfig, out), + newReleaseTestCmd(actionConfig, out), + newRollbackCmd(actionConfig, out), + newStatusCmd(actionConfig, out), + newTemplateCmd(actionConfig, out), + newUninstallCmd(actionConfig, out), + newUpgradeCmd(actionConfig, out), + newCompletionCmd(out), newEnvCmd(out), newPluginCmd(out), From 5840e529e143d3f63539a312b81848f0b25ff6ba Mon Sep 17 00:00:00 2001 From: Thomas O'Donnell Date: Mon, 18 May 2020 16:40:40 +0200 Subject: [PATCH 059/159] Update the Helm version docs Have just updated the helm version docs to include the GoVersion field. Signed-off-by: Thomas O'Donnell --- cmd/helm/version.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/helm/version.go b/cmd/helm/version.go index b3f831e07..2f50c876c 100644 --- a/cmd/helm/version.go +++ b/cmd/helm/version.go @@ -33,12 +33,13 @@ Show the version for Helm. This will print a representation the version of Helm. The output will look something like this: -version.BuildInfo{Version:"v2.0.0", GitCommit:"ff52399e51bb880526e9cd0ed8386f6433b74da1", GitTreeState:"clean"} +version.BuildInfo{Version:"v3.2.1", GitCommit:"fe51cd1e31e6a202cba7dead9552a6d418ded79a", GitTreeState:"clean", GoVersion:"go1.13.10"} - Version is the semantic version of the release. - GitCommit is the SHA for the commit that this version was built from. - GitTreeState is "clean" if there are no local code changes when this binary was built, and "dirty" if the binary was built from locally modified code. +- GoVersion is the version of Go that was used to compile Helm. When using the --template flag the following properties are available to use in the template: From 2ae83f276b60085c550fc81fb6e21b38146e2d9f Mon Sep 17 00:00:00 2001 From: Martin Hickey Date: Mon, 18 May 2020 18:06:09 +0000 Subject: [PATCH 060/159] Fix repo cache setting Fix `repo add` and `repo update` to use a repository cache set using `--repository-cache` flag Signed-off-by: Martin Hickey Signed-off-by: Trond Hindenes --- cmd/helm/repo_add.go | 3 +++ cmd/helm/repo_update.go | 9 +++++++-- cmd/helm/repo_update_test.go | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/cmd/helm/repo_add.go b/cmd/helm/repo_add.go index 3d36fd0ed..9c67641e5 100644 --- a/cmd/helm/repo_add.go +++ b/cmd/helm/repo_add.go @@ -130,6 +130,9 @@ func (o *repoAddOptions) run(out io.Writer) error { return err } + if o.repoCache != "" { + r.CachePath = o.repoCache + } if _, err := r.DownloadIndexFile(); err != nil { return errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", o.url) } diff --git a/cmd/helm/repo_update.go b/cmd/helm/repo_update.go index 027f18518..5c1086e81 100644 --- a/cmd/helm/repo_update.go +++ b/cmd/helm/repo_update.go @@ -37,8 +37,9 @@ Information is cached locally, where it is used by commands like 'helm search'. var errNoRepositories = errors.New("no repositories found. You must add one before updating") type repoUpdateOptions struct { - update func([]*repo.ChartRepository, io.Writer) - repoFile string + update func([]*repo.ChartRepository, io.Writer) + repoFile string + repoCache string } func newRepoUpdateCmd(out io.Writer) *cobra.Command { @@ -52,6 +53,7 @@ func newRepoUpdateCmd(out io.Writer) *cobra.Command { Args: require.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { o.repoFile = settings.RepositoryConfig + o.repoCache = settings.RepositoryCache return o.run(out) }, } @@ -69,6 +71,9 @@ func (o *repoUpdateOptions) run(out io.Writer) error { if err != nil { return err } + if o.repoCache != "" { + r.CachePath = o.repoCache + } repos = append(repos, r) } diff --git a/cmd/helm/repo_update_test.go b/cmd/helm/repo_update_test.go index 6ddce0637..b13d575e2 100644 --- a/cmd/helm/repo_update_test.go +++ b/cmd/helm/repo_update_test.go @@ -19,6 +19,8 @@ import ( "bytes" "fmt" "io" + "io/ioutil" + "path/filepath" "strings" "testing" @@ -79,3 +81,34 @@ func TestUpdateCharts(t *testing.T) { t.Error("Update was not successful") } } + +func TestUpdateChartsCustomCache(t *testing.T) { + defer resetEnv()() + defer ensure.HelmHome(t)() + + ts, err := repotest.NewTempServer("testdata/testserver/*.*") + if err != nil { + t.Fatal(err) + } + defer ts.Stop() + + r, err := repo.NewChartRepository(&repo.Entry{ + Name: "charts", + URL: ts.URL(), + }, getter.All(settings)) + if err != nil { + t.Error(err) + } + + cachePath := ensure.TempDir(t) + cacheFile := filepath.Join(cachePath, "charts-index.yaml") + r.CachePath = cachePath + + b := bytes.NewBuffer(nil) + updateCharts([]*repo.ChartRepository{r}, b) + + _, err = ioutil.ReadFile(cacheFile) + if err != nil { + t.Error(err) + } +} From 5600a2c82d236422e54b6089d5384dea44349900 Mon Sep 17 00:00:00 2001 From: Martin Hickey Date: Tue, 19 May 2020 15:45:14 +0000 Subject: [PATCH 061/159] Fix unit test Signed-off-by: Martin Hickey --- cmd/helm/repo_update_test.go | 52 ++++++++++++++---------------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/cmd/helm/repo_update_test.go b/cmd/helm/repo_update_test.go index b13d575e2..981f0bba3 100644 --- a/cmd/helm/repo_update_test.go +++ b/cmd/helm/repo_update_test.go @@ -19,7 +19,7 @@ import ( "bytes" "fmt" "io" - "io/ioutil" + "os" "path/filepath" "strings" "testing" @@ -52,6 +52,25 @@ func TestUpdateCmd(t *testing.T) { } } +func TestUpdateCustomCacheCmd(t *testing.T) { + var out bytes.Buffer + rootDir := ensure.TempDir(t) + cachePath := filepath.Join(rootDir, "updcustomcache") + _ = os.Mkdir(cachePath, os.ModePerm) + defer os.RemoveAll(cachePath) + o := &repoUpdateOptions{ + update: updateCharts, + repoFile: "testdata/repositories.yaml", + repoCache: cachePath, + } + if err := o.run(&out); err != nil { + t.Fatal(err) + } + if _, err := os.Stat(filepath.Join(cachePath, "charts-index.yaml")); err != nil { + t.Fatalf("error finding created index file in custom cache: %#v", err) + } +} + func TestUpdateCharts(t *testing.T) { defer resetEnv()() defer ensure.HelmHome(t)() @@ -81,34 +100,3 @@ func TestUpdateCharts(t *testing.T) { t.Error("Update was not successful") } } - -func TestUpdateChartsCustomCache(t *testing.T) { - defer resetEnv()() - defer ensure.HelmHome(t)() - - ts, err := repotest.NewTempServer("testdata/testserver/*.*") - if err != nil { - t.Fatal(err) - } - defer ts.Stop() - - r, err := repo.NewChartRepository(&repo.Entry{ - Name: "charts", - URL: ts.URL(), - }, getter.All(settings)) - if err != nil { - t.Error(err) - } - - cachePath := ensure.TempDir(t) - cacheFile := filepath.Join(cachePath, "charts-index.yaml") - r.CachePath = cachePath - - b := bytes.NewBuffer(nil) - updateCharts([]*repo.ChartRepository{r}, b) - - _, err = ioutil.ReadFile(cacheFile) - if err != nil { - t.Error(err) - } -} From 146e0f9cc3b9c7ca9cb9dd0eba12de2270ae6faf Mon Sep 17 00:00:00 2001 From: hzliangbin Date: Thu, 21 May 2020 18:00:16 +0800 Subject: [PATCH 062/159] add kind_sorter support for SecretList Signed-off-by: Bin Liang --- pkg/releaseutil/kind_sorter.go | 2 ++ pkg/releaseutil/kind_sorter_test.go | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pkg/releaseutil/kind_sorter.go b/pkg/releaseutil/kind_sorter.go index 5b131b3b0..a340dfc29 100644 --- a/pkg/releaseutil/kind_sorter.go +++ b/pkg/releaseutil/kind_sorter.go @@ -37,6 +37,7 @@ var InstallOrder KindSortOrder = []string{ "PodDisruptionBudget", "ServiceAccount", "Secret", + "SecretList", "ConfigMap", "StorageClass", "PersistentVolume", @@ -93,6 +94,7 @@ var UninstallOrder KindSortOrder = []string{ "PersistentVolume", "StorageClass", "ConfigMap", + "SecretList", "Secret", "ServiceAccount", "PodDisruptionBudget", diff --git a/pkg/releaseutil/kind_sorter_test.go b/pkg/releaseutil/kind_sorter_test.go index 341f528a0..71d355210 100644 --- a/pkg/releaseutil/kind_sorter_test.go +++ b/pkg/releaseutil/kind_sorter_test.go @@ -25,6 +25,10 @@ import ( func TestKindSorter(t *testing.T) { manifests := []Manifest{ + { + Name: "E", + Head: &SimpleHead{Kind: "SecretList"}, + }, { Name: "i", Head: &SimpleHead{Kind: "ClusterRole"}, @@ -168,8 +172,8 @@ func TestKindSorter(t *testing.T) { order KindSortOrder expected string }{ - {"install", InstallOrder, "aAbcC3def1gh2iIjJkKlLmnopqrxstuvw!"}, - {"uninstall", UninstallOrder, "wvmutsxrqponLlKkJjIi2hg1fed3CcbAa!"}, + {"install", InstallOrder, "aAbcC3deEf1gh2iIjJkKlLmnopqrxstuvw!"}, + {"uninstall", UninstallOrder, "wvmutsxrqponLlKkJjIi2hg1fEed3CcbAa!"}, } { var buf bytes.Buffer t.Run(test.description, func(t *testing.T) { From 6d49f562bce78c6459f11e82ea8d37e12edb8590 Mon Sep 17 00:00:00 2001 From: vitt-bagal <31851690+vitt-bagal@users.noreply.github.com> Date: Wed, 20 May 2020 19:00:17 +0530 Subject: [PATCH 063/159] Added s390x support Signed-off-by: vitthalb@us.ibm.com --- scripts/get-helm-3 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/get-helm-3 b/scripts/get-helm-3 index 1d0b3502e..22a93aa0e 100755 --- a/scripts/get-helm-3 +++ b/scripts/get-helm-3 @@ -33,6 +33,7 @@ initArch() { x86_64) ARCH="amd64";; i686) ARCH="386";; i386) ARCH="386";; + s390x) ARCH="s390x";; esac } @@ -60,7 +61,7 @@ runAsRoot() { # verifySupported checks that the os/arch combination is supported for # binary builds. verifySupported() { - local supported="darwin-386\ndarwin-amd64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-ppc64le\nwindows-386\nwindows-amd64" + local supported="darwin-386\ndarwin-amd64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-ppc64le\nlinux-s390x\nwindows-386\nwindows-amd64" if ! echo "${supported}" | grep -q "${OS}-${ARCH}"; then echo "No prebuilt binary for ${OS}-${ARCH}." echo "To build from source, go to https://github.com/helm/helm" From dbd001e5326561076e17a62b41ea3a9aa18e069d Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Thu, 21 May 2020 15:26:16 -0400 Subject: [PATCH 064/159] Removing tiller language Since Tiller is no longer part of Helm v3, internal documentation language about Tiller can be removed Signed-off-by: Matt Farina --- pkg/engine/doc.go | 8 ++++---- pkg/engine/engine.go | 2 +- pkg/kube/client.go | 2 +- pkg/lint/rules/template.go | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/engine/doc.go b/pkg/engine/doc.go index a68b6f7af..6ff875c46 100644 --- a/pkg/engine/doc.go +++ b/pkg/engine/doc.go @@ -14,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -/*Package engine implements the Go template engine as a Tiller Engine. +/*Package engine implements the Go text template engine as needed for Helm. -Tiller provides a simple interface for taking a Chart and rendering its templates. -The 'engine' package implements this interface using Go's built-in 'text/template' -package. +When Helm renders templates it does so with additional functions and different +modes (e.g., strict, lint mode). This package handles the helm specific +implementation. */ package engine // import "helm.sh/helm/v3/pkg/engine" diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index c5d064ad5..5aa0ed8ec 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -33,7 +33,7 @@ import ( "helm.sh/helm/v3/pkg/chartutil" ) -// Engine is an implementation of 'cmd/tiller/environment'.Engine that uses Go templates. +// Engine is an implementation of the Helm rendering implementation for templates. type Engine struct { // If strict is enabled, template rendering will fail if a template references // a value that was not passed in. diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 4683d8033..f908611db 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -434,7 +434,7 @@ func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, if patch == nil || string(patch) == "{}" { c.Log("Looks like there are no changes for %s %q", target.Mapping.GroupVersionKind.Kind, target.Name) - // This needs to happen to make sure that tiller has the latest info from the API + // This needs to happen to make sure that Helm has the latest info from the API // Otherwise there will be no labels and other functions that use labels will panic if err := target.Get(); err != nil { return errors.Wrap(err, "failed to refresh resource information") diff --git a/pkg/lint/rules/template.go b/pkg/lint/rules/template.go index 787c5b26a..cf8b4f84b 100644 --- a/pkg/lint/rules/template.go +++ b/pkg/lint/rules/template.go @@ -57,7 +57,7 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace return } - // Load chart and parse templates, based on tiller/release_server + // Load chart and parse templates chart, err := loader.Load(linter.ChartDir) chartLoaded := linter.RunLinterRule(support.ErrorSev, path, err) From 99f277a2f3de395160b473ac7a8cae6c380b6d1c Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Fri, 22 May 2020 09:51:48 -0400 Subject: [PATCH 065/159] Using flags instead of persistent flags on status Persistent flags are available on subcommands. Status does not need the persistent nature. Closes #8149 Signed-off-by: Matt Farina --- cmd/helm/status.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/status.go b/cmd/helm/status.go index 6313b3975..2efb2006c 100644 --- a/cmd/helm/status.go +++ b/cmd/helm/status.go @@ -74,7 +74,7 @@ func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { return compListReleases(toComplete, cfg) }) - f := cmd.PersistentFlags() + f := cmd.Flags() f.IntVar(&client.Version, "revision", 0, "if set, display the status of the named release with revision") flag := f.Lookup("revision") From c56778a8d8c7fe3237bb38f6019d7003d85603d0 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Fri, 22 May 2020 11:43:32 -0400 Subject: [PATCH 066/159] Removing legacy completions.bash file This file was previously used for shell completions but is no longer in use as there is a new completions system in place and there has been for some time. The contents of this file were out of date and reflect Helm v2. Closes #8186 Signed-off-by: Matt Farina --- scripts/completions.bash | 1632 -------------------------------------- 1 file changed, 1632 deletions(-) delete mode 100644 scripts/completions.bash diff --git a/scripts/completions.bash b/scripts/completions.bash deleted file mode 100644 index 027cc3322..000000000 --- a/scripts/completions.bash +++ /dev/null @@ -1,1632 +0,0 @@ -# bash completion for helm -*- shell-script -*- - -__debug() -{ - if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then - echo "$*" >> "${BASH_COMP_DEBUG_FILE}" - fi -} - -# Homebrew on Macs have version 1.3 of bash-completion which doesn't include -# _init_completion. This is a very minimal version of that function. -__my_init_completion() -{ - COMPREPLY=() - _get_comp_words_by_ref "$@" cur prev words cword -} - -__index_of_word() -{ - local w word=$1 - shift - index=0 - for w in "$@"; do - [[ $w = "$word" ]] && return - index=$((index+1)) - done - index=-1 -} - -__contains_word() -{ - local w word=$1; shift - for w in "$@"; do - [[ $w = "$word" ]] && return - done - return 1 -} - -__handle_reply() -{ - __debug "${FUNCNAME[0]}" - case $cur in - -*) - if [[ $(type -t compopt) = "builtin" ]]; then - compopt -o nospace - fi - local allflags - if [ ${#must_have_one_flag[@]} -ne 0 ]; then - allflags=("${must_have_one_flag[@]}") - else - allflags=("${flags[*]} ${two_word_flags[*]}") - fi - COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") ) - if [[ $(type -t compopt) = "builtin" ]]; then - [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace - fi - - # complete after --flag=abc - if [[ $cur == *=* ]]; then - if [[ $(type -t compopt) = "builtin" ]]; then - compopt +o nospace - fi - - local index flag - flag="${cur%%=*}" - __index_of_word "${flag}" "${flags_with_completion[@]}" - if [[ ${index} -ge 0 ]]; then - COMPREPLY=() - PREFIX="" - cur="${cur#*=}" - ${flags_completion[${index}]} - if [ -n "${ZSH_VERSION}" ]; then - # zfs completion needs --flag= prefix - eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )" - fi - fi - fi - return 0; - ;; - esac - - # check if we are handling a flag with special work handling - local index - __index_of_word "${prev}" "${flags_with_completion[@]}" - if [[ ${index} -ge 0 ]]; then - ${flags_completion[${index}]} - return - fi - - # we are parsing a flag and don't have a special handler, no completion - if [[ ${cur} != "${words[cword]}" ]]; then - return - fi - - local completions - completions=("${commands[@]}") - if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then - completions=("${must_have_one_noun[@]}") - fi - if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then - completions+=("${must_have_one_flag[@]}") - fi - COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") ) - - if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then - COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") ) - fi - - if [[ ${#COMPREPLY[@]} -eq 0 ]]; then - declare -F __custom_func >/dev/null && __custom_func - fi - - __ltrim_colon_completions "$cur" -} - -# The arguments should be in the form "ext1|ext2|extn" -__handle_filename_extension_flag() -{ - local ext="$1" - _filedir "@(${ext})" -} - -__handle_subdirs_in_dir_flag() -{ - local dir="$1" - pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 -} - -__handle_flag() -{ - __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" - - # if a command required a flag, and we found it, unset must_have_one_flag() - local flagname=${words[c]} - local flagvalue - # if the word contained an = - if [[ ${words[c]} == *"="* ]]; then - flagvalue=${flagname#*=} # take in as flagvalue after the = - flagname=${flagname%%=*} # strip everything after the = - flagname="${flagname}=" # but put the = back - fi - __debug "${FUNCNAME[0]}: looking for ${flagname}" - if __contains_word "${flagname}" "${must_have_one_flag[@]}"; then - must_have_one_flag=() - fi - - # if you set a flag which only applies to this command, don't show subcommands - if __contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then - commands=() - fi - - # keep flag value with flagname as flaghash - if [ -n "${flagvalue}" ] ; then - flaghash[${flagname}]=${flagvalue} - elif [ -n "${words[ $((c+1)) ]}" ] ; then - flaghash[${flagname}]=${words[ $((c+1)) ]} - else - flaghash[${flagname}]="true" # pad "true" for bool flag - fi - - # skip the argument to a two word flag - if __contains_word "${words[c]}" "${two_word_flags[@]}"; then - c=$((c+1)) - # if we are looking for a flags value, don't show commands - if [[ $c -eq $cword ]]; then - commands=() - fi - fi - - c=$((c+1)) - -} - -__handle_noun() -{ - __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" - - if __contains_word "${words[c]}" "${must_have_one_noun[@]}"; then - must_have_one_noun=() - elif __contains_word "${words[c]}" "${noun_aliases[@]}"; then - must_have_one_noun=() - fi - - nouns+=("${words[c]}") - c=$((c+1)) -} - -__handle_command() -{ - __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" - - local next_command - if [[ -n ${last_command} ]]; then - next_command="_${last_command}_${words[c]//:/__}" - else - if [[ $c -eq 0 ]]; then - next_command="_$(basename "${words[c]//:/__}")" - else - next_command="_${words[c]//:/__}" - fi - fi - c=$((c+1)) - __debug "${FUNCNAME[0]}: looking for ${next_command}" - declare -F $next_command >/dev/null && $next_command -} - -__handle_word() -{ - if [[ $c -ge $cword ]]; then - __handle_reply - return - fi - __debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" - if [[ "${words[c]}" == -* ]]; then - __handle_flag - elif __contains_word "${words[c]}" "${commands[@]}"; then - __handle_command - elif [[ $c -eq 0 ]] && __contains_word "$(basename "${words[c]}")" "${commands[@]}"; then - __handle_command - else - __handle_noun - fi - __handle_word -} - -_helm_completion() -{ - last_command="helm_completion" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - must_have_one_noun+=("bash") - must_have_one_noun+=("zsh") - noun_aliases=() -} - -_helm_create() -{ - last_command="helm_create" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--starter=") - two_word_flags+=("-p") - local_nonpersistent_flags+=("--starter=") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_delete() -{ - last_command="helm_delete" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--dry-run") - local_nonpersistent_flags+=("--dry-run") - flags+=("--no-hooks") - local_nonpersistent_flags+=("--no-hooks") - flags+=("--keep-history") - local_nonpersistent_flags+=("--keep-history") - flags+=("--timeout=") - local_nonpersistent_flags+=("--timeout=") - flags+=("--tls") - local_nonpersistent_flags+=("--tls") - flags+=("--tls-ca-cert=") - local_nonpersistent_flags+=("--tls-ca-cert=") - flags+=("--tls-cert=") - local_nonpersistent_flags+=("--tls-cert=") - flags+=("--tls-key=") - local_nonpersistent_flags+=("--tls-key=") - flags+=("--tls-verify") - local_nonpersistent_flags+=("--tls-verify") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_dependency_build() -{ - last_command="helm_dependency_build" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--keyring=") - local_nonpersistent_flags+=("--keyring=") - flags+=("--verify") - local_nonpersistent_flags+=("--verify") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_dependency_list() -{ - last_command="helm_dependency_list" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_dependency_update() -{ - last_command="helm_dependency_update" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--keyring=") - local_nonpersistent_flags+=("--keyring=") - flags+=("--skip-refresh") - local_nonpersistent_flags+=("--skip-refresh") - flags+=("--verify") - local_nonpersistent_flags+=("--verify") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_dependency() -{ - last_command="helm_dependency" - commands=() - commands+=("build") - commands+=("list") - commands+=("update") - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_fetch() -{ - last_command="helm_fetch" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--ca-file=") - local_nonpersistent_flags+=("--ca-file=") - flags+=("--cert-file=") - local_nonpersistent_flags+=("--cert-file=") - flags+=("--destination=") - two_word_flags+=("-d") - local_nonpersistent_flags+=("--destination=") - flags+=("--devel") - local_nonpersistent_flags+=("--devel") - flags+=("--key-file=") - local_nonpersistent_flags+=("--key-file=") - flags+=("--keyring=") - local_nonpersistent_flags+=("--keyring=") - flags+=("--prov") - local_nonpersistent_flags+=("--prov") - flags+=("--repo=") - local_nonpersistent_flags+=("--repo=") - flags+=("--untar") - local_nonpersistent_flags+=("--untar") - flags+=("--untardir=") - local_nonpersistent_flags+=("--untardir=") - flags+=("--verify") - local_nonpersistent_flags+=("--verify") - flags+=("--version=") - local_nonpersistent_flags+=("--version=") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_get_hooks() -{ - last_command="helm_get_hooks" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--revision=") - local_nonpersistent_flags+=("--revision=") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_get_manifest() -{ - last_command="helm_get_manifest" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--revision=") - local_nonpersistent_flags+=("--revision=") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_get_values() -{ - last_command="helm_get_values" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--all") - flags+=("-a") - local_nonpersistent_flags+=("--all") - flags+=("--revision=") - local_nonpersistent_flags+=("--revision=") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_get() -{ - last_command="helm_get" - commands=() - commands+=("hooks") - commands+=("manifest") - commands+=("values") - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--revision=") - local_nonpersistent_flags+=("--revision=") - flags+=("--tls") - local_nonpersistent_flags+=("--tls") - flags+=("--tls-ca-cert=") - local_nonpersistent_flags+=("--tls-ca-cert=") - flags+=("--tls-cert=") - local_nonpersistent_flags+=("--tls-cert=") - flags+=("--tls-key=") - local_nonpersistent_flags+=("--tls-key=") - flags+=("--tls-verify") - local_nonpersistent_flags+=("--tls-verify") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_history() -{ - last_command="helm_history" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--max=") - local_nonpersistent_flags+=("--max=") - flags+=("--tls") - local_nonpersistent_flags+=("--tls") - flags+=("--tls-ca-cert=") - local_nonpersistent_flags+=("--tls-ca-cert=") - flags+=("--tls-cert=") - local_nonpersistent_flags+=("--tls-cert=") - flags+=("--tls-key=") - local_nonpersistent_flags+=("--tls-key=") - flags+=("--tls-verify") - local_nonpersistent_flags+=("--tls-verify") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_home() -{ - last_command="helm_home" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_init() -{ - last_command="helm_init" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--canary-image") - local_nonpersistent_flags+=("--canary-image") - flags+=("--client-only") - flags+=("-c") - local_nonpersistent_flags+=("--client-only") - flags+=("--dry-run") - local_nonpersistent_flags+=("--dry-run") - flags+=("--local-repo-url=") - local_nonpersistent_flags+=("--local-repo-url=") - flags+=("--net-host") - local_nonpersistent_flags+=("--net-host") - flags+=("--service-account=") - local_nonpersistent_flags+=("--service-account=") - flags+=("--skip-refresh") - local_nonpersistent_flags+=("--skip-refresh") - flags+=("--tiller-image=") - two_word_flags+=("-i") - local_nonpersistent_flags+=("--tiller-image=") - flags+=("--tiller-tls") - local_nonpersistent_flags+=("--tiller-tls") - flags+=("--tiller-tls-cert=") - local_nonpersistent_flags+=("--tiller-tls-cert=") - flags+=("--tiller-tls-key=") - local_nonpersistent_flags+=("--tiller-tls-key=") - flags+=("--tiller-tls-verify") - local_nonpersistent_flags+=("--tiller-tls-verify") - flags+=("--tls-ca-cert=") - local_nonpersistent_flags+=("--tls-ca-cert=") - flags+=("--upgrade") - local_nonpersistent_flags+=("--upgrade") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_inspect_chart() -{ - last_command="helm_inspect_chart" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--ca-file=") - local_nonpersistent_flags+=("--ca-file=") - flags+=("--cert-file=") - local_nonpersistent_flags+=("--cert-file=") - flags+=("--key-file=") - local_nonpersistent_flags+=("--key-file=") - flags+=("--keyring=") - local_nonpersistent_flags+=("--keyring=") - flags+=("--repo=") - local_nonpersistent_flags+=("--repo=") - flags+=("--verify") - local_nonpersistent_flags+=("--verify") - flags+=("--version=") - local_nonpersistent_flags+=("--version=") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_inspect_values() -{ - last_command="helm_inspect_values" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--ca-file=") - local_nonpersistent_flags+=("--ca-file=") - flags+=("--cert-file=") - local_nonpersistent_flags+=("--cert-file=") - flags+=("--key-file=") - local_nonpersistent_flags+=("--key-file=") - flags+=("--keyring=") - local_nonpersistent_flags+=("--keyring=") - flags+=("--repo=") - local_nonpersistent_flags+=("--repo=") - flags+=("--verify") - local_nonpersistent_flags+=("--verify") - flags+=("--version=") - local_nonpersistent_flags+=("--version=") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_inspect() -{ - last_command="helm_inspect" - commands=() - commands+=("chart") - commands+=("values") - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--ca-file=") - local_nonpersistent_flags+=("--ca-file=") - flags+=("--cert-file=") - local_nonpersistent_flags+=("--cert-file=") - flags+=("--key-file=") - local_nonpersistent_flags+=("--key-file=") - flags+=("--keyring=") - local_nonpersistent_flags+=("--keyring=") - flags+=("--repo=") - local_nonpersistent_flags+=("--repo=") - flags+=("--verify") - local_nonpersistent_flags+=("--verify") - flags+=("--version=") - local_nonpersistent_flags+=("--version=") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_install() -{ - last_command="helm_install" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--ca-file=") - local_nonpersistent_flags+=("--ca-file=") - flags+=("--cert-file=") - local_nonpersistent_flags+=("--cert-file=") - flags+=("--devel") - local_nonpersistent_flags+=("--devel") - flags+=("--dry-run") - local_nonpersistent_flags+=("--dry-run") - flags+=("--key-file=") - local_nonpersistent_flags+=("--key-file=") - flags+=("--keyring=") - local_nonpersistent_flags+=("--keyring=") - flags+=("--name=") - two_word_flags+=("-n") - local_nonpersistent_flags+=("--name=") - flags+=("--name-template=") - local_nonpersistent_flags+=("--name-template=") - flags+=("--namespace=") - local_nonpersistent_flags+=("--namespace=") - flags+=("--no-hooks") - local_nonpersistent_flags+=("--no-hooks") - flags+=("--replace") - local_nonpersistent_flags+=("--replace") - flags+=("--repo=") - local_nonpersistent_flags+=("--repo=") - flags+=("--set=") - local_nonpersistent_flags+=("--set=") - flags+=("--set-string=") - local_nonpersistent_flags+=("--set-string=") - flags+=("--timeout=") - local_nonpersistent_flags+=("--timeout=") - flags+=("--tls") - local_nonpersistent_flags+=("--tls") - flags+=("--tls-ca-cert=") - local_nonpersistent_flags+=("--tls-ca-cert=") - flags+=("--tls-cert=") - local_nonpersistent_flags+=("--tls-cert=") - flags+=("--tls-key=") - local_nonpersistent_flags+=("--tls-key=") - flags+=("--tls-verify") - local_nonpersistent_flags+=("--tls-verify") - flags+=("--values=") - two_word_flags+=("-f") - local_nonpersistent_flags+=("--values=") - flags+=("--verify") - local_nonpersistent_flags+=("--verify") - flags+=("--version=") - local_nonpersistent_flags+=("--version=") - flags+=("--wait") - local_nonpersistent_flags+=("--wait") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_lint() -{ - last_command="helm_lint" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--strict") - local_nonpersistent_flags+=("--strict") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_list() -{ - last_command="helm_list" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--all") - local_nonpersistent_flags+=("--all") - flags+=("--date") - flags+=("-d") - local_nonpersistent_flags+=("--date") - flags+=("--uninstalled") - local_nonpersistent_flags+=("--uninstalled") - flags+=("--uninstalling") - local_nonpersistent_flags+=("--uninstalling") - flags+=("--deployed") - local_nonpersistent_flags+=("--deployed") - flags+=("--failed") - local_nonpersistent_flags+=("--failed") - flags+=("--max=") - two_word_flags+=("-m") - local_nonpersistent_flags+=("--max=") - flags+=("--namespace=") - local_nonpersistent_flags+=("--namespace=") - flags+=("--offset=") - two_word_flags+=("-o") - local_nonpersistent_flags+=("--offset=") - flags+=("--reverse") - flags+=("-r") - local_nonpersistent_flags+=("--reverse") - flags+=("--short") - flags+=("-q") - local_nonpersistent_flags+=("--short") - flags+=("--tls") - local_nonpersistent_flags+=("--tls") - flags+=("--tls-ca-cert=") - local_nonpersistent_flags+=("--tls-ca-cert=") - flags+=("--tls-cert=") - local_nonpersistent_flags+=("--tls-cert=") - flags+=("--tls-key=") - local_nonpersistent_flags+=("--tls-key=") - flags+=("--tls-verify") - local_nonpersistent_flags+=("--tls-verify") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_package() -{ - last_command="helm_package" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--destination=") - two_word_flags+=("-d") - local_nonpersistent_flags+=("--destination=") - flags+=("--key=") - local_nonpersistent_flags+=("--key=") - flags+=("--keyring=") - local_nonpersistent_flags+=("--keyring=") - flags+=("--save") - local_nonpersistent_flags+=("--save") - flags+=("--sign") - local_nonpersistent_flags+=("--sign") - flags+=("--version=") - local_nonpersistent_flags+=("--version=") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_plugin_install() -{ - last_command="helm_plugin_install" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--version=") - local_nonpersistent_flags+=("--version=") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_plugin_list() -{ - last_command="helm_plugin_list" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_plugin_remove() -{ - last_command="helm_plugin_remove" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_plugin_update() -{ - last_command="helm_plugin_update" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_plugin() -{ - last_command="helm_plugin" - commands=() - commands+=("install") - commands+=("list") - commands+=("remove") - commands+=("update") - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_repo_add() -{ - last_command="helm_repo_add" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--ca-file=") - local_nonpersistent_flags+=("--ca-file=") - flags+=("--cert-file=") - local_nonpersistent_flags+=("--cert-file=") - flags+=("--key-file=") - local_nonpersistent_flags+=("--key-file=") - flags+=("--no-update") - local_nonpersistent_flags+=("--no-update") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_repo_index() -{ - last_command="helm_repo_index" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--merge=") - local_nonpersistent_flags+=("--merge=") - flags+=("--url=") - local_nonpersistent_flags+=("--url=") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_repo_list() -{ - last_command="helm_repo_list" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_repo_remove() -{ - last_command="helm_repo_remove" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_repo_update() -{ - last_command="helm_repo_update" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_repo() -{ - last_command="helm_repo" - commands=() - commands+=("add") - commands+=("index") - commands+=("list") - commands+=("remove") - commands+=("update") - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_reset() -{ - last_command="helm_reset" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--force") - flags+=("-f") - local_nonpersistent_flags+=("--force") - flags+=("--remove-helm-home") - local_nonpersistent_flags+=("--remove-helm-home") - flags+=("--tls") - local_nonpersistent_flags+=("--tls") - flags+=("--tls-ca-cert=") - local_nonpersistent_flags+=("--tls-ca-cert=") - flags+=("--tls-cert=") - local_nonpersistent_flags+=("--tls-cert=") - flags+=("--tls-key=") - local_nonpersistent_flags+=("--tls-key=") - flags+=("--tls-verify") - local_nonpersistent_flags+=("--tls-verify") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_rollback() -{ - last_command="helm_rollback" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--dry-run") - local_nonpersistent_flags+=("--dry-run") - flags+=("--force") - local_nonpersistent_flags+=("--force") - flags+=("--no-hooks") - local_nonpersistent_flags+=("--no-hooks") - flags+=("--recreate-pods") - local_nonpersistent_flags+=("--recreate-pods") - flags+=("--timeout=") - local_nonpersistent_flags+=("--timeout=") - flags+=("--tls") - local_nonpersistent_flags+=("--tls") - flags+=("--tls-ca-cert=") - local_nonpersistent_flags+=("--tls-ca-cert=") - flags+=("--tls-cert=") - local_nonpersistent_flags+=("--tls-cert=") - flags+=("--tls-key=") - local_nonpersistent_flags+=("--tls-key=") - flags+=("--tls-verify") - local_nonpersistent_flags+=("--tls-verify") - flags+=("--wait") - local_nonpersistent_flags+=("--wait") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_search() -{ - last_command="helm_search" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--regexp") - flags+=("-r") - local_nonpersistent_flags+=("--regexp") - flags+=("--version=") - two_word_flags+=("-v") - local_nonpersistent_flags+=("--version=") - flags+=("--versions") - flags+=("-l") - local_nonpersistent_flags+=("--versions") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_serve() -{ - last_command="helm_serve" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--address=") - local_nonpersistent_flags+=("--address=") - flags+=("--repo-path=") - local_nonpersistent_flags+=("--repo-path=") - flags+=("--url=") - local_nonpersistent_flags+=("--url=") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_status() -{ - last_command="helm_status" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--revision=") - flags+=("--tls") - local_nonpersistent_flags+=("--tls") - flags+=("--tls-ca-cert=") - local_nonpersistent_flags+=("--tls-ca-cert=") - flags+=("--tls-cert=") - local_nonpersistent_flags+=("--tls-cert=") - flags+=("--tls-key=") - local_nonpersistent_flags+=("--tls-key=") - flags+=("--tls-verify") - local_nonpersistent_flags+=("--tls-verify") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_test() -{ - last_command="helm_test" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--cleanup") - local_nonpersistent_flags+=("--cleanup") - flags+=("--timeout=") - local_nonpersistent_flags+=("--timeout=") - flags+=("--tls") - local_nonpersistent_flags+=("--tls") - flags+=("--tls-ca-cert=") - local_nonpersistent_flags+=("--tls-ca-cert=") - flags+=("--tls-cert=") - local_nonpersistent_flags+=("--tls-cert=") - flags+=("--tls-key=") - local_nonpersistent_flags+=("--tls-key=") - flags+=("--tls-verify") - local_nonpersistent_flags+=("--tls-verify") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_upgrade() -{ - last_command="helm_upgrade" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--ca-file=") - local_nonpersistent_flags+=("--ca-file=") - flags+=("--cert-file=") - local_nonpersistent_flags+=("--cert-file=") - flags+=("--devel") - local_nonpersistent_flags+=("--devel") - flags+=("--disable-hooks") - local_nonpersistent_flags+=("--disable-hooks") - flags+=("--dry-run") - local_nonpersistent_flags+=("--dry-run") - flags+=("--force") - local_nonpersistent_flags+=("--force") - flags+=("--install") - flags+=("-i") - local_nonpersistent_flags+=("--install") - flags+=("--key-file=") - local_nonpersistent_flags+=("--key-file=") - flags+=("--keyring=") - local_nonpersistent_flags+=("--keyring=") - flags+=("--namespace=") - local_nonpersistent_flags+=("--namespace=") - flags+=("--no-hooks") - local_nonpersistent_flags+=("--no-hooks") - flags+=("--recreate-pods") - local_nonpersistent_flags+=("--recreate-pods") - flags+=("--repo=") - local_nonpersistent_flags+=("--repo=") - flags+=("--reset-values") - local_nonpersistent_flags+=("--reset-values") - flags+=("--reuse-values") - local_nonpersistent_flags+=("--reuse-values") - flags+=("--set=") - local_nonpersistent_flags+=("--set=") - flags+=("--timeout=") - local_nonpersistent_flags+=("--timeout=") - flags+=("--tls") - local_nonpersistent_flags+=("--tls") - flags+=("--tls-ca-cert=") - local_nonpersistent_flags+=("--tls-ca-cert=") - flags+=("--tls-cert=") - local_nonpersistent_flags+=("--tls-cert=") - flags+=("--tls-key=") - local_nonpersistent_flags+=("--tls-key=") - flags+=("--tls-verify") - local_nonpersistent_flags+=("--tls-verify") - flags+=("--values=") - two_word_flags+=("-f") - local_nonpersistent_flags+=("--values=") - flags+=("--verify") - local_nonpersistent_flags+=("--verify") - flags+=("--version=") - local_nonpersistent_flags+=("--version=") - flags+=("--wait") - local_nonpersistent_flags+=("--wait") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_verify() -{ - last_command="helm_verify" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--keyring=") - local_nonpersistent_flags+=("--keyring=") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm_version() -{ - last_command="helm_version" - commands=() - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--client") - flags+=("-c") - local_nonpersistent_flags+=("--client") - flags+=("--server") - flags+=("-s") - local_nonpersistent_flags+=("--server") - flags+=("--short") - local_nonpersistent_flags+=("--short") - flags+=("--tls") - local_nonpersistent_flags+=("--tls") - flags+=("--tls-ca-cert=") - local_nonpersistent_flags+=("--tls-ca-cert=") - flags+=("--tls-cert=") - local_nonpersistent_flags+=("--tls-cert=") - flags+=("--tls-key=") - local_nonpersistent_flags+=("--tls-key=") - flags+=("--tls-verify") - local_nonpersistent_flags+=("--tls-verify") - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -_helm() -{ - last_command="helm" - commands=() - commands+=("completion") - commands+=("create") - commands+=("delete") - commands+=("dependency") - commands+=("fetch") - commands+=("get") - commands+=("history") - commands+=("home") - commands+=("init") - commands+=("inspect") - commands+=("install") - commands+=("lint") - commands+=("list") - commands+=("package") - commands+=("plugin") - commands+=("repo") - commands+=("reset") - commands+=("rollback") - commands+=("search") - commands+=("serve") - commands+=("status") - commands+=("test") - commands+=("upgrade") - commands+=("verify") - commands+=("version") - - flags=() - two_word_flags=() - local_nonpersistent_flags=() - flags_with_completion=() - flags_completion=() - - flags+=("--debug") - flags+=("--host=") - flags+=("--kube-context=") - flags+=("--tiller-namespace=") - - must_have_one_flag=() - must_have_one_noun=() - noun_aliases=() -} - -__start_helm() -{ - local cur prev words cword - declare -A flaghash 2>/dev/null || : - if declare -F _init_completion >/dev/null 2>&1; then - _init_completion -s || return - else - __my_init_completion -n "=" || return - fi - - local c=0 - local flags=() - local two_word_flags=() - local local_nonpersistent_flags=() - local flags_with_completion=() - local flags_completion=() - local commands=("helm") - local must_have_one_flag=() - local must_have_one_noun=() - local last_command - local nouns=() - - __handle_word -} - -if [[ $(type -t compopt) = "builtin" ]]; then - complete -o default -F __start_helm helm -else - complete -o default -o nospace -F __start_helm helm -fi - -# ex: ts=4 sw=4 et filetype=sh From f182ebc11c9ea7a5bf75e35d8e061f3ac68482fd Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Fri, 22 May 2020 12:04:37 -0400 Subject: [PATCH 067/159] Fix issue with unhandled error on Stat If stat returns an error other than the directory not existing it was unhandled. When IsDir is called in one of these situations it causes a panic. Closes #8181 Signed-off-by: Matt Farina --- pkg/chartutil/save.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pkg/chartutil/save.go b/pkg/chartutil/save.go index 1011436b5..2ce4eddaf 100644 --- a/pkg/chartutil/save.go +++ b/pkg/chartutil/save.go @@ -106,12 +106,17 @@ func Save(c *chart.Chart, outDir string) (string, error) { filename := fmt.Sprintf("%s-%s.tgz", c.Name(), c.Metadata.Version) filename = filepath.Join(outDir, filename) - if stat, err := os.Stat(filepath.Dir(filename)); os.IsNotExist(err) { - if err := os.MkdirAll(filepath.Dir(filename), 0755); err != nil { - return "", err + dir := filepath.Dir(filename) + if stat, err := os.Stat(dir); err != nil { + if os.IsNotExist(err) { + if err2 := os.MkdirAll(dir, 0755); err2 != nil { + return "", err2 + } + } else { + return "", errors.Wrapf(err, "stat %s", dir) } } else if !stat.IsDir() { - return "", errors.Errorf("is not a directory: %s", filepath.Dir(filename)) + return "", errors.Errorf("is not a directory: %s", dir) } f, err := os.Create(filename) From 44a2225035d93ab6e8dc40af7c3ee4ff13452fae Mon Sep 17 00:00:00 2001 From: Adam Reese Date: Fri, 22 May 2020 11:39:20 -0700 Subject: [PATCH 068/159] ref(tests): localize unit test fixtures to package Use test fixtures that are in the same package as test. Signed-off-by: Adam Reese --- cmd/helm/template_test.go | 2 +- .../output/template-name-template.txt | 28 +- cmd/helm/testdata/output/template-set.txt | 28 +- .../output/template-show-only-glob.txt | 12 +- .../output/template-show-only-multiple.txt | 10 +- .../output/template-show-only-one.txt | 8 +- .../testdata/output/template-values-files.txt | 28 +- .../output/template-with-api-version.txt | 28 +- .../testdata/output/template-with-crds.txt | 28 +- cmd/helm/testdata/output/template.txt | 28 +- .../chart-with-no-templates-dir/values.yaml | 1 - .../testcharts/decompressedchart/.helmignore | 5 - .../testdata/testcharts/novals/Chart.yaml | 8 - cmd/helm/testdata/testcharts/novals/README.md | 13 - .../novals/templates/alpine-pod.yaml | 28 -- .../testdata/testcharts/subchart/Chart.yaml | 36 +++ .../subchart/charts/subchartA/Chart.yaml | 4 + .../charts/subchartA/templates/service.yaml | 15 ++ .../subchart/charts/subchartA/values.yaml | 17 ++ .../subchart/charts/subchartB/Chart.yaml | 4 + .../charts/subchartB/templates/service.yaml | 15 ++ .../subchart/charts/subchartB/values.yaml | 35 +++ .../testcharts/subchart/crds/crdA.yaml | 13 + .../testcharts/subchart/templates/NOTES.txt | 1 + .../subchart/templates/service.yaml | 22 ++ .../subchart/templates/subdir/role.yaml | 7 + .../templates/subdir/rolebinding.yaml | 12 + .../templates/subdir/serviceaccount.yaml | 4 + .../testdata/testcharts/subchart/values.yaml | 55 ++++ internal/resolver/resolver_test.go | 14 +- .../testdata/chartpath/base/Chart.yaml | 3 + pkg/action/dependency_test.go | 10 +- pkg/action/lint_test.go | 26 +- pkg/action/show.go | 20 +- pkg/action/show_test.go | 61 ++--- .../charts/chart-missing-deps/.helmignore | 5 - .../charts/chart-missing-deps/Chart.yaml | 18 -- .../charts/chart-missing-deps/README.md | 232 ---------------- .../chart-missing-deps/templates/NOTES.txt | 38 --- .../chart-missing-deps/templates/_helpers.tpl | 24 -- .../charts/chart-missing-deps/values.yaml | 254 ------------------ .../.helmignore | 5 - .../Chart.yaml | 18 -- .../README.md | 3 - .../templates/NOTES.txt | 1 - .../values.yaml | 254 ------------------ .../chart-with-no-templates-dir/Chart.yaml | 0 .../chart-with-schema-negative/Chart.yaml | 7 + .../templates/empty.yaml | 1 + .../values.schema.json | 67 +++++ .../chart-with-schema-negative/values.yaml | 14 + .../charts/chart-with-schema/Chart.yaml | 7 + .../chart-with-schema/extra-values.yaml | 2 + .../chart-with-schema/templates/empty.yaml | 1 + .../chart-with-schema/values.schema.json | 67 +++++ .../charts/chart-with-schema/values.yaml | 17 ++ .../charts/compressedchart-0.1.0.tar.gz | Bin 0 -> 477 bytes .../testdata/charts/compressedchart-0.1.0.tgz | Bin 0 -> 477 bytes .../testdata/charts/compressedchart-0.2.0.tgz | Bin 0 -> 477 bytes .../testdata/charts/compressedchart-0.3.0.tgz | Bin 0 -> 477 bytes .../compressedchart-with-hyphens-0.1.0.tgz | Bin 0 -> 548 bytes .../charts}/corrupted-compressed-chart.tgz | 0 .../charts}/decompressedchart/Chart.yaml | 0 .../charts}/decompressedchart/values.yaml | 0 .../multiplecharts-lint-chart-1/Chart.yaml | 0 .../templates/configmap.yaml | 0 .../multiplecharts-lint-chart-1/values.yaml | 0 .../multiplecharts-lint-chart-2/Chart.yaml | 0 .../templates/configmap.yaml | 0 .../multiplecharts-lint-chart-2/values.yaml | 0 .../charts/pre-release-chart-0.1.0-alpha.tgz | Bin 0 -> 355 bytes ...s-tgz.txt => list-compressed-deps-tgz.txt} | 0 ...ssed-deps.txt => list-compressed-deps.txt} | 0 ...missing-deps.txt => list-missing-deps.txt} | 0 ...tgz.txt => list-uncompressed-deps-tgz.txt} | 0 ...ed-deps.txt => list-uncompressed-deps.txt} | 0 76 files changed, 591 insertions(+), 1073 deletions(-) delete mode 100644 cmd/helm/testdata/testcharts/chart-with-no-templates-dir/values.yaml delete mode 100644 cmd/helm/testdata/testcharts/decompressedchart/.helmignore delete mode 100644 cmd/helm/testdata/testcharts/novals/Chart.yaml delete mode 100644 cmd/helm/testdata/testcharts/novals/README.md delete mode 100644 cmd/helm/testdata/testcharts/novals/templates/alpine-pod.yaml create mode 100644 cmd/helm/testdata/testcharts/subchart/Chart.yaml create mode 100644 cmd/helm/testdata/testcharts/subchart/charts/subchartA/Chart.yaml create mode 100644 cmd/helm/testdata/testcharts/subchart/charts/subchartA/templates/service.yaml create mode 100644 cmd/helm/testdata/testcharts/subchart/charts/subchartA/values.yaml create mode 100644 cmd/helm/testdata/testcharts/subchart/charts/subchartB/Chart.yaml create mode 100644 cmd/helm/testdata/testcharts/subchart/charts/subchartB/templates/service.yaml create mode 100644 cmd/helm/testdata/testcharts/subchart/charts/subchartB/values.yaml create mode 100644 cmd/helm/testdata/testcharts/subchart/crds/crdA.yaml create mode 100644 cmd/helm/testdata/testcharts/subchart/templates/NOTES.txt create mode 100644 cmd/helm/testdata/testcharts/subchart/templates/service.yaml create mode 100644 cmd/helm/testdata/testcharts/subchart/templates/subdir/role.yaml create mode 100644 cmd/helm/testdata/testcharts/subchart/templates/subdir/rolebinding.yaml create mode 100644 cmd/helm/testdata/testcharts/subchart/templates/subdir/serviceaccount.yaml create mode 100644 cmd/helm/testdata/testcharts/subchart/values.yaml create mode 100644 internal/resolver/testdata/chartpath/base/Chart.yaml delete mode 100755 pkg/action/testdata/charts/chart-missing-deps/.helmignore delete mode 100755 pkg/action/testdata/charts/chart-missing-deps/README.md delete mode 100755 pkg/action/testdata/charts/chart-missing-deps/templates/NOTES.txt delete mode 100755 pkg/action/testdata/charts/chart-missing-deps/templates/_helpers.tpl delete mode 100755 pkg/action/testdata/charts/chart-missing-deps/values.yaml delete mode 100755 pkg/action/testdata/charts/chart-with-compressed-dependencies/.helmignore delete mode 100755 pkg/action/testdata/charts/chart-with-compressed-dependencies/README.md delete mode 100755 pkg/action/testdata/charts/chart-with-compressed-dependencies/templates/NOTES.txt delete mode 100755 pkg/action/testdata/charts/chart-with-compressed-dependencies/values.yaml rename {cmd/helm/testdata/testcharts => pkg/action/testdata/charts}/chart-with-no-templates-dir/Chart.yaml (100%) create mode 100644 pkg/action/testdata/charts/chart-with-schema-negative/Chart.yaml create mode 100644 pkg/action/testdata/charts/chart-with-schema-negative/templates/empty.yaml create mode 100644 pkg/action/testdata/charts/chart-with-schema-negative/values.schema.json create mode 100644 pkg/action/testdata/charts/chart-with-schema-negative/values.yaml create mode 100644 pkg/action/testdata/charts/chart-with-schema/Chart.yaml create mode 100644 pkg/action/testdata/charts/chart-with-schema/extra-values.yaml create mode 100644 pkg/action/testdata/charts/chart-with-schema/templates/empty.yaml create mode 100644 pkg/action/testdata/charts/chart-with-schema/values.schema.json create mode 100644 pkg/action/testdata/charts/chart-with-schema/values.yaml create mode 100644 pkg/action/testdata/charts/compressedchart-0.1.0.tar.gz create mode 100644 pkg/action/testdata/charts/compressedchart-0.1.0.tgz create mode 100644 pkg/action/testdata/charts/compressedchart-0.2.0.tgz create mode 100644 pkg/action/testdata/charts/compressedchart-0.3.0.tgz create mode 100644 pkg/action/testdata/charts/compressedchart-with-hyphens-0.1.0.tgz rename {cmd/helm/testdata/testcharts => pkg/action/testdata/charts}/corrupted-compressed-chart.tgz (100%) rename {cmd/helm/testdata/testcharts => pkg/action/testdata/charts}/decompressedchart/Chart.yaml (100%) rename {cmd/helm/testdata/testcharts => pkg/action/testdata/charts}/decompressedchart/values.yaml (100%) rename {cmd/helm/testdata/testcharts => pkg/action/testdata/charts}/multiplecharts-lint-chart-1/Chart.yaml (100%) rename {cmd/helm/testdata/testcharts => pkg/action/testdata/charts}/multiplecharts-lint-chart-1/templates/configmap.yaml (100%) rename {cmd/helm/testdata/testcharts => pkg/action/testdata/charts}/multiplecharts-lint-chart-1/values.yaml (100%) rename {cmd/helm/testdata/testcharts => pkg/action/testdata/charts}/multiplecharts-lint-chart-2/Chart.yaml (100%) rename {cmd/helm/testdata/testcharts => pkg/action/testdata/charts}/multiplecharts-lint-chart-2/templates/configmap.yaml (100%) rename {cmd/helm/testdata/testcharts => pkg/action/testdata/charts}/multiplecharts-lint-chart-2/values.yaml (100%) create mode 100644 pkg/action/testdata/charts/pre-release-chart-0.1.0-alpha.tgz rename pkg/action/testdata/output/{compressed-deps-tgz.txt => list-compressed-deps-tgz.txt} (100%) rename pkg/action/testdata/output/{compressed-deps.txt => list-compressed-deps.txt} (100%) rename pkg/action/testdata/output/{missing-deps.txt => list-missing-deps.txt} (100%) rename pkg/action/testdata/output/{uncompressed-deps-tgz.txt => list-uncompressed-deps-tgz.txt} (100%) rename pkg/action/testdata/output/{uncompressed-deps.txt => list-uncompressed-deps.txt} (100%) diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go index 87ee79e5a..92dd9825e 100644 --- a/cmd/helm/template_test.go +++ b/cmd/helm/template_test.go @@ -22,7 +22,7 @@ import ( "testing" ) -var chartPath = "./../../pkg/chartutil/testdata/subpop/charts/subchart1" +var chartPath = "testdata/testcharts/subchart" func TestTemplateCmd(t *testing.T) { tests := []cmdTestCase{ diff --git a/cmd/helm/testdata/output/template-name-template.txt b/cmd/helm/testdata/output/template-name-template.txt index 24f2bb616..84a9e565c 100644 --- a/cmd/helm/testdata/output/template-name-template.txt +++ b/cmd/helm/testdata/output/template-name-template.txt @@ -1,34 +1,34 @@ --- -# Source: subchart1/templates/subdir/serviceaccount.yaml +# Source: subchart/templates/subdir/serviceaccount.yaml apiVersion: v1 kind: ServiceAccount metadata: - name: subchart1-sa + name: subchart-sa --- -# Source: subchart1/templates/subdir/role.yaml +# Source: subchart/templates/subdir/role.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: subchart1-role + name: subchart-role rules: - resources: ["*"] verbs: ["get","list","watch"] --- -# Source: subchart1/templates/subdir/rolebinding.yaml +# Source: subchart/templates/subdir/rolebinding.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: subchart1-binding + name: subchart-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: subchart1-role + name: subchart-role subjects: - kind: ServiceAccount - name: subchart1-sa + name: subchart-sa namespace: default --- -# Source: subchart1/charts/subcharta/templates/service.yaml +# Source: subchart/charts/subcharta/templates/service.yaml apiVersion: v1 kind: Service metadata: @@ -45,7 +45,7 @@ spec: selector: app.kubernetes.io/name: subcharta --- -# Source: subchart1/charts/subchartb/templates/service.yaml +# Source: subchart/charts/subchartb/templates/service.yaml apiVersion: v1 kind: Service metadata: @@ -62,13 +62,13 @@ spec: selector: app.kubernetes.io/name: subchartb --- -# Source: subchart1/templates/service.yaml +# Source: subchart/templates/service.yaml apiVersion: v1 kind: Service metadata: - name: subchart1 + name: subchart labels: - helm.sh/chart: "subchart1-0.1.0" + helm.sh/chart: "subchart-0.1.0" app.kubernetes.io/instance: "foobar-YWJj-baz" kube-version/major: "1" kube-version/minor: "18" @@ -81,4 +81,4 @@ spec: protocol: TCP name: nginx selector: - app.kubernetes.io/name: subchart1 + app.kubernetes.io/name: subchart diff --git a/cmd/helm/testdata/output/template-set.txt b/cmd/helm/testdata/output/template-set.txt index 4c7f1f626..1cb97723e 100644 --- a/cmd/helm/testdata/output/template-set.txt +++ b/cmd/helm/testdata/output/template-set.txt @@ -1,34 +1,34 @@ --- -# Source: subchart1/templates/subdir/serviceaccount.yaml +# Source: subchart/templates/subdir/serviceaccount.yaml apiVersion: v1 kind: ServiceAccount metadata: - name: subchart1-sa + name: subchart-sa --- -# Source: subchart1/templates/subdir/role.yaml +# Source: subchart/templates/subdir/role.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: subchart1-role + name: subchart-role rules: - resources: ["*"] verbs: ["get","list","watch"] --- -# Source: subchart1/templates/subdir/rolebinding.yaml +# Source: subchart/templates/subdir/rolebinding.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: subchart1-binding + name: subchart-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: subchart1-role + name: subchart-role subjects: - kind: ServiceAccount - name: subchart1-sa + name: subchart-sa namespace: default --- -# Source: subchart1/charts/subcharta/templates/service.yaml +# Source: subchart/charts/subcharta/templates/service.yaml apiVersion: v1 kind: Service metadata: @@ -45,7 +45,7 @@ spec: selector: app.kubernetes.io/name: subcharta --- -# Source: subchart1/charts/subchartb/templates/service.yaml +# Source: subchart/charts/subchartb/templates/service.yaml apiVersion: v1 kind: Service metadata: @@ -62,13 +62,13 @@ spec: selector: app.kubernetes.io/name: subchartb --- -# Source: subchart1/templates/service.yaml +# Source: subchart/templates/service.yaml apiVersion: v1 kind: Service metadata: - name: subchart1 + name: subchart labels: - helm.sh/chart: "subchart1-0.1.0" + helm.sh/chart: "subchart-0.1.0" app.kubernetes.io/instance: "RELEASE-NAME" kube-version/major: "1" kube-version/minor: "18" @@ -81,4 +81,4 @@ spec: protocol: TCP name: apache selector: - app.kubernetes.io/name: subchart1 + app.kubernetes.io/name: subchart diff --git a/cmd/helm/testdata/output/template-show-only-glob.txt b/cmd/helm/testdata/output/template-show-only-glob.txt index 0970e6cd3..cc651f596 100644 --- a/cmd/helm/testdata/output/template-show-only-glob.txt +++ b/cmd/helm/testdata/output/template-show-only-glob.txt @@ -1,23 +1,23 @@ --- -# Source: subchart1/templates/subdir/role.yaml +# Source: subchart/templates/subdir/role.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: subchart1-role + name: subchart-role rules: - resources: ["*"] verbs: ["get","list","watch"] --- -# Source: subchart1/templates/subdir/rolebinding.yaml +# Source: subchart/templates/subdir/rolebinding.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: subchart1-binding + name: subchart-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: subchart1-role + name: subchart-role subjects: - kind: ServiceAccount - name: subchart1-sa + name: subchart-sa namespace: default diff --git a/cmd/helm/testdata/output/template-show-only-multiple.txt b/cmd/helm/testdata/output/template-show-only-multiple.txt index 75b590e20..1c4b1f29e 100644 --- a/cmd/helm/testdata/output/template-show-only-multiple.txt +++ b/cmd/helm/testdata/output/template-show-only-multiple.txt @@ -1,11 +1,11 @@ --- -# Source: subchart1/templates/service.yaml +# Source: subchart/templates/service.yaml apiVersion: v1 kind: Service metadata: - name: subchart1 + name: subchart labels: - helm.sh/chart: "subchart1-0.1.0" + helm.sh/chart: "subchart-0.1.0" app.kubernetes.io/instance: "RELEASE-NAME" kube-version/major: "1" kube-version/minor: "18" @@ -19,9 +19,9 @@ spec: protocol: TCP name: nginx selector: - app.kubernetes.io/name: subchart1 + app.kubernetes.io/name: subchart --- -# Source: subchart1/charts/subcharta/templates/service.yaml +# Source: subchart/charts/subcharta/templates/service.yaml apiVersion: v1 kind: Service metadata: diff --git a/cmd/helm/testdata/output/template-show-only-one.txt b/cmd/helm/testdata/output/template-show-only-one.txt index ce61f481f..7b1443ea8 100644 --- a/cmd/helm/testdata/output/template-show-only-one.txt +++ b/cmd/helm/testdata/output/template-show-only-one.txt @@ -1,11 +1,11 @@ --- -# Source: subchart1/templates/service.yaml +# Source: subchart/templates/service.yaml apiVersion: v1 kind: Service metadata: - name: subchart1 + name: subchart labels: - helm.sh/chart: "subchart1-0.1.0" + helm.sh/chart: "subchart-0.1.0" app.kubernetes.io/instance: "RELEASE-NAME" kube-version/major: "1" kube-version/minor: "18" @@ -19,4 +19,4 @@ spec: protocol: TCP name: nginx selector: - app.kubernetes.io/name: subchart1 + app.kubernetes.io/name: subchart diff --git a/cmd/helm/testdata/output/template-values-files.txt b/cmd/helm/testdata/output/template-values-files.txt index 4c7f1f626..1cb97723e 100644 --- a/cmd/helm/testdata/output/template-values-files.txt +++ b/cmd/helm/testdata/output/template-values-files.txt @@ -1,34 +1,34 @@ --- -# Source: subchart1/templates/subdir/serviceaccount.yaml +# Source: subchart/templates/subdir/serviceaccount.yaml apiVersion: v1 kind: ServiceAccount metadata: - name: subchart1-sa + name: subchart-sa --- -# Source: subchart1/templates/subdir/role.yaml +# Source: subchart/templates/subdir/role.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: subchart1-role + name: subchart-role rules: - resources: ["*"] verbs: ["get","list","watch"] --- -# Source: subchart1/templates/subdir/rolebinding.yaml +# Source: subchart/templates/subdir/rolebinding.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: subchart1-binding + name: subchart-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: subchart1-role + name: subchart-role subjects: - kind: ServiceAccount - name: subchart1-sa + name: subchart-sa namespace: default --- -# Source: subchart1/charts/subcharta/templates/service.yaml +# Source: subchart/charts/subcharta/templates/service.yaml apiVersion: v1 kind: Service metadata: @@ -45,7 +45,7 @@ spec: selector: app.kubernetes.io/name: subcharta --- -# Source: subchart1/charts/subchartb/templates/service.yaml +# Source: subchart/charts/subchartb/templates/service.yaml apiVersion: v1 kind: Service metadata: @@ -62,13 +62,13 @@ spec: selector: app.kubernetes.io/name: subchartb --- -# Source: subchart1/templates/service.yaml +# Source: subchart/templates/service.yaml apiVersion: v1 kind: Service metadata: - name: subchart1 + name: subchart labels: - helm.sh/chart: "subchart1-0.1.0" + helm.sh/chart: "subchart-0.1.0" app.kubernetes.io/instance: "RELEASE-NAME" kube-version/major: "1" kube-version/minor: "18" @@ -81,4 +81,4 @@ spec: protocol: TCP name: apache selector: - app.kubernetes.io/name: subchart1 + app.kubernetes.io/name: subchart diff --git a/cmd/helm/testdata/output/template-with-api-version.txt b/cmd/helm/testdata/output/template-with-api-version.txt index 210dcc503..ea4b5c96b 100644 --- a/cmd/helm/testdata/output/template-with-api-version.txt +++ b/cmd/helm/testdata/output/template-with-api-version.txt @@ -1,34 +1,34 @@ --- -# Source: subchart1/templates/subdir/serviceaccount.yaml +# Source: subchart/templates/subdir/serviceaccount.yaml apiVersion: v1 kind: ServiceAccount metadata: - name: subchart1-sa + name: subchart-sa --- -# Source: subchart1/templates/subdir/role.yaml +# Source: subchart/templates/subdir/role.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: subchart1-role + name: subchart-role rules: - resources: ["*"] verbs: ["get","list","watch"] --- -# Source: subchart1/templates/subdir/rolebinding.yaml +# Source: subchart/templates/subdir/rolebinding.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: subchart1-binding + name: subchart-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: subchart1-role + name: subchart-role subjects: - kind: ServiceAccount - name: subchart1-sa + name: subchart-sa namespace: default --- -# Source: subchart1/charts/subcharta/templates/service.yaml +# Source: subchart/charts/subcharta/templates/service.yaml apiVersion: v1 kind: Service metadata: @@ -45,7 +45,7 @@ spec: selector: app.kubernetes.io/name: subcharta --- -# Source: subchart1/charts/subchartb/templates/service.yaml +# Source: subchart/charts/subchartb/templates/service.yaml apiVersion: v1 kind: Service metadata: @@ -62,13 +62,13 @@ spec: selector: app.kubernetes.io/name: subchartb --- -# Source: subchart1/templates/service.yaml +# Source: subchart/templates/service.yaml apiVersion: v1 kind: Service metadata: - name: subchart1 + name: subchart labels: - helm.sh/chart: "subchart1-0.1.0" + helm.sh/chart: "subchart-0.1.0" app.kubernetes.io/instance: "RELEASE-NAME" kube-version/major: "1" kube-version/minor: "18" @@ -82,4 +82,4 @@ spec: protocol: TCP name: nginx selector: - app.kubernetes.io/name: subchart1 + app.kubernetes.io/name: subchart diff --git a/cmd/helm/testdata/output/template-with-crds.txt b/cmd/helm/testdata/output/template-with-crds.txt index 289eec291..fa2a79bac 100644 --- a/cmd/helm/testdata/output/template-with-crds.txt +++ b/cmd/helm/testdata/output/template-with-crds.txt @@ -15,36 +15,36 @@ spec: singular: authconfig --- -# Source: subchart1/templates/subdir/serviceaccount.yaml +# Source: subchart/templates/subdir/serviceaccount.yaml apiVersion: v1 kind: ServiceAccount metadata: - name: subchart1-sa + name: subchart-sa --- -# Source: subchart1/templates/subdir/role.yaml +# Source: subchart/templates/subdir/role.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: subchart1-role + name: subchart-role rules: - resources: ["*"] verbs: ["get","list","watch"] --- -# Source: subchart1/templates/subdir/rolebinding.yaml +# Source: subchart/templates/subdir/rolebinding.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: subchart1-binding + name: subchart-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: subchart1-role + name: subchart-role subjects: - kind: ServiceAccount - name: subchart1-sa + name: subchart-sa namespace: default --- -# Source: subchart1/charts/subcharta/templates/service.yaml +# Source: subchart/charts/subcharta/templates/service.yaml apiVersion: v1 kind: Service metadata: @@ -61,7 +61,7 @@ spec: selector: app.kubernetes.io/name: subcharta --- -# Source: subchart1/charts/subchartb/templates/service.yaml +# Source: subchart/charts/subchartb/templates/service.yaml apiVersion: v1 kind: Service metadata: @@ -78,13 +78,13 @@ spec: selector: app.kubernetes.io/name: subchartb --- -# Source: subchart1/templates/service.yaml +# Source: subchart/templates/service.yaml apiVersion: v1 kind: Service metadata: - name: subchart1 + name: subchart labels: - helm.sh/chart: "subchart1-0.1.0" + helm.sh/chart: "subchart-0.1.0" app.kubernetes.io/instance: "RELEASE-NAME" kube-version/major: "1" kube-version/minor: "18" @@ -98,4 +98,4 @@ spec: protocol: TCP name: nginx selector: - app.kubernetes.io/name: subchart1 + app.kubernetes.io/name: subchart diff --git a/cmd/helm/testdata/output/template.txt b/cmd/helm/testdata/output/template.txt index 82a21c5a1..9195f98b7 100644 --- a/cmd/helm/testdata/output/template.txt +++ b/cmd/helm/testdata/output/template.txt @@ -1,34 +1,34 @@ --- -# Source: subchart1/templates/subdir/serviceaccount.yaml +# Source: subchart/templates/subdir/serviceaccount.yaml apiVersion: v1 kind: ServiceAccount metadata: - name: subchart1-sa + name: subchart-sa --- -# Source: subchart1/templates/subdir/role.yaml +# Source: subchart/templates/subdir/role.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: subchart1-role + name: subchart-role rules: - resources: ["*"] verbs: ["get","list","watch"] --- -# Source: subchart1/templates/subdir/rolebinding.yaml +# Source: subchart/templates/subdir/rolebinding.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: subchart1-binding + name: subchart-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: subchart1-role + name: subchart-role subjects: - kind: ServiceAccount - name: subchart1-sa + name: subchart-sa namespace: default --- -# Source: subchart1/charts/subcharta/templates/service.yaml +# Source: subchart/charts/subcharta/templates/service.yaml apiVersion: v1 kind: Service metadata: @@ -45,7 +45,7 @@ spec: selector: app.kubernetes.io/name: subcharta --- -# Source: subchart1/charts/subchartb/templates/service.yaml +# Source: subchart/charts/subchartb/templates/service.yaml apiVersion: v1 kind: Service metadata: @@ -62,13 +62,13 @@ spec: selector: app.kubernetes.io/name: subchartb --- -# Source: subchart1/templates/service.yaml +# Source: subchart/templates/service.yaml apiVersion: v1 kind: Service metadata: - name: subchart1 + name: subchart labels: - helm.sh/chart: "subchart1-0.1.0" + helm.sh/chart: "subchart-0.1.0" app.kubernetes.io/instance: "RELEASE-NAME" kube-version/major: "1" kube-version/minor: "18" @@ -81,4 +81,4 @@ spec: protocol: TCP name: nginx selector: - app.kubernetes.io/name: subchart1 + app.kubernetes.io/name: subchart diff --git a/cmd/helm/testdata/testcharts/chart-with-no-templates-dir/values.yaml b/cmd/helm/testdata/testcharts/chart-with-no-templates-dir/values.yaml deleted file mode 100644 index ec82367be..000000000 --- a/cmd/helm/testdata/testcharts/chart-with-no-templates-dir/values.yaml +++ /dev/null @@ -1 +0,0 @@ -justAValue: "an example chart here" diff --git a/cmd/helm/testdata/testcharts/decompressedchart/.helmignore b/cmd/helm/testdata/testcharts/decompressedchart/.helmignore deleted file mode 100644 index 435b756d8..000000000 --- a/cmd/helm/testdata/testcharts/decompressedchart/.helmignore +++ /dev/null @@ -1,5 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -.git diff --git a/cmd/helm/testdata/testcharts/novals/Chart.yaml b/cmd/helm/testdata/testcharts/novals/Chart.yaml deleted file mode 100644 index a4282470b..000000000 --- a/cmd/helm/testdata/testcharts/novals/Chart.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -description: Deploy a basic Alpine Linux pod -home: https://helm.sh/helm -name: novals -sources: - - https://github.com/helm/helm -version: 0.2.0 -appVersion: 3.3 diff --git a/cmd/helm/testdata/testcharts/novals/README.md b/cmd/helm/testdata/testcharts/novals/README.md deleted file mode 100644 index fcf7ee017..000000000 --- a/cmd/helm/testdata/testcharts/novals/README.md +++ /dev/null @@ -1,13 +0,0 @@ -#Alpine: A simple Helm chart - -Run a single pod of Alpine Linux. - -This example was generated using the command `helm create alpine`. - -The `templates/` directory contains a very simple pod resource with a -couple of parameters. - -The `values.yaml` file contains the default values for the -`alpine-pod.yaml` template. - -You can install this example using `helm install ./alpine`. diff --git a/cmd/helm/testdata/testcharts/novals/templates/alpine-pod.yaml b/cmd/helm/testdata/testcharts/novals/templates/alpine-pod.yaml deleted file mode 100644 index 96c92d61d..000000000 --- a/cmd/helm/testdata/testcharts/novals/templates/alpine-pod.yaml +++ /dev/null @@ -1,28 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: "{{.Release.Name}}-{{.Values.Name}}" - labels: - # The "app.kubernetes.io/managed-by" label is used to track which tool - # deployed a given chart. It is useful for admins who want to see what - # releases a particular tool is responsible for. - app.kubernetes.io/managed-by: {{.Release.Service | quote }} - # The "app.kubernetes.io/instance" convention makes it easy to tie a release - # to all of the Kubernetes resources that were created as part of that - # release. - app.kubernetes.io/instance: {{.Release.Name | quote }} - app.kubernetes.io/version: {{ .Chart.AppVersion }} - # This makes it easy to audit chart usage. - helm.sh/chart: "{{.Chart.Name}}-{{.Chart.Version}}" - annotations: - "helm.sh/created": {{.Release.Time.Seconds | quote }} -spec: - # This shows how to use a simple value. This will look for a passed-in value - # called restartPolicy. If it is not found, it will use the default value. - # {{default "Never" .restartPolicy}} is a slightly optimized version of the - # more conventional syntax: {{.restartPolicy | default "Never"}} - restartPolicy: {{default "Never" .Values.restartPolicy}} - containers: - - name: waiter - image: "alpine:3.3" - command: ["/bin/sleep","9000"] diff --git a/cmd/helm/testdata/testcharts/subchart/Chart.yaml b/cmd/helm/testdata/testcharts/subchart/Chart.yaml new file mode 100644 index 000000000..b03ea3cd3 --- /dev/null +++ b/cmd/helm/testdata/testcharts/subchart/Chart.yaml @@ -0,0 +1,36 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: subchart +version: 0.1.0 +dependencies: + - name: subcharta + repository: http://localhost:10191 + version: 0.1.0 + condition: subcharta.enabled + tags: + - front-end + - subcharta + import-values: + - child: SCAdata + parent: imported-chartA + - child: SCAdata + parent: overridden-chartA + - child: SCAdata + parent: imported-chartA-B + + - name: subchartb + repository: http://localhost:10191 + version: 0.1.0 + condition: subchartb.enabled + import-values: + - child: SCBdata + parent: imported-chartB + - child: SCBdata + parent: imported-chartA-B + - child: exports.SCBexported2 + parent: exports.SCBexported2 + - SCBexported1 + + tags: + - front-end + - subchartb diff --git a/cmd/helm/testdata/testcharts/subchart/charts/subchartA/Chart.yaml b/cmd/helm/testdata/testcharts/subchart/charts/subchartA/Chart.yaml new file mode 100644 index 000000000..be3edcefb --- /dev/null +++ b/cmd/helm/testdata/testcharts/subchart/charts/subchartA/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: subcharta +version: 0.1.0 diff --git a/cmd/helm/testdata/testcharts/subchart/charts/subchartA/templates/service.yaml b/cmd/helm/testdata/testcharts/subchart/charts/subchartA/templates/service.yaml new file mode 100644 index 000000000..27501e1e0 --- /dev/null +++ b/cmd/helm/testdata/testcharts/subchart/charts/subchartA/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Chart.Name }} + labels: + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.externalPort }} + targetPort: {{ .Values.service.internalPort }} + protocol: TCP + name: {{ .Values.service.name }} + selector: + app.kubernetes.io/name: {{ .Chart.Name }} diff --git a/cmd/helm/testdata/testcharts/subchart/charts/subchartA/values.yaml b/cmd/helm/testdata/testcharts/subchart/charts/subchartA/values.yaml new file mode 100644 index 000000000..f0381ae6a --- /dev/null +++ b/cmd/helm/testdata/testcharts/subchart/charts/subchartA/values.yaml @@ -0,0 +1,17 @@ +# Default values for subchart. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +# subchartA +service: + name: apache + type: ClusterIP + externalPort: 80 + internalPort: 80 +SCAdata: + SCAbool: false + SCAfloat: 3.1 + SCAint: 55 + SCAstring: "jabba" + SCAnested1: + SCAnested2: true + diff --git a/cmd/helm/testdata/testcharts/subchart/charts/subchartB/Chart.yaml b/cmd/helm/testdata/testcharts/subchart/charts/subchartB/Chart.yaml new file mode 100644 index 000000000..c3c6bbaf0 --- /dev/null +++ b/cmd/helm/testdata/testcharts/subchart/charts/subchartB/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: subchartb +version: 0.1.0 diff --git a/cmd/helm/testdata/testcharts/subchart/charts/subchartB/templates/service.yaml b/cmd/helm/testdata/testcharts/subchart/charts/subchartB/templates/service.yaml new file mode 100644 index 000000000..27501e1e0 --- /dev/null +++ b/cmd/helm/testdata/testcharts/subchart/charts/subchartB/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Chart.Name }} + labels: + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.externalPort }} + targetPort: {{ .Values.service.internalPort }} + protocol: TCP + name: {{ .Values.service.name }} + selector: + app.kubernetes.io/name: {{ .Chart.Name }} diff --git a/cmd/helm/testdata/testcharts/subchart/charts/subchartB/values.yaml b/cmd/helm/testdata/testcharts/subchart/charts/subchartB/values.yaml new file mode 100644 index 000000000..774fdd75c --- /dev/null +++ b/cmd/helm/testdata/testcharts/subchart/charts/subchartB/values.yaml @@ -0,0 +1,35 @@ +# Default values for subchart. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +service: + name: nginx + type: ClusterIP + externalPort: 80 + internalPort: 80 + +SCBdata: + SCBbool: true + SCBfloat: 7.77 + SCBint: 33 + SCBstring: "boba" + +exports: + SCBexported1: + SCBexported1A: + SCBexported1B: 1965 + + SCBexported2: + SCBexported2A: "blaster" + +global: + kolla: + nova: + api: + all: + port: 8774 + metadata: + all: + port: 8775 + + + diff --git a/cmd/helm/testdata/testcharts/subchart/crds/crdA.yaml b/cmd/helm/testdata/testcharts/subchart/crds/crdA.yaml new file mode 100644 index 000000000..fca77fd4b --- /dev/null +++ b/cmd/helm/testdata/testcharts/subchart/crds/crdA.yaml @@ -0,0 +1,13 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: testCRDs +spec: + group: testCRDGroups + names: + kind: TestCRD + listKind: TestCRDList + plural: TestCRDs + shortNames: + - tc + singular: authconfig diff --git a/cmd/helm/testdata/testcharts/subchart/templates/NOTES.txt b/cmd/helm/testdata/testcharts/subchart/templates/NOTES.txt new file mode 100644 index 000000000..4bdf443f6 --- /dev/null +++ b/cmd/helm/testdata/testcharts/subchart/templates/NOTES.txt @@ -0,0 +1 @@ +Sample notes for {{ .Chart.Name }} \ No newline at end of file diff --git a/cmd/helm/testdata/testcharts/subchart/templates/service.yaml b/cmd/helm/testdata/testcharts/subchart/templates/service.yaml new file mode 100644 index 000000000..fee94dced --- /dev/null +++ b/cmd/helm/testdata/testcharts/subchart/templates/service.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Chart.Name }} + labels: + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app.kubernetes.io/instance: "{{ .Release.Name }}" + kube-version/major: "{{ .Capabilities.KubeVersion.Major }}" + kube-version/minor: "{{ .Capabilities.KubeVersion.Minor }}" + kube-version/version: "v{{ .Capabilities.KubeVersion.Major }}.{{ .Capabilities.KubeVersion.Minor }}.0" +{{- if .Capabilities.APIVersions.Has "helm.k8s.io/test" }} + kube-api-version/test: v1 +{{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.externalPort }} + targetPort: {{ .Values.service.internalPort }} + protocol: TCP + name: {{ .Values.service.name }} + selector: + app.kubernetes.io/name: {{ .Chart.Name }} diff --git a/cmd/helm/testdata/testcharts/subchart/templates/subdir/role.yaml b/cmd/helm/testdata/testcharts/subchart/templates/subdir/role.yaml new file mode 100644 index 000000000..91b954e5f --- /dev/null +++ b/cmd/helm/testdata/testcharts/subchart/templates/subdir/role.yaml @@ -0,0 +1,7 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ .Chart.Name }}-role +rules: +- resources: ["*"] + verbs: ["get","list","watch"] diff --git a/cmd/helm/testdata/testcharts/subchart/templates/subdir/rolebinding.yaml b/cmd/helm/testdata/testcharts/subchart/templates/subdir/rolebinding.yaml new file mode 100644 index 000000000..5d193f1a6 --- /dev/null +++ b/cmd/helm/testdata/testcharts/subchart/templates/subdir/rolebinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ .Chart.Name }}-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ .Chart.Name }}-role +subjects: +- kind: ServiceAccount + name: {{ .Chart.Name }}-sa + namespace: default diff --git a/cmd/helm/testdata/testcharts/subchart/templates/subdir/serviceaccount.yaml b/cmd/helm/testdata/testcharts/subchart/templates/subdir/serviceaccount.yaml new file mode 100644 index 000000000..7126c7d89 --- /dev/null +++ b/cmd/helm/testdata/testcharts/subchart/templates/subdir/serviceaccount.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Chart.Name }}-sa diff --git a/cmd/helm/testdata/testcharts/subchart/values.yaml b/cmd/helm/testdata/testcharts/subchart/values.yaml new file mode 100644 index 000000000..8a3ab6c64 --- /dev/null +++ b/cmd/helm/testdata/testcharts/subchart/values.yaml @@ -0,0 +1,55 @@ +# Default values for subchart. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +# subchart +service: + name: nginx + type: ClusterIP + externalPort: 80 + internalPort: 80 + + +SC1data: + SC1bool: true + SC1float: 3.14 + SC1int: 100 + SC1string: "dollywood" + SC1extra1: 11 + +imported-chartA: + SC1extra2: 1.337 + +overridden-chartA: + SCAbool: true + SCAfloat: 3.14 + SCAint: 100 + SCAstring: "jabbathehut" + SC1extra3: true + +imported-chartA-B: + SC1extra5: "tiller" + +overridden-chartA-B: + SCAbool: true + SCAfloat: 3.33 + SCAint: 555 + SCAstring: "wormwood" + SCAextra1: 23 + + SCBbool: true + SCBfloat: 0.25 + SCBint: 98 + SCBstring: "murkwood" + SCBextra1: 13 + + SC1extra6: 77 + +SCBexported1A: + SC1extra7: true + +exports: + SC1exported1: + global: + SC1exported2: + all: + SC1exported3: "SC1expstr" diff --git a/internal/resolver/resolver_test.go b/internal/resolver/resolver_test.go index bb3d3e6ac..0b0c3a6f8 100644 --- a/internal/resolver/resolver_test.go +++ b/internal/resolver/resolver_test.go @@ -74,18 +74,18 @@ func TestResolve(t *testing.T) { { name: "repo from valid local path", req: []*chart.Dependency{ - {Name: "signtest", Repository: "file://../../../../cmd/helm/testdata/testcharts/signtest", Version: "0.1.0"}, + {Name: "base", Repository: "file://base", Version: "0.1.0"}, }, expect: &chart.Lock{ Dependencies: []*chart.Dependency{ - {Name: "signtest", Repository: "file://../../../../cmd/helm/testdata/testcharts/signtest", Version: "0.1.0"}, + {Name: "base", Repository: "file://base", Version: "0.1.0"}, }, }, }, { name: "repo from invalid local path", req: []*chart.Dependency{ - {Name: "notexist", Repository: "file://../testdata/notexist", Version: "0.1.0"}, + {Name: "notexist", Repository: "file://testdata/notexist", Version: "0.1.0"}, }, err: true, }, @@ -232,9 +232,9 @@ func TestGetLocalPath(t *testing.T) { }, { name: "relative path", - repo: "file://../../../../cmd/helm/testdata/testcharts/signtest", + repo: "file://../../testdata/chartpath/base", chartpath: "foo/bar", - expect: "../../cmd/helm/testdata/testcharts/signtest", + expect: "testdata/chartpath/base", }, { name: "current directory path", @@ -244,13 +244,13 @@ func TestGetLocalPath(t *testing.T) { }, { name: "invalid local path", - repo: "file://../testdata/notexist", + repo: "file://testdata/notexist", chartpath: "testdata/chartpath", err: true, }, { name: "invalid path under current directory", - repo: "../charts/nonexistentdependency", + repo: "charts/nonexistentdependency", chartpath: "testdata/chartpath/charts", err: true, }, diff --git a/internal/resolver/testdata/chartpath/base/Chart.yaml b/internal/resolver/testdata/chartpath/base/Chart.yaml new file mode 100644 index 000000000..860b09091 --- /dev/null +++ b/internal/resolver/testdata/chartpath/base/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: base +version: 0.1.0 diff --git a/pkg/action/dependency_test.go b/pkg/action/dependency_test.go index 158acbfb9..4f3cb69a5 100644 --- a/pkg/action/dependency_test.go +++ b/pkg/action/dependency_test.go @@ -30,23 +30,23 @@ func TestList(t *testing.T) { }{ { chart: "testdata/charts/chart-with-compressed-dependencies", - golden: "output/compressed-deps.txt", + golden: "output/list-compressed-deps.txt", }, { chart: "testdata/charts/chart-with-compressed-dependencies-2.1.8.tgz", - golden: "output/compressed-deps-tgz.txt", + golden: "output/list-compressed-deps-tgz.txt", }, { chart: "testdata/charts/chart-with-uncompressed-dependencies", - golden: "output/uncompressed-deps.txt", + golden: "output/list-uncompressed-deps.txt", }, { chart: "testdata/charts/chart-with-uncompressed-dependencies-2.1.8.tgz", - golden: "output/uncompressed-deps-tgz.txt", + golden: "output/list-uncompressed-deps-tgz.txt", }, { chart: "testdata/charts/chart-missing-deps", - golden: "output/missing-deps.txt", + golden: "output/list-missing-deps.txt", }, } { buf := bytes.Buffer{} diff --git a/pkg/action/lint_test.go b/pkg/action/lint_test.go index 68d3c4bb4..1828461f3 100644 --- a/pkg/action/lint_test.go +++ b/pkg/action/lint_test.go @@ -24,10 +24,10 @@ var ( values = make(map[string]interface{}) namespace = "testNamespace" strict = false - chart1MultipleChartLint = "../../cmd/helm/testdata/testcharts/multiplecharts-lint-chart-1" - chart2MultipleChartLint = "../../cmd/helm/testdata/testcharts/multiplecharts-lint-chart-2" - corruptedTgzChart = "../../cmd/helm/testdata/testcharts/corrupted-compressed-chart.tgz" - chartWithNoTemplatesDir = "../../cmd/helm/testdata/testcharts/chart-with-no-templates-dir" + chart1MultipleChartLint = "testdata/charts/multiplecharts-lint-chart-1" + chart2MultipleChartLint = "testdata/charts/multiplecharts-lint-chart-2" + corruptedTgzChart = "testdata/charts/corrupted-compressed-chart.tgz" + chartWithNoTemplatesDir = "testdata/charts/chart-with-no-templates-dir" ) func TestLintChart(t *testing.T) { @@ -38,41 +38,41 @@ func TestLintChart(t *testing.T) { }{ { name: "decompressed-chart", - chartPath: "../../cmd/helm/testdata/testcharts/decompressedchart/", + chartPath: "testdata/charts/decompressedchart/", }, { name: "archived-chart-path", - chartPath: "../../cmd/helm/testdata/testcharts/compressedchart-0.1.0.tgz", + chartPath: "testdata/charts/compressedchart-0.1.0.tgz", }, { name: "archived-chart-path-with-hyphens", - chartPath: "../../cmd/helm/testdata/testcharts/compressedchart-with-hyphens-0.1.0.tgz", + chartPath: "testdata/charts/compressedchart-with-hyphens-0.1.0.tgz", }, { name: "archived-tar-gz-chart-path", - chartPath: "../../cmd/helm/testdata/testcharts/compressedchart-0.1.0.tar.gz", + chartPath: "testdata/charts/compressedchart-0.1.0.tar.gz", }, { name: "invalid-archived-chart-path", - chartPath: "../../cmd/helm/testdata/testcharts/invalidcompressedchart0.1.0.tgz", + chartPath: "testdata/charts/invalidcompressedchart0.1.0.tgz", err: true, }, { name: "chart-missing-manifest", - chartPath: "../../cmd/helm/testdata/testcharts/chart-missing-manifest", + chartPath: "testdata/charts/chart-missing-manifest", err: true, }, { name: "chart-with-schema", - chartPath: "../../cmd/helm/testdata/testcharts/chart-with-schema", + chartPath: "testdata/charts/chart-with-schema", }, { name: "chart-with-schema-negative", - chartPath: "../../cmd/helm/testdata/testcharts/chart-with-schema-negative", + chartPath: "testdata/charts/chart-with-schema-negative", }, { name: "pre-release-chart", - chartPath: "../../cmd/helm/testdata/testcharts/pre-release-chart-0.1.0-alpha.tgz", + chartPath: "testdata/charts/pre-release-chart-0.1.0-alpha.tgz", }, } diff --git a/pkg/action/show.go b/pkg/action/show.go index cc85477cd..9baa9cf43 100644 --- a/pkg/action/show.go +++ b/pkg/action/show.go @@ -54,6 +54,7 @@ type Show struct { ChartPathOptions Devel bool OutputFormat ShowOutputFormat + chart *chart.Chart // for testing } // NewShow creates a new Show object with the given configuration. @@ -65,25 +66,28 @@ func NewShow(output ShowOutputFormat) *Show { // Run executes 'helm show' against the given release. func (s *Show) Run(chartpath string) (string, error) { - var out strings.Builder - chrt, err := loader.Load(chartpath) - if err != nil { - return "", err + if s.chart == nil { + chrt, err := loader.Load(chartpath) + if err != nil { + return "", err + } + s.chart = chrt } - cf, err := yaml.Marshal(chrt.Metadata) + cf, err := yaml.Marshal(s.chart.Metadata) if err != nil { return "", err } + var out strings.Builder if s.OutputFormat == ShowChart || s.OutputFormat == ShowAll { fmt.Fprintf(&out, "%s\n", cf) } - if (s.OutputFormat == ShowValues || s.OutputFormat == ShowAll) && chrt.Values != nil { + if (s.OutputFormat == ShowValues || s.OutputFormat == ShowAll) && s.chart.Values != nil { if s.OutputFormat == ShowAll { fmt.Fprintln(&out, "---") } - for _, f := range chrt.Raw { + for _, f := range s.chart.Raw { if f.Name == chartutil.ValuesfileName { fmt.Fprintln(&out, string(f.Data)) } @@ -94,7 +98,7 @@ func (s *Show) Run(chartpath string) (string, error) { if s.OutputFormat == ShowAll { fmt.Fprintln(&out, "---") } - readme := findReadme(chrt.Files) + readme := findReadme(s.chart.Files) if readme == nil { return out.String(), nil } diff --git a/pkg/action/show_test.go b/pkg/action/show_test.go index 0a532746a..7be9daaa5 100644 --- a/pkg/action/show_test.go +++ b/pkg/action/show_test.go @@ -17,55 +17,50 @@ limitations under the License. package action import ( - "io/ioutil" - "strings" "testing" + + "helm.sh/helm/v3/pkg/chart" ) func TestShow(t *testing.T) { client := NewShow(ShowAll) - - output, err := client.Run("../../cmd/helm/testdata/testcharts/alpine") - if err != nil { - t.Fatal(err) + client.chart = &chart.Chart{ + Metadata: &chart.Metadata{Name: "alpine"}, + Files: []*chart.File{ + {Name: "README.md", Data: []byte("README\n")}, + }, + Raw: []*chart.File{ + {Name: "values.yaml", Data: []byte("VALUES\n")}, + }, + Values: map[string]interface{}{}, } - // Load the data from the textfixture directly. - cdata, err := ioutil.ReadFile("../../cmd/helm/testdata/testcharts/alpine/Chart.yaml") + output, err := client.Run("") if err != nil { t.Fatal(err) } - data, err := ioutil.ReadFile("../../cmd/helm/testdata/testcharts/alpine/values.yaml") - if err != nil { - t.Fatal(err) - } - readmeData, err := ioutil.ReadFile("../../cmd/helm/testdata/testcharts/alpine/README.md") - if err != nil { - t.Fatal(err) - } - parts := strings.SplitN(output, "---", 3) - if len(parts) != 3 { - t.Fatalf("Expected 2 parts, got %d", len(parts)) - } - expect := []string{ - strings.ReplaceAll(strings.TrimSpace(string(cdata)), "\r", ""), - strings.ReplaceAll(strings.TrimSpace(string(data)), "\r", ""), - strings.ReplaceAll(strings.TrimSpace(string(readmeData)), "\r", ""), - } + expect := `name: alpine + +--- +VALUES - // Problem: ghodss/yaml doesn't marshal into struct order. To solve, we - // have to carefully craft the Chart.yaml to match. - for i, got := range parts { - got = strings.ReplaceAll(strings.TrimSpace(got), "\r", "") - if got != expect[i] { - t.Errorf("Expected\n%q\nGot\n%q\n", expect[i], got) - } +--- +README + +` + if output != expect { + t.Errorf("Expected\n%q\nGot\n%q\n", expect, output) } +} + +func TestShowNoValues(t *testing.T) { + client := NewShow(ShowAll) + client.chart = new(chart.Chart) // Regression tests for missing values. See issue #1024. client.OutputFormat = ShowValues - output, err = client.Run("../../cmd/helm/testdata/testcharts/novals") + output, err := client.Run("") if err != nil { t.Fatal(err) } diff --git a/pkg/action/testdata/charts/chart-missing-deps/.helmignore b/pkg/action/testdata/charts/chart-missing-deps/.helmignore deleted file mode 100755 index e2cf7941f..000000000 --- a/pkg/action/testdata/charts/chart-missing-deps/.helmignore +++ /dev/null @@ -1,5 +0,0 @@ -.git -# OWNERS file for Kubernetes -OWNERS -# example production yaml -values-production.yaml \ No newline at end of file diff --git a/pkg/action/testdata/charts/chart-missing-deps/Chart.yaml b/pkg/action/testdata/charts/chart-missing-deps/Chart.yaml index 8304984fd..ba10ee803 100755 --- a/pkg/action/testdata/charts/chart-missing-deps/Chart.yaml +++ b/pkg/action/testdata/charts/chart-missing-deps/Chart.yaml @@ -1,20 +1,2 @@ -appVersion: 4.9.8 -description: Web publishing platform for building blogs and websites. -engine: gotpl -home: http://www.wordpress.com/ -icon: https://bitnami.com/assets/stacks/wordpress/img/wordpress-stack-220x234.png -keywords: -- wordpress -- cms -- blog -- http -- web -- application -- php -maintainers: -- email: containers@bitnami.com - name: bitnami-bot name: chart-with-missing-deps -sources: -- https://github.com/bitnami/bitnami-docker-wordpress version: 2.1.8 diff --git a/pkg/action/testdata/charts/chart-missing-deps/README.md b/pkg/action/testdata/charts/chart-missing-deps/README.md deleted file mode 100755 index 5859a17fa..000000000 --- a/pkg/action/testdata/charts/chart-missing-deps/README.md +++ /dev/null @@ -1,232 +0,0 @@ -# WordPress - -[WordPress](https://wordpress.org/) is one of the most versatile open source content management systems on the market. A publishing platform for building blogs and websites. - -## TL;DR; - -```console -$ helm install stable/wordpress -``` - -## Introduction - -This chart bootstraps a [WordPress](https://github.com/bitnami/bitnami-docker-wordpress) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. - -It also packages the [Bitnami MariaDB chart](https://github.com/kubernetes/charts/tree/master/stable/mariadb) which is required for bootstrapping a MariaDB deployment for the database requirements of the WordPress application. - -## Prerequisites - -- Kubernetes 1.4+ with Beta APIs enabled -- PV provisioner support in the underlying infrastructure - -## Installing the Chart - -To install the chart with the release name `my-release`: - -```console -$ helm install --name my-release stable/wordpress -``` - -The command deploys WordPress on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation. - -> **Tip**: List all releases using `helm list` - -## Uninstalling the Chart - -To uninstall/delete the `my-release` deployment: - -```console -$ helm delete my-release -``` - -The command removes all the Kubernetes components associated with the chart and deletes the release. - -## Configuration - -The following table lists the configurable parameters of the WordPress chart and their default values. - -| Parameter | Description | Default | -|----------------------------------|--------------------------------------------|---------------------------------------------------------| -| `image.registry` | WordPress image registry | `docker.io` | -| `image.repository` | WordPress image name | `bitnami/wordpress` | -| `image.tag` | WordPress image tag | `{VERSION}` | -| `image.pullPolicy` | Image pull policy | `Always` if `imageTag` is `latest`, else `IfNotPresent` | -| `image.pullSecrets` | Specify image pull secrets | `nil` | -| `wordpressUsername` | User of the application | `user` | -| `wordpressPassword` | Application password | _random 10 character long alphanumeric string_ | -| `wordpressEmail` | Admin email | `user@example.com` | -| `wordpressFirstName` | First name | `FirstName` | -| `wordpressLastName` | Last name | `LastName` | -| `wordpressBlogName` | Blog name | `User's Blog!` | -| `wordpressTablePrefix` | Table prefix | `wp_` | -| `allowEmptyPassword` | Allow DB blank passwords | `yes` | -| `smtpHost` | SMTP host | `nil` | -| `smtpPort` | SMTP port | `nil` | -| `smtpUser` | SMTP user | `nil` | -| `smtpPassword` | SMTP password | `nil` | -| `smtpUsername` | User name for SMTP emails | `nil` | -| `smtpProtocol` | SMTP protocol [`tls`, `ssl`] | `nil` | -| `replicaCount` | Number of WordPress Pods to run | `1` | -| `mariadb.enabled` | Deploy MariaDB container(s) | `true` | -| `mariadb.rootUser.password` | MariaDB admin password | `nil` | -| `mariadb.db.name` | Database name to create | `bitnami_wordpress` | -| `mariadb.db.user` | Database user to create | `bn_wordpress` | -| `mariadb.db.password` | Password for the database | _random 10 character long alphanumeric string_ | -| `externalDatabase.host` | Host of the external database | `localhost` | -| `externalDatabase.user` | Existing username in the external db | `bn_wordpress` | -| `externalDatabase.password` | Password for the above username | `nil` | -| `externalDatabase.database` | Name of the existing database | `bitnami_wordpress` | -| `externalDatabase.port` | Database port number | `3306` | -| `serviceType` | Kubernetes Service type | `LoadBalancer` | -| `serviceExternalTrafficPolicy` | Enable client source IP preservation | `Cluster` | -| `nodePorts.http` | Kubernetes http node port | `""` | -| `nodePorts.https` | Kubernetes https node port | `""` | -| `healthcheckHttps` | Use https for liveliness and readiness | `false` | -| `ingress.enabled` | Enable ingress controller resource | `false` | -| `ingress.hosts[0].name` | Hostname to your WordPress installation | `wordpress.local` | -| `ingress.hosts[0].path` | Path within the url structure | `/` | -| `ingress.hosts[0].tls` | Utilize TLS backend in ingress | `false` | -| `ingress.hosts[0].tlsSecret` | TLS Secret (certificates) | `wordpress.local-tls-secret` | -| `ingress.hosts[0].annotations` | Annotations for this host's ingress record | `[]` | -| `ingress.secrets[0].name` | TLS Secret Name | `nil` | -| `ingress.secrets[0].certificate` | TLS Secret Certificate | `nil` | -| `ingress.secrets[0].key` | TLS Secret Key | `nil` | -| `persistence.enabled` | Enable persistence using PVC | `true` | -| `persistence.existingClaim` | Enable persistence using an existing PVC | `nil` | -| `persistence.storageClass` | PVC Storage Class | `nil` (uses alpha storage class annotation) | -| `persistence.accessMode` | PVC Access Mode | `ReadWriteOnce` | -| `persistence.size` | PVC Storage Request | `10Gi` | -| `nodeSelector` | Node labels for pod assignment | `{}` | -| `tolerations` | List of node taints to tolerate | `[]` | -| `affinity` | Map of node/pod affinities | `{}` | - -The above parameters map to the env variables defined in [bitnami/wordpress](http://github.com/bitnami/bitnami-docker-wordpress). For more information please refer to the [bitnami/wordpress](http://github.com/bitnami/bitnami-docker-wordpress) image documentation. - -Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, - -```console -$ helm install --name my-release \ - --set wordpressUsername=admin,wordpressPassword=password,mariadb.mariadbRootPassword=secretpassword \ - stable/wordpress -``` - -The above command sets the WordPress administrator account username and password to `admin` and `password` respectively. Additionally, it sets the MariaDB `root` user password to `secretpassword`. - -Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, - -```console -$ helm install --name my-release -f values.yaml stable/wordpress -``` - -> **Tip**: You can use the default [values.yaml](values.yaml) - -## Production and horizontal scaling - -The following repo contains the recommended production settings for wordpress capture in an alternative [values file](values-production.yaml). Please read carefully the comments in the values-production.yaml file to set up your environment appropriately. - -To horizontally scale this chart, first download the [values-production.yaml](values-production.yaml) file to your local folder, then: - -```console -$ helm install --name my-release -f ./values-production.yaml stable/wordpress -``` - -Note that [values-production.yaml](values-production.yaml) includes a replicaCount of 3, so there will be 3 WordPress pods. As a result, to use the /admin portal and to ensure you can scale wordpress you need to provide a ReadWriteMany PVC, if you don't have a provisioner for this type of storage, we recommend that you install the nfs provisioner and map it to a RWO volume. - -```console -$ helm install stable/nfs-server-provisioner --set persistence.enabled=true,persistence.size=10Gi -$ helm install --name my-release -f values-production.yaml --set persistence.storageClass=nfs stable/wordpress -``` - -## Persistence - -The [Bitnami WordPress](https://github.com/bitnami/bitnami-docker-wordpress) image stores the WordPress data and configurations at the `/bitnami` path of the container. - -Persistent Volume Claims are used to keep the data across deployments. This is known to work in GCE, AWS, and minikube. -See the [Configuration](#configuration) section to configure the PVC or to disable persistence. - -## Using an external database - -Sometimes you may want to have Wordpress connect to an external database rather than installing one inside your cluster, e.g. to use a managed database service, or use run a single database server for all your applications. To do this, the chart allows you to specify credentials for an external database under the [`externalDatabase` parameter](#configuration). You should also disable the MariaDB installation with the `mariadb.enabled` option. For example: - -```console -$ helm install stable/wordpress \ - --set mariadb.enabled=false,externalDatabase.host=myexternalhost,externalDatabase.user=myuser,externalDatabase.password=mypassword,externalDatabase.database=mydatabase,externalDatabase.port=3306 -``` - -Note also if you disable MariaDB per above you MUST supply values for the `externalDatabase` connection. - -## Ingress - -This chart provides support for ingress resources. If you have an -ingress controller installed on your cluster, such as [nginx-ingress](https://kubeapps.com/charts/stable/nginx-ingress) -or [traefik](https://kubeapps.com/charts/stable/traefik) you can utilize -the ingress controller to serve your WordPress application. - -To enable ingress integration, please set `ingress.enabled` to `true` - -### Hosts - -Most likely you will only want to have one hostname that maps to this -WordPress installation, however, it is possible to have more than one -host. To facilitate this, the `ingress.hosts` object is an array. - -For each item, please indicate a `name`, `tls`, `tlsSecret`, and any -`annotations` that you may want the ingress controller to know about. - -Indicating TLS will cause WordPress to generate HTTPS URLs, and -WordPress will be connected to at port 443. The actual secret that -`tlsSecret` references do not have to be generated by this chart. -However, please note that if TLS is enabled, the ingress record will not -work until this secret exists. - -For annotations, please see [this document](https://github.com/kubernetes/ingress-nginx/blob/master/docs/annotations.md). -Not all annotations are supported by all ingress controllers, but this -document does a good job of indicating which annotation is supported by -many popular ingress controllers. - -### TLS Secrets - -This chart will facilitate the creation of TLS secrets for use with the -ingress controller, however, this is not required. There are three -common use cases: - -* helm generates/manages certificate secrets -* user generates/manages certificates separately -* an additional tool (like [kube-lego](https://kubeapps.com/charts/stable/kube-lego)) -manages the secrets for the application - -In the first two cases, one will need a certificate and a key. We would -expect them to look like this: - -* certificate files should look like (and there can be more than one -certificate if there is a certificate chain) - -``` ------BEGIN CERTIFICATE----- -MIID6TCCAtGgAwIBAgIJAIaCwivkeB5EMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV -... -jScrvkiBO65F46KioCL9h5tDvomdU1aqpI/CBzhvZn1c0ZTf87tGQR8NK7v7 ------END CERTIFICATE----- -``` -* keys should look like: -``` ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAvLYcyu8f3skuRyUgeeNpeDvYBCDcgq+LsWap6zbX5f8oLqp4 -... -wrj2wDbCDCFmfqnSJ+dKI3vFLlEz44sAV8jX/kd4Y6ZTQhlLbYc= ------END RSA PRIVATE KEY----- -```` - -If you are going to use Helm to manage the certificates, please copy -these values into the `certificate` and `key` values for a given -`ingress.secrets` entry. - -If you are going are going to manage TLS secrets outside of Helm, please -know that you can create a TLS secret by doing the following: - -``` -kubectl create secret tls wordpress.local-tls --key /path/to/key.key --cert /path/to/cert.crt -``` - -Please see [this example](https://github.com/kubernetes/contrib/tree/master/ingress/controllers/nginx/examples/tls) -for more information. diff --git a/pkg/action/testdata/charts/chart-missing-deps/templates/NOTES.txt b/pkg/action/testdata/charts/chart-missing-deps/templates/NOTES.txt deleted file mode 100755 index 55626e4d1..000000000 --- a/pkg/action/testdata/charts/chart-missing-deps/templates/NOTES.txt +++ /dev/null @@ -1,38 +0,0 @@ -1. Get the WordPress URL: - -{{- if .Values.ingress.enabled }} - - You should be able to access your new WordPress installation through - - {{- range .Values.ingress.hosts }} - {{ if .tls }}https{{ else }}http{{ end }}://{{ .name }}/admin - {{- end }} - -{{- else if contains "LoadBalancer" .Values.serviceType }} - - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "fullname" . }}' - - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') - echo "WordPress URL: http://$SERVICE_IP/" - echo "WordPress Admin URL: http://$SERVICE_IP/admin" - -{{- else if contains "ClusterIP" .Values.serviceType }} - - echo "WordPress URL: http://127.0.0.1:8080/" - echo "WordPress Admin URL: http://127.0.0.1:8080/admin" - kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ template "fullname" . }} 8080:80 - -{{- else if contains "NodePort" .Values.serviceType }} - - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "fullname" . }}) - export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") - echo "WordPress URL: http://$NODE_IP:$NODE_PORT/" - echo "WordPress Admin URL: http://$NODE_IP:$NODE_PORT/admin" - -{{- end }} - -2. Login with the following credentials to see your blog - - echo Username: {{ .Values.wordpressUsername }} - echo Password: $(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath="{.data.wordpress-password}" | base64 --decode) diff --git a/pkg/action/testdata/charts/chart-missing-deps/templates/_helpers.tpl b/pkg/action/testdata/charts/chart-missing-deps/templates/_helpers.tpl deleted file mode 100755 index 1e52d321c..000000000 --- a/pkg/action/testdata/charts/chart-missing-deps/templates/_helpers.tpl +++ /dev/null @@ -1,24 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -*/}} -{{- define "fullname" -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -*/}} -{{- define "mariadb.fullname" -}} -{{- printf "%s-%s" .Release.Name "mariadb" | trunc 63 | trimSuffix "-" -}} -{{- end -}} diff --git a/pkg/action/testdata/charts/chart-missing-deps/values.yaml b/pkg/action/testdata/charts/chart-missing-deps/values.yaml deleted file mode 100755 index 3cb66dafd..000000000 --- a/pkg/action/testdata/charts/chart-missing-deps/values.yaml +++ /dev/null @@ -1,254 +0,0 @@ -## Bitnami WordPress image version -## ref: https://hub.docker.com/r/bitnami/wordpress/tags/ -## -image: - registry: docker.io - repository: bitnami/wordpress - tag: 4.9.8-debian-9 - ## Specify a imagePullPolicy - ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' - ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images - ## - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## - # pullSecrets: - # - myRegistrKeySecretName - -## User of the application -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -## -wordpressUsername: user - -## Application password -## Defaults to a random 10-character alphanumeric string if not set -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -## -# wordpressPassword: - -## Admin email -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -## -wordpressEmail: user@example.com - -## First name -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -## -wordpressFirstName: FirstName - -## Last name -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -## -wordpressLastName: LastName - -## Blog name -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -## -wordpressBlogName: User's Blog! - -## Table prefix -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -## -wordpressTablePrefix: wp_ - -## Set to `yes` to allow the container to be started with blank passwords -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -allowEmptyPassword: yes - -## SMTP mail delivery configuration -## ref: https://github.com/bitnami/bitnami-docker-wordpress/#smtp-configuration -## -# smtpHost: -# smtpPort: -# smtpUser: -# smtpPassword: -# smtpUsername: -# smtpProtocol: - -replicaCount: 1 - -externalDatabase: -## All of these values are only used when mariadb.enabled is set to false - ## Database host - host: localhost - - ## non-root Username for Wordpress Database - user: bn_wordpress - - ## Database password - password: "" - - ## Database name - database: bitnami_wordpress - - ## Database port number - port: 3306 - -## -## MariaDB chart configuration -## -mariadb: - ## Whether to deploy a mariadb server to satisfy the applications database requirements. To use an external database set this to false and configure the externalDatabase parameters - enabled: true - ## Disable MariaDB replication - replication: - enabled: false - - ## Create a database and a database user - ## ref: https://github.com/bitnami/bitnami-docker-mariadb/blob/master/README.md#creating-a-database-user-on-first-run - ## - db: - name: bitnami_wordpress - user: bn_wordpress - ## If the password is not specified, mariadb will generates a random password - ## - # password: - - ## MariaDB admin password - ## ref: https://github.com/bitnami/bitnami-docker-mariadb/blob/master/README.md#setting-the-root-password-on-first-run - ## - # rootUser: - # password: - - ## Enable persistence using Persistent Volume Claims - ## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/ - ## - master: - persistence: - enabled: true - ## mariadb data Persistent Volume Storage Class - ## If defined, storageClassName: - ## If set to "-", storageClassName: "", which disables dynamic provisioning - ## If undefined (the default) or set to null, no storageClassName spec is - ## set, choosing the default provisioner. (gp2 on AWS, standard on - ## GKE, AWS & OpenStack) - ## - # storageClass: "-" - accessMode: ReadWriteOnce - size: 8Gi - -## Kubernetes configuration -## For minikube, set this to NodePort, elsewhere use LoadBalancer or ClusterIP -## -serviceType: LoadBalancer -## -## serviceType: NodePort -## nodePorts: -## http: -## https: -nodePorts: - http: "" - https: "" -## Enable client source IP preservation -## ref http://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip -## -serviceExternalTrafficPolicy: Cluster - -## Allow health checks to be pointed at the https port -healthcheckHttps: false - -## Configure extra options for liveness and readiness probes -## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) -livenessProbe: - initialDelaySeconds: 120 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 -readinessProbe: - initialDelaySeconds: 30 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - -## Configure the ingress resource that allows you to access the -## Wordpress installation. Set up the URL -## ref: http://kubernetes.io/docs/user-guide/ingress/ -## -ingress: - ## Set to true to enable ingress record generation - enabled: false - - ## The list of hostnames to be covered with this ingress record. - ## Most likely this will be just one host, but in the event more hosts are needed, this is an array - hosts: - - name: wordpress.local - - ## Set this to true in order to enable TLS on the ingress record - ## A side effect of this will be that the backend wordpress service will be connected at port 443 - tls: false - - ## If TLS is set to true, you must declare what secret will store the key/certificate for TLS - tlsSecret: wordpress.local-tls - - ## Ingress annotations done as key:value pairs - ## If you're using kube-lego, you will want to add: - ## kubernetes.io/tls-acme: true - ## - ## For a full list of possible ingress annotations, please see - ## ref: https://github.com/kubernetes/ingress-nginx/blob/master/docs/annotations.md - ## - ## If tls is set to true, annotation ingress.kubernetes.io/secure-backends: "true" will automatically be set - annotations: - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: true - - secrets: - ## If you're providing your own certificates, please use this to add the certificates as secrets - ## key and certificate should start with -----BEGIN CERTIFICATE----- or - ## -----BEGIN RSA PRIVATE KEY----- - ## - ## name should line up with a tlsSecret set further up - ## If you're using kube-lego, this is unneeded, as it will create the secret for you if it is not set - ## - ## It is also possible to create and manage the certificates outside of this helm chart - ## Please see README.md for more information - # - name: wordpress.local-tls - # key: - # certificate: - -## Enable persistence using Persistent Volume Claims -## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/ -## -persistence: - enabled: true - ## wordpress data Persistent Volume Storage Class - ## If defined, storageClassName: - ## If set to "-", storageClassName: "", which disables dynamic provisioning - ## If undefined (the default) or set to null, no storageClassName spec is - ## set, choosing the default provisioner. (gp2 on AWS, standard on - ## GKE, AWS & OpenStack) - ## - # storageClass: "-" - ## - ## If you want to reuse an existing claim, you can pass the name of the PVC using - ## the existingClaim variable - # existingClaim: your-claim - accessMode: ReadWriteOnce - size: 10Gi - -## Configure resource requests and limits -## ref: http://kubernetes.io/docs/user-guide/compute-resources/ -## -resources: - requests: - memory: 512Mi - cpu: 300m - -## Node labels for pod assignment -## Ref: https://kubernetes.io/docs/user-guide/node-selection/ -## -nodeSelector: {} - -## Tolerations for pod assignment -## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ -## -tolerations: [] - -## Affinity for pod assignment -## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity -## -affinity: {} diff --git a/pkg/action/testdata/charts/chart-with-compressed-dependencies/.helmignore b/pkg/action/testdata/charts/chart-with-compressed-dependencies/.helmignore deleted file mode 100755 index e2cf7941f..000000000 --- a/pkg/action/testdata/charts/chart-with-compressed-dependencies/.helmignore +++ /dev/null @@ -1,5 +0,0 @@ -.git -# OWNERS file for Kubernetes -OWNERS -# example production yaml -values-production.yaml \ No newline at end of file diff --git a/pkg/action/testdata/charts/chart-with-compressed-dependencies/Chart.yaml b/pkg/action/testdata/charts/chart-with-compressed-dependencies/Chart.yaml index 602644caa..1d16590b6 100755 --- a/pkg/action/testdata/charts/chart-with-compressed-dependencies/Chart.yaml +++ b/pkg/action/testdata/charts/chart-with-compressed-dependencies/Chart.yaml @@ -1,20 +1,2 @@ -appVersion: 4.9.8 -description: Web publishing platform for building blogs and websites. -engine: gotpl -home: http://www.wordpress.com/ -icon: https://bitnami.com/assets/stacks/wordpress/img/wordpress-stack-220x234.png -keywords: -- wordpress -- cms -- blog -- http -- web -- application -- php -maintainers: -- email: containers@bitnami.com - name: bitnami-bot name: chart-with-compressed-dependencies -sources: -- https://github.com/bitnami/bitnami-docker-wordpress version: 2.1.8 diff --git a/pkg/action/testdata/charts/chart-with-compressed-dependencies/README.md b/pkg/action/testdata/charts/chart-with-compressed-dependencies/README.md deleted file mode 100755 index 3174417e0..000000000 --- a/pkg/action/testdata/charts/chart-with-compressed-dependencies/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# WordPress - -This is a testing fork of the Wordpress chart. It is not operational. diff --git a/pkg/action/testdata/charts/chart-with-compressed-dependencies/templates/NOTES.txt b/pkg/action/testdata/charts/chart-with-compressed-dependencies/templates/NOTES.txt deleted file mode 100755 index 3b94f9157..000000000 --- a/pkg/action/testdata/charts/chart-with-compressed-dependencies/templates/NOTES.txt +++ /dev/null @@ -1 +0,0 @@ -Placeholder diff --git a/pkg/action/testdata/charts/chart-with-compressed-dependencies/values.yaml b/pkg/action/testdata/charts/chart-with-compressed-dependencies/values.yaml deleted file mode 100755 index 3cb66dafd..000000000 --- a/pkg/action/testdata/charts/chart-with-compressed-dependencies/values.yaml +++ /dev/null @@ -1,254 +0,0 @@ -## Bitnami WordPress image version -## ref: https://hub.docker.com/r/bitnami/wordpress/tags/ -## -image: - registry: docker.io - repository: bitnami/wordpress - tag: 4.9.8-debian-9 - ## Specify a imagePullPolicy - ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' - ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images - ## - pullPolicy: IfNotPresent - ## Optionally specify an array of imagePullSecrets. - ## Secrets must be manually created in the namespace. - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ - ## - # pullSecrets: - # - myRegistrKeySecretName - -## User of the application -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -## -wordpressUsername: user - -## Application password -## Defaults to a random 10-character alphanumeric string if not set -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -## -# wordpressPassword: - -## Admin email -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -## -wordpressEmail: user@example.com - -## First name -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -## -wordpressFirstName: FirstName - -## Last name -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -## -wordpressLastName: LastName - -## Blog name -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -## -wordpressBlogName: User's Blog! - -## Table prefix -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -## -wordpressTablePrefix: wp_ - -## Set to `yes` to allow the container to be started with blank passwords -## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables -allowEmptyPassword: yes - -## SMTP mail delivery configuration -## ref: https://github.com/bitnami/bitnami-docker-wordpress/#smtp-configuration -## -# smtpHost: -# smtpPort: -# smtpUser: -# smtpPassword: -# smtpUsername: -# smtpProtocol: - -replicaCount: 1 - -externalDatabase: -## All of these values are only used when mariadb.enabled is set to false - ## Database host - host: localhost - - ## non-root Username for Wordpress Database - user: bn_wordpress - - ## Database password - password: "" - - ## Database name - database: bitnami_wordpress - - ## Database port number - port: 3306 - -## -## MariaDB chart configuration -## -mariadb: - ## Whether to deploy a mariadb server to satisfy the applications database requirements. To use an external database set this to false and configure the externalDatabase parameters - enabled: true - ## Disable MariaDB replication - replication: - enabled: false - - ## Create a database and a database user - ## ref: https://github.com/bitnami/bitnami-docker-mariadb/blob/master/README.md#creating-a-database-user-on-first-run - ## - db: - name: bitnami_wordpress - user: bn_wordpress - ## If the password is not specified, mariadb will generates a random password - ## - # password: - - ## MariaDB admin password - ## ref: https://github.com/bitnami/bitnami-docker-mariadb/blob/master/README.md#setting-the-root-password-on-first-run - ## - # rootUser: - # password: - - ## Enable persistence using Persistent Volume Claims - ## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/ - ## - master: - persistence: - enabled: true - ## mariadb data Persistent Volume Storage Class - ## If defined, storageClassName: - ## If set to "-", storageClassName: "", which disables dynamic provisioning - ## If undefined (the default) or set to null, no storageClassName spec is - ## set, choosing the default provisioner. (gp2 on AWS, standard on - ## GKE, AWS & OpenStack) - ## - # storageClass: "-" - accessMode: ReadWriteOnce - size: 8Gi - -## Kubernetes configuration -## For minikube, set this to NodePort, elsewhere use LoadBalancer or ClusterIP -## -serviceType: LoadBalancer -## -## serviceType: NodePort -## nodePorts: -## http: -## https: -nodePorts: - http: "" - https: "" -## Enable client source IP preservation -## ref http://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip -## -serviceExternalTrafficPolicy: Cluster - -## Allow health checks to be pointed at the https port -healthcheckHttps: false - -## Configure extra options for liveness and readiness probes -## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) -livenessProbe: - initialDelaySeconds: 120 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 -readinessProbe: - initialDelaySeconds: 30 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 6 - successThreshold: 1 - -## Configure the ingress resource that allows you to access the -## Wordpress installation. Set up the URL -## ref: http://kubernetes.io/docs/user-guide/ingress/ -## -ingress: - ## Set to true to enable ingress record generation - enabled: false - - ## The list of hostnames to be covered with this ingress record. - ## Most likely this will be just one host, but in the event more hosts are needed, this is an array - hosts: - - name: wordpress.local - - ## Set this to true in order to enable TLS on the ingress record - ## A side effect of this will be that the backend wordpress service will be connected at port 443 - tls: false - - ## If TLS is set to true, you must declare what secret will store the key/certificate for TLS - tlsSecret: wordpress.local-tls - - ## Ingress annotations done as key:value pairs - ## If you're using kube-lego, you will want to add: - ## kubernetes.io/tls-acme: true - ## - ## For a full list of possible ingress annotations, please see - ## ref: https://github.com/kubernetes/ingress-nginx/blob/master/docs/annotations.md - ## - ## If tls is set to true, annotation ingress.kubernetes.io/secure-backends: "true" will automatically be set - annotations: - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: true - - secrets: - ## If you're providing your own certificates, please use this to add the certificates as secrets - ## key and certificate should start with -----BEGIN CERTIFICATE----- or - ## -----BEGIN RSA PRIVATE KEY----- - ## - ## name should line up with a tlsSecret set further up - ## If you're using kube-lego, this is unneeded, as it will create the secret for you if it is not set - ## - ## It is also possible to create and manage the certificates outside of this helm chart - ## Please see README.md for more information - # - name: wordpress.local-tls - # key: - # certificate: - -## Enable persistence using Persistent Volume Claims -## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/ -## -persistence: - enabled: true - ## wordpress data Persistent Volume Storage Class - ## If defined, storageClassName: - ## If set to "-", storageClassName: "", which disables dynamic provisioning - ## If undefined (the default) or set to null, no storageClassName spec is - ## set, choosing the default provisioner. (gp2 on AWS, standard on - ## GKE, AWS & OpenStack) - ## - # storageClass: "-" - ## - ## If you want to reuse an existing claim, you can pass the name of the PVC using - ## the existingClaim variable - # existingClaim: your-claim - accessMode: ReadWriteOnce - size: 10Gi - -## Configure resource requests and limits -## ref: http://kubernetes.io/docs/user-guide/compute-resources/ -## -resources: - requests: - memory: 512Mi - cpu: 300m - -## Node labels for pod assignment -## Ref: https://kubernetes.io/docs/user-guide/node-selection/ -## -nodeSelector: {} - -## Tolerations for pod assignment -## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ -## -tolerations: [] - -## Affinity for pod assignment -## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity -## -affinity: {} diff --git a/cmd/helm/testdata/testcharts/chart-with-no-templates-dir/Chart.yaml b/pkg/action/testdata/charts/chart-with-no-templates-dir/Chart.yaml similarity index 100% rename from cmd/helm/testdata/testcharts/chart-with-no-templates-dir/Chart.yaml rename to pkg/action/testdata/charts/chart-with-no-templates-dir/Chart.yaml diff --git a/pkg/action/testdata/charts/chart-with-schema-negative/Chart.yaml b/pkg/action/testdata/charts/chart-with-schema-negative/Chart.yaml new file mode 100644 index 000000000..395d24f6a --- /dev/null +++ b/pkg/action/testdata/charts/chart-with-schema-negative/Chart.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +description: Empty testing chart +home: https://k8s.io/helm +name: empty +sources: +- https://github.com/kubernetes/helm +version: 0.1.0 diff --git a/pkg/action/testdata/charts/chart-with-schema-negative/templates/empty.yaml b/pkg/action/testdata/charts/chart-with-schema-negative/templates/empty.yaml new file mode 100644 index 000000000..c80812f6e --- /dev/null +++ b/pkg/action/testdata/charts/chart-with-schema-negative/templates/empty.yaml @@ -0,0 +1 @@ +# This file is intentionally blank diff --git a/pkg/action/testdata/charts/chart-with-schema-negative/values.schema.json b/pkg/action/testdata/charts/chart-with-schema-negative/values.schema.json new file mode 100644 index 000000000..4df89bbe8 --- /dev/null +++ b/pkg/action/testdata/charts/chart-with-schema-negative/values.schema.json @@ -0,0 +1,67 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "addresses": { + "description": "List of addresses", + "items": { + "properties": { + "city": { + "type": "string" + }, + "number": { + "type": "number" + }, + "street": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "age": { + "description": "Age", + "minimum": 0, + "type": "integer" + }, + "employmentInfo": { + "properties": { + "salary": { + "minimum": 0, + "type": "number" + }, + "title": { + "type": "string" + } + }, + "required": [ + "salary" + ], + "type": "object" + }, + "firstname": { + "description": "First name", + "type": "string" + }, + "lastname": { + "type": "string" + }, + "likesCoffee": { + "type": "boolean" + }, + "phoneNumbers": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "firstname", + "lastname", + "addresses", + "employmentInfo" + ], + "title": "Values", + "type": "object" +} diff --git a/pkg/action/testdata/charts/chart-with-schema-negative/values.yaml b/pkg/action/testdata/charts/chart-with-schema-negative/values.yaml new file mode 100644 index 000000000..5a1250bff --- /dev/null +++ b/pkg/action/testdata/charts/chart-with-schema-negative/values.yaml @@ -0,0 +1,14 @@ +firstname: John +lastname: Doe +age: -5 +likesCoffee: true +addresses: + - city: Springfield + street: Main + number: 12345 + - city: New York + street: Broadway + number: 67890 +phoneNumbers: + - "(888) 888-8888" + - "(555) 555-5555" diff --git a/pkg/action/testdata/charts/chart-with-schema/Chart.yaml b/pkg/action/testdata/charts/chart-with-schema/Chart.yaml new file mode 100644 index 000000000..395d24f6a --- /dev/null +++ b/pkg/action/testdata/charts/chart-with-schema/Chart.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +description: Empty testing chart +home: https://k8s.io/helm +name: empty +sources: +- https://github.com/kubernetes/helm +version: 0.1.0 diff --git a/pkg/action/testdata/charts/chart-with-schema/extra-values.yaml b/pkg/action/testdata/charts/chart-with-schema/extra-values.yaml new file mode 100644 index 000000000..76c290c4f --- /dev/null +++ b/pkg/action/testdata/charts/chart-with-schema/extra-values.yaml @@ -0,0 +1,2 @@ +age: -5 +employmentInfo: null diff --git a/pkg/action/testdata/charts/chart-with-schema/templates/empty.yaml b/pkg/action/testdata/charts/chart-with-schema/templates/empty.yaml new file mode 100644 index 000000000..c80812f6e --- /dev/null +++ b/pkg/action/testdata/charts/chart-with-schema/templates/empty.yaml @@ -0,0 +1 @@ +# This file is intentionally blank diff --git a/pkg/action/testdata/charts/chart-with-schema/values.schema.json b/pkg/action/testdata/charts/chart-with-schema/values.schema.json new file mode 100644 index 000000000..4df89bbe8 --- /dev/null +++ b/pkg/action/testdata/charts/chart-with-schema/values.schema.json @@ -0,0 +1,67 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "addresses": { + "description": "List of addresses", + "items": { + "properties": { + "city": { + "type": "string" + }, + "number": { + "type": "number" + }, + "street": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "age": { + "description": "Age", + "minimum": 0, + "type": "integer" + }, + "employmentInfo": { + "properties": { + "salary": { + "minimum": 0, + "type": "number" + }, + "title": { + "type": "string" + } + }, + "required": [ + "salary" + ], + "type": "object" + }, + "firstname": { + "description": "First name", + "type": "string" + }, + "lastname": { + "type": "string" + }, + "likesCoffee": { + "type": "boolean" + }, + "phoneNumbers": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "firstname", + "lastname", + "addresses", + "employmentInfo" + ], + "title": "Values", + "type": "object" +} diff --git a/pkg/action/testdata/charts/chart-with-schema/values.yaml b/pkg/action/testdata/charts/chart-with-schema/values.yaml new file mode 100644 index 000000000..042dea664 --- /dev/null +++ b/pkg/action/testdata/charts/chart-with-schema/values.yaml @@ -0,0 +1,17 @@ +firstname: John +lastname: Doe +age: 25 +likesCoffee: true +employmentInfo: + title: Software Developer + salary: 100000 +addresses: + - city: Springfield + street: Main + number: 12345 + - city: New York + street: Broadway + number: 67890 +phoneNumbers: + - "(888) 888-8888" + - "(555) 555-5555" diff --git a/pkg/action/testdata/charts/compressedchart-0.1.0.tar.gz b/pkg/action/testdata/charts/compressedchart-0.1.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..3c9c24d76063d6a904405b2d6a7a84cb087f1ce4 GIT binary patch literal 477 zcmV<30V4h%iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PL4vi_<_5!26s}F{UjHhD>x0Xejw~|-egB1QU=&JEdrHEIt>CEtv%dd}n=<=92zSKn;o(8OM@#S> zYFc5(0#_R!xxRXQ%zfa$rtiOMiLGgzk94**j`?3M7Jt0|r`i8O7{f;tq39Bbhr@%1 zO-l}zo#EQJ1_D-Jv7w}jF??!Gg4BiJqa;WzF+;Dc zVQyr3R8em|NM&qo0PL4vi_<_5!26s}F{UjHhD>x0Xejw~|-egB1QU=&JEdrHEIt>CEtv%dd}n=<=92zSKn;o(8OM@#S> zYFc5(0#_R!xxRXQ%zfa$rtiOMiLGgzk94**j`?3M7Jt0|r`i8O7{f;tq39Bbhr@%1 zO-l}zo#EQJ1_D-Jv7w}jF??!Gg4BiJqa;WzF+;Dc zVQyr3R8em|NM&qo0PL4vi_<_5!26s}F)eG5__n?E62T&$9nR zaPZh}uYVQ7^}*#!N0u3azW+itFbbuoJtg79R&dn+S>OM~O_}{4ggavP@bIACqb2wb zHLb8?fvb&=Twgst=05OW)AwJs#MU&^XY$NVoBi$C7~)9n8sjNv1SP;?2z!{Nch zrX>f<&Tws90|BeA*icf%7(TToLFz*AQ4*wspoCYeko Tb2>i)00960YK^g$02BZKS`FmP literal 0 HcmV?d00001 diff --git a/pkg/action/testdata/charts/compressedchart-0.3.0.tgz b/pkg/action/testdata/charts/compressedchart-0.3.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..051bd6fd9a030a3f4327e8002a8912c1f5f68050 GIT binary patch literal 477 zcmV<30V4h%iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PL4vi_<_5!26s}Fj!(#55d%N%6r{|dRMblL`R$bVgxL;q*9Y4-md z>^-)d>tBU%y?6Q2k!8-o(0?Ht7=_Z)o|156D>&%?bm;&5rp*4Ig*#&Q@bIACqb2wb z4K1-}fvdHT++00A=05OWGxT3|#MZRVM>^RWhx{++^FQAIRrdcZjNv1SP;?2z!~Vg; zx+4dR-f&}F3jyn|*iur(7(R6-LFz;BQ4*w%n4x9A0E<$0#EPK51s@!5z`Na*+mIko1U8OTq2AtqxfdU)P_4<|CYeko Tb38u+00960Q~zm}02BZK0h8&p literal 0 HcmV?d00001 diff --git a/pkg/action/testdata/charts/compressedchart-with-hyphens-0.1.0.tgz b/pkg/action/testdata/charts/compressedchart-with-hyphens-0.1.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..379210a92c1795429d2c4baae389f1e971f26824 GIT binary patch literal 548 zcmV+<0^9u`iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PL4fi`y^|#dG$jc->rDXjD0A64=|)92WW)wwIoYVoz*QSrU?* zG;H^~7dcDXrjTqgP3fZFMMBsbi zPWu0B_M89nr2n%p#E0nPPIpGV%QZGNX)If*N~tSYQG5|qH0t|nfN!leE_nEwltQJ< z5{(E&Ep_!Aj+6*;9W6i9KdlR0WlY0RR8Xa#gbc6aWCh@%&~0 literal 0 HcmV?d00001 diff --git a/cmd/helm/testdata/testcharts/corrupted-compressed-chart.tgz b/pkg/action/testdata/charts/corrupted-compressed-chart.tgz similarity index 100% rename from cmd/helm/testdata/testcharts/corrupted-compressed-chart.tgz rename to pkg/action/testdata/charts/corrupted-compressed-chart.tgz diff --git a/cmd/helm/testdata/testcharts/decompressedchart/Chart.yaml b/pkg/action/testdata/charts/decompressedchart/Chart.yaml similarity index 100% rename from cmd/helm/testdata/testcharts/decompressedchart/Chart.yaml rename to pkg/action/testdata/charts/decompressedchart/Chart.yaml diff --git a/cmd/helm/testdata/testcharts/decompressedchart/values.yaml b/pkg/action/testdata/charts/decompressedchart/values.yaml similarity index 100% rename from cmd/helm/testdata/testcharts/decompressedchart/values.yaml rename to pkg/action/testdata/charts/decompressedchart/values.yaml diff --git a/cmd/helm/testdata/testcharts/multiplecharts-lint-chart-1/Chart.yaml b/pkg/action/testdata/charts/multiplecharts-lint-chart-1/Chart.yaml similarity index 100% rename from cmd/helm/testdata/testcharts/multiplecharts-lint-chart-1/Chart.yaml rename to pkg/action/testdata/charts/multiplecharts-lint-chart-1/Chart.yaml diff --git a/cmd/helm/testdata/testcharts/multiplecharts-lint-chart-1/templates/configmap.yaml b/pkg/action/testdata/charts/multiplecharts-lint-chart-1/templates/configmap.yaml similarity index 100% rename from cmd/helm/testdata/testcharts/multiplecharts-lint-chart-1/templates/configmap.yaml rename to pkg/action/testdata/charts/multiplecharts-lint-chart-1/templates/configmap.yaml diff --git a/cmd/helm/testdata/testcharts/multiplecharts-lint-chart-1/values.yaml b/pkg/action/testdata/charts/multiplecharts-lint-chart-1/values.yaml similarity index 100% rename from cmd/helm/testdata/testcharts/multiplecharts-lint-chart-1/values.yaml rename to pkg/action/testdata/charts/multiplecharts-lint-chart-1/values.yaml diff --git a/cmd/helm/testdata/testcharts/multiplecharts-lint-chart-2/Chart.yaml b/pkg/action/testdata/charts/multiplecharts-lint-chart-2/Chart.yaml similarity index 100% rename from cmd/helm/testdata/testcharts/multiplecharts-lint-chart-2/Chart.yaml rename to pkg/action/testdata/charts/multiplecharts-lint-chart-2/Chart.yaml diff --git a/cmd/helm/testdata/testcharts/multiplecharts-lint-chart-2/templates/configmap.yaml b/pkg/action/testdata/charts/multiplecharts-lint-chart-2/templates/configmap.yaml similarity index 100% rename from cmd/helm/testdata/testcharts/multiplecharts-lint-chart-2/templates/configmap.yaml rename to pkg/action/testdata/charts/multiplecharts-lint-chart-2/templates/configmap.yaml diff --git a/cmd/helm/testdata/testcharts/multiplecharts-lint-chart-2/values.yaml b/pkg/action/testdata/charts/multiplecharts-lint-chart-2/values.yaml similarity index 100% rename from cmd/helm/testdata/testcharts/multiplecharts-lint-chart-2/values.yaml rename to pkg/action/testdata/charts/multiplecharts-lint-chart-2/values.yaml diff --git a/pkg/action/testdata/charts/pre-release-chart-0.1.0-alpha.tgz b/pkg/action/testdata/charts/pre-release-chart-0.1.0-alpha.tgz new file mode 100644 index 0000000000000000000000000000000000000000..5d5770fed227de5f776eb9080eb377aad6293c1b GIT binary patch literal 355 zcmV-p0i6CHiwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PK{zYV$x4g;nb*23$-3NWU)N&csC^NtY(&SQ_DlU9Ff|8T|G^ za%V#lh=@thS7=o1ZFbK&gK#2jnUs^}ND}@%OyBfO&PEG?h*+29ToLiQVwP7?_P@yL zI1Ma8b~7i_FmV`{SsQ%M$8b5@3*jnN45@T9YE&=p2h=9&w(}W z$?+C$9uN+r2y|ofk(Ta0{KWJPp`$V@VjMq`0UE1~Q@$ zJRGL~X*n=`@No8{Kwvjm3an`imvnLG Date: Sun, 15 Dec 2019 20:13:56 +0530 Subject: [PATCH 069/159] Show errors when linting for Chart.yaml version and appVersion fields of type non-string Signed-off-by: Karuppiah Natarajan --- .../multiplecharts-lint-chart-1/Chart.yaml | 2 +- .../multiplecharts-lint-chart-2/Chart.yaml | 2 +- pkg/lint/rules/chartfile.go | 42 ++++++++++ pkg/lint/rules/chartfile_test.go | 78 +++++++++++++------ .../testdata/anotherbadchartfile/Chart.yaml | 15 ++++ 5 files changed, 112 insertions(+), 27 deletions(-) create mode 100644 pkg/lint/rules/testdata/anotherbadchartfile/Chart.yaml diff --git a/pkg/action/testdata/charts/multiplecharts-lint-chart-1/Chart.yaml b/pkg/action/testdata/charts/multiplecharts-lint-chart-1/Chart.yaml index 3b342ae4f..e33c97e8c 100644 --- a/pkg/action/testdata/charts/multiplecharts-lint-chart-1/Chart.yaml +++ b/pkg/action/testdata/charts/multiplecharts-lint-chart-1/Chart.yaml @@ -1,4 +1,4 @@ apiVersion: v1 name: multiplecharts-lint-chart-1 -version: 1 +version: "1" icon: "" \ No newline at end of file diff --git a/pkg/action/testdata/charts/multiplecharts-lint-chart-2/Chart.yaml b/pkg/action/testdata/charts/multiplecharts-lint-chart-2/Chart.yaml index bd101d808..b27de2754 100644 --- a/pkg/action/testdata/charts/multiplecharts-lint-chart-2/Chart.yaml +++ b/pkg/action/testdata/charts/multiplecharts-lint-chart-2/Chart.yaml @@ -1,4 +1,4 @@ apiVersion: v1 name: multiplecharts-lint-chart-2 -version: 1 +version: "1" icon: "" \ No newline at end of file diff --git a/pkg/lint/rules/chartfile.go b/pkg/lint/rules/chartfile.go index 91a64fe13..b49f2cec0 100644 --- a/pkg/lint/rules/chartfile.go +++ b/pkg/lint/rules/chartfile.go @@ -18,12 +18,14 @@ package rules // import "helm.sh/helm/v3/pkg/lint/rules" import ( "fmt" + "io/ioutil" "os" "path/filepath" "github.com/Masterminds/semver/v3" "github.com/asaskevich/govalidator" "github.com/pkg/errors" + "sigs.k8s.io/yaml" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chartutil" @@ -45,11 +47,18 @@ func Chartfile(linter *support.Linter) { return } + // type check for Chart.yaml . ignoring error as any parse + // errors would already be caught in the above load function + chartFileForTypeCheck, _ := loadChartFileForTypeCheck(chartPath) + linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartName(chartFile)) // Chart metadata linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartAPIVersion(chartFile)) + + linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartVersionType(chartFileForTypeCheck)) linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartVersion(chartFile)) + linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartAppVersionType(chartFileForTypeCheck)) linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartMaintainer(chartFile)) linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartSources(chartFile)) linter.RunLinterRule(support.InfoSev, chartFileName, validateChartIconPresence(chartFile)) @@ -58,6 +67,26 @@ func Chartfile(linter *support.Linter) { linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartDependencies(chartFile)) } +func validateChartVersionType(data map[string]interface{}) error { + return isStringValue(data, "version") +} + +func validateChartAppVersionType(data map[string]interface{}) error { + return isStringValue(data, "appVersion") +} + +func isStringValue(data map[string]interface{}, key string) error { + value, ok := data[key] + if !ok { + return nil + } + valueType := fmt.Sprintf("%T", value) + if valueType != "string" { + return errors.Errorf("%s should be of type string but it's of type %s", key, valueType) + } + return nil +} + func validateChartYamlNotDirectory(chartPath string) error { fi, err := os.Stat(chartPath) @@ -166,3 +195,16 @@ func validateChartType(cf *chart.Metadata) error { } return nil } + +// loadChartFileForTypeCheck loads the Chart.yaml +// in a generic form of a map[string]interface{}, so that the type +// of the values can be checked +func loadChartFileForTypeCheck(filename string) (map[string]interface{}, error) { + b, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + y := make(map[string]interface{}) + err = yaml.Unmarshal(b, &y) + return y, err +} diff --git a/pkg/lint/rules/chartfile_test.go b/pkg/lint/rules/chartfile_test.go index d032dd12f..087cda047 100644 --- a/pkg/lint/rules/chartfile_test.go +++ b/pkg/lint/rules/chartfile_test.go @@ -30,7 +30,8 @@ import ( ) const ( - badChartDir = "testdata/badchartfile" + badChartDir = "testdata/badchartfile" + anotherBadChartDir = "testdata/anotherbadchartfile" ) var ( @@ -184,36 +185,63 @@ func TestValidateChartIconURL(t *testing.T) { } func TestChartfile(t *testing.T) { - linter := support.Linter{ChartDir: badChartDir} - Chartfile(&linter) - msgs := linter.Messages + t.Run("Chart.yaml basic validity issues", func(t *testing.T) { + linter := support.Linter{ChartDir: badChartDir} + Chartfile(&linter) + msgs := linter.Messages + expectedNumberOfErrorMessages := 6 + + if len(msgs) != expectedNumberOfErrorMessages { + t.Errorf("Expected %d errors, got %d", expectedNumberOfErrorMessages, len(msgs)) + return + } - if len(msgs) != 6 { - t.Errorf("Expected 6 errors, got %d", len(msgs)) - } + if !strings.Contains(msgs[0].Err.Error(), "name is required") { + t.Errorf("Unexpected message 0: %s", msgs[0].Err) + } - if !strings.Contains(msgs[0].Err.Error(), "name is required") { - t.Errorf("Unexpected message 0: %s", msgs[0].Err) - } + if !strings.Contains(msgs[1].Err.Error(), "apiVersion is required. The value must be either \"v1\" or \"v2\"") { + t.Errorf("Unexpected message 1: %s", msgs[1].Err) + } - if !strings.Contains(msgs[1].Err.Error(), "apiVersion is required. The value must be either \"v1\" or \"v2\"") { - t.Errorf("Unexpected message 1: %s", msgs[1].Err) - } + if !strings.Contains(msgs[2].Err.Error(), "version '0.0.0.0' is not a valid SemVer") { + t.Errorf("Unexpected message 2: %s", msgs[2].Err) + } - if !strings.Contains(msgs[2].Err.Error(), "version '0.0.0.0' is not a valid SemVer") { - t.Errorf("Unexpected message 2: %s", msgs[2].Err) - } + if !strings.Contains(msgs[3].Err.Error(), "icon is recommended") { + t.Errorf("Unexpected message 3: %s", msgs[3].Err) + } - if !strings.Contains(msgs[3].Err.Error(), "icon is recommended") { - t.Errorf("Unexpected message 3: %s", msgs[3].Err) - } + if !strings.Contains(msgs[4].Err.Error(), "chart type is not valid in apiVersion") { + t.Errorf("Unexpected message 4: %s", msgs[4].Err) + } - if !strings.Contains(msgs[4].Err.Error(), "chart type is not valid in apiVersion") { - t.Errorf("Unexpected message 4: %s", msgs[4].Err) - } + if !strings.Contains(msgs[5].Err.Error(), "dependencies are not valid in the Chart file with apiVersion") { + t.Errorf("Unexpected message 5: %s", msgs[5].Err) + } + }) - if !strings.Contains(msgs[5].Err.Error(), "dependencies are not valid in the Chart file with apiVersion") { - t.Errorf("Unexpected message 5: %s", msgs[5].Err) - } + t.Run("Chart.yaml validity issues due to type mismatch", func(t *testing.T) { + linter := support.Linter{ChartDir: anotherBadChartDir} + Chartfile(&linter) + msgs := linter.Messages + expectedNumberOfErrorMessages := 3 + + if len(msgs) != expectedNumberOfErrorMessages { + t.Errorf("Expected %d errors, got %d", expectedNumberOfErrorMessages, len(msgs)) + return + } + if !strings.Contains(msgs[0].Err.Error(), "version should be of type string") { + t.Errorf("Unexpected message 0: %s", msgs[0].Err) + } + + if !strings.Contains(msgs[1].Err.Error(), "version '7.2445e+06' is not a valid SemVer") { + t.Errorf("Unexpected message 1: %s", msgs[1].Err) + } + + if !strings.Contains(msgs[2].Err.Error(), "appVersion should be of type string") { + t.Errorf("Unexpected message 2: %s", msgs[2].Err) + } + }) } diff --git a/pkg/lint/rules/testdata/anotherbadchartfile/Chart.yaml b/pkg/lint/rules/testdata/anotherbadchartfile/Chart.yaml new file mode 100644 index 000000000..7f3cab390 --- /dev/null +++ b/pkg/lint/rules/testdata/anotherbadchartfile/Chart.yaml @@ -0,0 +1,15 @@ +name: "some-chart" +apiVersion: v2 +description: A Helm chart for Kubernetes +version: 72445e2 +home: "" +type: application +appVersion: 72225e2 +icon: "https://some-url.com/icon.jpeg" +dependencies: + - name: mariadb + version: 5.x.x + repository: https://kubernetes-charts.storage.googleapis.com/ + condition: mariadb.enabled + tags: + - database From a0fd1d81f03aaabbd961f0bfd0dfd907493078c6 Mon Sep 17 00:00:00 2001 From: Peter Engelbert Date: Thu, 28 May 2020 13:44:43 -0500 Subject: [PATCH 070/159] Fix crashing `helm chart list` with large list With a large list of charts, `helm chart list` will crash with the following message: ``` $ helm chart list --debug Error: open /home/me/.cache/helm/registry/cache/blobs/sha256/109971e44d63f7fd11fff60d19db41c2429a136943be2e3f8fd3e4c165156536: too many open files helm.go:75: [debug] open /home/me/.cache/helm/registry/cache/blobs/sha256/109971e44d63f7fd11fff60d19db41c2429a136943be2e3f8fd3e4c165156536: too many open files ``` Signed-off-by: Peter Engelbert --- internal/experimental/registry/cache.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/experimental/registry/cache.go b/internal/experimental/registry/cache.go index fbd62562a..5aca63668 100644 --- a/internal/experimental/registry/cache.go +++ b/internal/experimental/registry/cache.go @@ -357,6 +357,8 @@ func (cache *Cache) fetchBlob(desc *ocispec.Descriptor) ([]byte, error) { if err != nil { return nil, err } + defer reader.Close() + bytes := make([]byte, desc.Size) _, err = reader.ReadAt(bytes, 0) if err != nil { From 7dec5dcb8e2857dd14d0ea43f1c68876b5ac8a2d Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Fri, 29 May 2020 15:54:42 -0400 Subject: [PATCH 071/159] chore(helm): Avoid confusion in command usage Having both the `showCmd` and the `subCmd` passed to `addShowFlags()` can easily lead to mistakes in using the wrong command. Instead, `addShowFlags()` should only focus on the `subCmd` Signed-off-by: Marc Khouzam --- cmd/helm/show.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/helm/show.go b/cmd/helm/show.go index b335c5f76..91c35a53c 100644 --- a/cmd/helm/show.go +++ b/cmd/helm/show.go @@ -136,7 +136,8 @@ func newShowCmd(out io.Writer) *cobra.Command { cmds := []*cobra.Command{all, readmeSubCmd, valuesSubCmd, chartSubCmd} for _, subCmd := range cmds { - addShowFlags(showCommand, subCmd, client) + addShowFlags(subCmd, client) + showCommand.AddCommand(subCmd) // Register the completion function for each subcommand completion.RegisterValidArgsFunc(subCmd, validArgsFunc) @@ -145,12 +146,11 @@ func newShowCmd(out io.Writer) *cobra.Command { return showCommand } -func addShowFlags(showCmd *cobra.Command, subCmd *cobra.Command, client *action.Show) { +func addShowFlags(subCmd *cobra.Command, client *action.Show) { f := subCmd.Flags() f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored") addChartPathOptionsFlags(f, &client.ChartPathOptions) - showCmd.AddCommand(subCmd) } func runShow(args []string, client *action.Show) (string, error) { From f11e74ee571f6a21ea5fd647513324d7268ff8d3 Mon Sep 17 00:00:00 2001 From: Peter Engelbert Date: Wed, 3 Jun 2020 15:23:26 -0500 Subject: [PATCH 072/159] Add unit test for man-in-the-middle attack on pull Add a unit test that proves the digest of the received content being checked. The check should ensure that the digest of the received content is identical to the digest provided by the manifest in the layers[0] descriptor. This check is currently implemented in containerd, so the unit test ensures security in the case a breaking change is made in containerd. Signed-off-by: Peter Engelbert --- internal/experimental/registry/client_test.go | 66 +++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/internal/experimental/registry/client_test.go b/internal/experimental/registry/client_test.go index 6e9d5db36..2d208b7b9 100644 --- a/internal/experimental/registry/client_test.go +++ b/internal/experimental/registry/client_test.go @@ -24,11 +24,16 @@ import ( "io/ioutil" "net" "net/http" + "net/http/httptest" + "net/url" "os" "path/filepath" + "strings" "testing" "time" + "github.com/containerd/containerd/errdefs" + auth "github.com/deislabs/oras/pkg/auth/docker" "github.com/docker/distribution/configuration" "github.com/docker/distribution/registry" @@ -49,10 +54,11 @@ var ( type RegistryClientTestSuite struct { suite.Suite - Out io.Writer - DockerRegistryHost string - CacheRootDir string - RegistryClient *Client + Out io.Writer + DockerRegistryHost string + CompromisedRegistryHost string + CacheRootDir string + RegistryClient *Client } func (suite *RegistryClientTestSuite) SetupSuite() { @@ -116,6 +122,8 @@ func (suite *RegistryClientTestSuite) SetupSuite() { dockerRegistry, err := registry.NewRegistry(context.Background(), config) suite.Nil(err, "no error creating test registry") + suite.CompromisedRegistryHost = initCompromisedRegistryTestServer() + // Start Docker registry go dockerRegistry.ListenAndServe() } @@ -232,6 +240,16 @@ func (suite *RegistryClientTestSuite) Test_7_Logout() { suite.Nil(err, "no error logging out of registry") } +func (suite *RegistryClientTestSuite) Test_8_ManInTheMiddle() { + ref, err := ParseReference(fmt.Sprintf("%s/testrepo/supposedlysafechart:9.9.9", suite.CompromisedRegistryHost)) + suite.Nil(err) + + // returns content that does not match the expected digest + err = suite.RegistryClient.PullChart(ref) + suite.NotNil(err) + suite.True(errdefs.IsFailedPrecondition(err)) +} + func TestRegistryClientTestSuite(t *testing.T) { suite.Run(t, new(RegistryClientTestSuite)) } @@ -250,3 +268,43 @@ func getFreePort() (int, error) { defer l.Close() return l.Addr().(*net.TCPAddr).Port, nil } + +func initCompromisedRegistryTestServer() string { + s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if strings.Contains(r.URL.Path, "manifests") { + w.Header().Set("Content-Type", "application/vnd.oci.image.manifest.v1+json") + w.WriteHeader(200) + + // layers[0] is the blob []byte("a") + w.Write([]byte( + `{ "schemaVersion": 2, "config": { + "mediaType": "application/vnd.cncf.helm.config.v1+json", + "digest": "sha256:a705ee2789ab50a5ba20930f246dbd5cc01ff9712825bb98f57ee8414377f133", + "size": 181 + }, + "layers": [ + { + "mediaType": "application/tar+gzip", + "digest": "sha256:ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", + "size": 1 + } + ] +}`)) + } else if r.URL.Path == "/v2/testrepo/supposedlysafechart/blobs/sha256:a705ee2789ab50a5ba20930f246dbd5cc01ff9712825bb98f57ee8414377f133" { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + w.Write([]byte("{\"name\":\"mychart\",\"version\":\"0.1.0\",\"description\":\"A Helm chart for Kubernetes\\n" + + "an 'application' or a 'library' chart.\",\"apiVersion\":\"v2\",\"appVersion\":\"1.16.0\",\"type\":" + + "\"application\"}")) + } else if r.URL.Path == "/v2/testrepo/supposedlysafechart/blobs/sha256:ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" { + w.Header().Set("Content-Type", "application/tar+gzip") + w.WriteHeader(200) + w.Write([]byte("b")) + } else { + w.WriteHeader(500) + } + })) + + u, _ := url.Parse(s.URL) + return fmt.Sprintf("localhost:%s", u.Port()) +} From 562767b04015546e53677bb3c8aa5cae12897fa3 Mon Sep 17 00:00:00 2001 From: wawa0210 Date: Tue, 9 Jun 2020 17:49:02 +0800 Subject: [PATCH 073/159] Fix description is ignore when installed with upgrade Signed-off-by: wawa0210 --- cmd/helm/upgrade.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index c263d32e7..f8103b485 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -100,6 +100,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { instClient.PostRenderer = client.PostRenderer instClient.DisableOpenAPIValidation = client.DisableOpenAPIValidation instClient.SubNotes = client.SubNotes + instClient.Description = client.Description rel, err := runInstall(args, instClient, valueOpts, out) if err != nil { From e09e8604e6160775890c154b1fb8b6683a8bbb6f Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Fri, 29 May 2020 14:58:52 -0400 Subject: [PATCH 074/159] fix(doc): generic description for --version/verify The flags added by addChartPathOptionsFlags() are used for `helm install` and `helm upgrade` but also for `helm template`, `helm show` and `helm pull`. Because of the latter three, we should not use the word 'install' in the description of the --version and --verify flags. Signed-off-by: Marc Khouzam --- cmd/helm/flags.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/helm/flags.go b/cmd/helm/flags.go index 246cb0dd5..6b9c3050b 100644 --- a/cmd/helm/flags.go +++ b/cmd/helm/flags.go @@ -41,8 +41,8 @@ func addValueOptionsFlags(f *pflag.FlagSet, v *values.Options) { } func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) { - f.StringVar(&c.Version, "version", "", "specify the exact chart version to install. If this is not specified, the latest version is installed") - f.BoolVar(&c.Verify, "verify", false, "verify the package before installing it") + f.StringVar(&c.Version, "version", "", "specify the exact chart version to use. If this is not specified, the latest version is used") + f.BoolVar(&c.Verify, "verify", false, "verify the package before using it") f.StringVar(&c.Keyring, "keyring", defaultKeyring(), "location of public keys used for verification") f.StringVar(&c.RepoURL, "repo", "", "chart repository url where to locate the requested chart") f.StringVar(&c.Username, "username", "", "chart repository username where to locate the requested chart") From 70f89e5f26015a92432bdeb94ddb6d6e52532b19 Mon Sep 17 00:00:00 2001 From: Andrew Melis Date: Sat, 6 Jun 2020 03:32:49 -0400 Subject: [PATCH 075/159] Make helm ls return only current releases if providing state filter Previously, the `helm ls --$state` operation would display outdated releases under certain conditions. Given the following set of releases: ``` NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE bar 1 Wed Apr 8 16:54:39 2020 DEPLOYED bar-4.0.0 1.0 default foo 1 Fri Feb 7 06:16:56 2020 DEPLOYED foo-0.1.0 1.0 default foo 2 Mon May 4 07:16:56 2020 FAILED foo-0.1.0 1.0 default foo 3 Mon May 4 07:20:00 2020 FAILED foo-0.1.0 1.0 default foo 4 Tue May 5 08:16:56 2020 DEPLOYED foo-0.2.0 1.0 default qux 1 Tue Jun 9 10:32:00 2020 DEPLOYED qux-4.0.3 1.0 default qux 2 Tue Jun 9 10:57:00 2020 FAILED qux-4.0.3 1.0 default ``` `helm ls --failed` produced the following output: ``` NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE foo 3 Mon May 4 07:20:00 2020 FAILED foo-0.1.0 1.0 default qux 2 Tue Jun 9 10:57:00 2020 FAILED qux-4.0.0 1.0 default ``` Including the `qux` release in that `helm ls --failed` output is not controversial; the most recent revision of `qux` was not successful and an operator should investigate. Including the `foo` release in the output, however, is questionable. Revision 3 of `foo` is _not_ the most recent release of `foo`, and that FAILED release was fixed in a susubsequent upgrade. A user may see that FAILED deploy and start taking inappropriate action. Further, that issue was fixed months ago in this example -- troubleshooting an old deploy may not be safe if significant changes have occurred. Concern over this behavior was raised in https://github.com/helm/helm/issues/7495. This behavior applied to all the state filter flags (--deployed, --failed, --pending, etc.), and a user could pass multiple state filter flags to a single command. The previous behavior can be summarized as follows: For each release name, all release revisions having any of the supplied state flags were retrieved, and the most recent revision among these was returned (regardless of whether a newer revision of an unspecified state exists). This change request alters the helm list action to match user expectations such that only "current" releases are shown when filtering on release state. After this change, the following output would be produced by `helm ls --failed`: ``` NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE qux 2 Tue Jun 9 10:57:00 2020 FAILED qux-4.0.0 1.0 default ``` The command now returns only `qux` because it is the only "current" FAILED release. This behavior change applies to all the state filters _except_ `superseded`, which now becomes a special case. By definition, at least one newer release exists ahead of each superseded release. A conditional is included in this change request to maintain the preexisting behavior (return "most recent" superseded revison for each release name) if the superseded state filter is requested. --- Note that there is an alternate perspective that a state filter flag should return all releases of a given state rather than only the "current" releases. In the above example, `helm ls --failed` with this approach would return the following: ``` NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE foo 2 Mon May 4 07:16:56 2020 FAILED foo-0.1.0 1.0 default foo 3 Mon May 4 07:20:00 2020 FAILED foo-0.1.0 1.0 default qux 2 Tue Jun 9 10:57:00 2020 FAILED qux-4.0.0 1.0 default ``` Multiple FAILED `foo` revisions are included in the output, unlike the current behavior. This approach is logical and achievable. It allows a user to find exactly what is requested: all historical releases of a given state. In order to achieve continuity with helm behavior, however, a new filter (something like "current") would probably need to be implemented and become the new default. Given current helm behavior as well as the comments in the #7495, I did not pursue this approach. --- Technical details: - Moved list action state mask filter after latest release filter Previously, the list operation in helm/pkg/action/list.go skipped releases that were not covered by the state mask on _retrieval_ from the Releases store: ``` results, err := l.cfg.Releases.List(func(rel *release.Release) bool { // Skip anything that the mask doesn't cover currentStatus := l.StateMask.FromName(rel.Info.Status.String()) if l.StateMask¤tStatus == 0 { return false } ... ``` https://github.com/helm/helm/blob/8ea6b970ecd02365a230420692350057d48278e5/pkg/action/list.go#L154-L159 While filtering on retrieval in this manner avoided an extra iteration through the entire list to check on the supplied condition later, it introduced the possibility of returning an outdated release to the user because newer releases (that would have otherwise squashed outdated releases in the `filterList` function) are simply not included in the set of working records. This change moves the state mask filtering process to _after_ the set of current releases is built. Outdated, potentially misleading releases are scrubbed out prior to the application of the state mask filter. As written, this state mask filtration (in the new `filterStateMask` method on `*List`) incurs an additional, potentially expensive iteration over the set of releases to return to the user. An alternative approach could avoid that extra iteration and fit this logic into the existing `filterList` function at the cost of making `filterList` function a little harder to understand. - Rename filterList to filterLatestReleases for clarity Another function that filters the list is added, so update to the more descriptive name here. - List superseded releases without filtering for latest This change makes superseded releases a special case, as they would _never_ be displayed otherwise (by definition, as superseded releases have been replaced by a newer release), so a conditional maintains current behavior ("return newest superseded revision for each release name") Fixes #7495. Signed-off-by: Andrew Melis --- pkg/action/list.go | 35 +++++++++++++++++++------- pkg/action/list_test.go | 56 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 79 insertions(+), 12 deletions(-) diff --git a/pkg/action/list.go b/pkg/action/list.go index ac6fd1b75..3d5e6d7a6 100644 --- a/pkg/action/list.go +++ b/pkg/action/list.go @@ -152,12 +152,6 @@ func (l *List) Run() ([]*release.Release, error) { } results, err := l.cfg.Releases.List(func(rel *release.Release) bool { - // Skip anything that the mask doesn't cover - currentStatus := l.StateMask.FromName(rel.Info.Status.String()) - if l.StateMask¤tStatus == 0 { - return false - } - // Skip anything that doesn't match the filter. if filter != nil && !filter.MatchString(rel.Name) { return false @@ -173,7 +167,16 @@ func (l *List) Run() ([]*release.Release, error) { return results, nil } - results = filterList(results) + // by definition, superseded releases are never shown if + // only the latest releases are returned. so if requested statemask + // is _only_ ListSuperseded, skip the latest release filter + if l.StateMask != ListSuperseded { + results = filterLatestReleases(results) + } + + // State mask application must occur after filtering to + // latest releases, otherwise outdated entries can be returned + results = l.filterStateMask(results) // Unfortunately, we have to sort before truncating, which can incur substantial overhead l.sort(results) @@ -222,8 +225,8 @@ func (l *List) sort(rels []*release.Release) { } } -// filterList returns a list scrubbed of old releases. -func filterList(releases []*release.Release) []*release.Release { +// filterLatestReleases returns a list scrubbed of old releases. +func filterLatestReleases(releases []*release.Release) []*release.Release { latestReleases := make(map[string]*release.Release) for _, rls := range releases { @@ -242,6 +245,20 @@ func filterList(releases []*release.Release) []*release.Release { return list } +func (l *List) filterStateMask(releases []*release.Release) []*release.Release { + desiredStateReleases := make([]*release.Release, 0) + + for _, rls := range releases { + currentStatus := l.StateMask.FromName(rls.Info.Status.String()) + if l.StateMask¤tStatus == 0 { + continue + } + desiredStateReleases = append(desiredStateReleases, rls) + } + + return desiredStateReleases +} + // SetStateMask calculates the state mask based on parameters. func (l *List) SetStateMask() { if l.All { diff --git a/pkg/action/list_test.go b/pkg/action/list_test.go index 378a747b0..b8e2ece68 100644 --- a/pkg/action/list_test.go +++ b/pkg/action/list_test.go @@ -188,6 +188,56 @@ func TestList_StateMask(t *testing.T) { is.Len(res, 3) } +func TestList_StateMaskWithStaleRevisions(t *testing.T) { + is := assert.New(t) + lister := newListFixture(t) + lister.StateMask = ListFailed + + makeMeSomeReleasesWithStaleFailure(lister.cfg.Releases, t) + + res, err := lister.Run() + + is.NoError(err) + is.Len(res, 1) + + // "dirty" release should _not_ be present as most recent + // release is deployed despite failed release in past + is.Equal("failed", res[0].Name) +} + +func makeMeSomeReleasesWithStaleFailure(store *storage.Storage, t *testing.T) { + t.Helper() + one := namedReleaseStub("clean", release.StatusDeployed) + one.Namespace = "default" + one.Version = 1 + + two := namedReleaseStub("dirty", release.StatusDeployed) + two.Namespace = "default" + two.Version = 1 + + three := namedReleaseStub("dirty", release.StatusFailed) + three.Namespace = "default" + three.Version = 2 + + four := namedReleaseStub("dirty", release.StatusDeployed) + four.Namespace = "default" + four.Version = 3 + + five := namedReleaseStub("failed", release.StatusFailed) + five.Namespace = "default" + five.Version = 1 + + for _, rel := range []*release.Release{one, two, three, four, five} { + if err := store.Create(rel); err != nil { + t.Fatal(err) + } + } + + all, err := store.ListReleases() + assert.NoError(t, err) + assert.Len(t, all, 5, "sanity test: five items added") +} + func TestList_Filter(t *testing.T) { is := assert.New(t) lister := newListFixture(t) @@ -236,7 +286,7 @@ func makeMeSomeReleases(store *storage.Storage, t *testing.T) { assert.Len(t, all, 3, "sanity test: three items added") } -func TestFilterList(t *testing.T) { +func TestFilterLatestReleases(t *testing.T) { t.Run("should filter old versions of the same release", func(t *testing.T) { r1 := releaseStub() r1.Name = "r" @@ -248,7 +298,7 @@ func TestFilterList(t *testing.T) { another.Name = "another" another.Version = 1 - filteredList := filterList([]*release.Release{r1, r2, another}) + filteredList := filterLatestReleases([]*release.Release{r1, r2, another}) expectedFilteredList := []*release.Release{r2, another} assert.ElementsMatch(t, expectedFilteredList, filteredList) @@ -264,7 +314,7 @@ func TestFilterList(t *testing.T) { r2.Namespace = "testing" r2.Version = 2 - filteredList := filterList([]*release.Release{r1, r2}) + filteredList := filterLatestReleases([]*release.Release{r1, r2}) expectedFilteredList := []*release.Release{r1, r2} assert.ElementsMatch(t, expectedFilteredList, filteredList) From 88a3d6eaea65971b3e4884b5abbcccc4d7a79f72 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Sat, 11 Apr 2020 14:06:56 -0400 Subject: [PATCH 076/159] feat(comp): Move custom completions to Cobra 1.0 Cobra 1.0 introduces custom Go completions. This commit replaces Helm's own solution to use Cobra's solution. This allows to completely remove Helm's internal "completion" package. Signed-off-by: Marc Khouzam --- cmd/helm/flags.go | 13 +- cmd/helm/get_all.go | 25 +- cmd/helm/get_hooks.go | 28 +- cmd/helm/get_manifest.go | 28 +- cmd/helm/get_notes.go | 25 +- cmd/helm/get_values.go | 26 +- cmd/helm/history.go | 21 +- cmd/helm/install.go | 13 +- cmd/helm/list.go | 9 +- cmd/helm/load_plugins.go | 22 +- cmd/helm/plugin_uninstall.go | 16 +- cmd/helm/plugin_update.go | 16 +- cmd/helm/pull.go | 15 +- cmd/helm/release_testing.go | 15 +- cmd/helm/repo_remove.go | 10 +- cmd/helm/rollback.go | 15 +- cmd/helm/root.go | 40 +- cmd/helm/search_repo.go | 23 +- cmd/helm/show.go | 44 +- cmd/helm/status.go | 26 +- cmd/helm/template.go | 9 +- cmd/helm/testdata/output/output-comp.txt | 1 + cmd/helm/testdata/output/plugin_args_comp.txt | 1 + .../testdata/output/plugin_args_flag_comp.txt | 1 + .../output/plugin_args_many_args_comp.txt | 1 + .../testdata/output/plugin_args_ns_comp.txt | 1 + .../output/plugin_echo_bad_directive.txt | 1 + .../output/plugin_echo_no_directive.txt | 1 + cmd/helm/testdata/output/revision-comp.txt | 1 + .../output/revision-wrong-args-comp.txt | 1 + cmd/helm/testdata/output/status-comp.txt | 1 + .../output/status-wrong-args-comp.txt | 1 + cmd/helm/uninstall.go | 15 +- cmd/helm/upgrade.go | 21 +- internal/completion/complete.go | 399 ------------------ 35 files changed, 235 insertions(+), 650 deletions(-) delete mode 100644 internal/completion/complete.go diff --git a/cmd/helm/flags.go b/cmd/helm/flags.go index 6b9c3050b..d4cd88fef 100644 --- a/cmd/helm/flags.go +++ b/cmd/helm/flags.go @@ -18,12 +18,12 @@ package main import ( "fmt" + "log" "strings" "github.com/spf13/cobra" "github.com/spf13/pflag" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v3/pkg/cli/values" @@ -55,19 +55,22 @@ func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) { // bindOutputFlag will add the output flag to the given command and bind the // value to the given format pointer func bindOutputFlag(cmd *cobra.Command, varRef *output.Format) { - f := cmd.Flags() - flag := f.VarPF(newOutputValue(output.Table, varRef), outputFlag, "o", + cmd.Flags().VarP(newOutputValue(output.Table, varRef), outputFlag, "o", fmt.Sprintf("prints the output in the specified format. Allowed values: %s", strings.Join(output.Formats(), ", "))) - completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { + err := cmd.RegisterFlagCompletionFunc(outputFlag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { var formatNames []string for _, format := range output.Formats() { if strings.HasPrefix(format, toComplete) { formatNames = append(formatNames, format) } } - return formatNames, completion.BashCompDirectiveDefault + return formatNames, cobra.ShellCompDirectiveDefault }) + + if err != nil { + log.Fatal(err) + } } type outputValue output.Format diff --git a/cmd/helm/get_all.go b/cmd/helm/get_all.go index 7d893d7e0..1ebc7e387 100644 --- a/cmd/helm/get_all.go +++ b/cmd/helm/get_all.go @@ -18,11 +18,11 @@ package main import ( "io" + "log" "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/cli/output" ) @@ -41,6 +41,12 @@ func newGetAllCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Short: "download all information for a named release", Long: getAllHelp, Args: require.ExactArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compListReleases(toComplete, cfg) + }, RunE: func(cmd *cobra.Command, args []string) error { res, err := client.Run(args[0]) if err != nil { @@ -57,24 +63,19 @@ func newGetAllCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { }, } - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - if len(args) != 0 { - return nil, completion.BashCompDirectiveNoFileComp - } - return compListReleases(toComplete, cfg) - }) - f := cmd.Flags() f.IntVar(&client.Version, "revision", 0, "get the named release with revision") - flag := f.Lookup("revision") - completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { + err := cmd.RegisterFlagCompletionFunc("revision", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 1 { return compListRevisions(cfg, args[0]) } - return nil, completion.BashCompDirectiveNoFileComp + return nil, cobra.ShellCompDirectiveNoFileComp }) + if err != nil { + log.Fatal(err) + } + f.StringVar(&template, "template", "", "go template for formatting the output, eg: {{.Release.Name}}") return cmd diff --git a/cmd/helm/get_hooks.go b/cmd/helm/get_hooks.go index c2087b1ba..6453c30eb 100644 --- a/cmd/helm/get_hooks.go +++ b/cmd/helm/get_hooks.go @@ -19,11 +19,11 @@ package main import ( "fmt" "io" + "log" "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" ) @@ -41,6 +41,12 @@ func newGetHooksCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Short: "download all hooks for a named release", Long: getHooksHelp, Args: require.ExactArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compListReleases(toComplete, cfg) + }, RunE: func(cmd *cobra.Command, args []string) error { res, err := client.Run(args[0]) if err != nil { @@ -53,23 +59,17 @@ func newGetHooksCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { }, } - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - if len(args) != 0 { - return nil, completion.BashCompDirectiveNoFileComp - } - return compListReleases(toComplete, cfg) - }) - - f := cmd.Flags() - f.IntVar(&client.Version, "revision", 0, "get the named release with revision") - flag := f.Lookup("revision") - completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { + cmd.Flags().IntVar(&client.Version, "revision", 0, "get the named release with revision") + err := cmd.RegisterFlagCompletionFunc("revision", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 1 { return compListRevisions(cfg, args[0]) } - return nil, completion.BashCompDirectiveNoFileComp + return nil, cobra.ShellCompDirectiveNoFileComp }) + if err != nil { + log.Fatal(err) + } + return cmd } diff --git a/cmd/helm/get_manifest.go b/cmd/helm/get_manifest.go index f332befd9..048bf36b0 100644 --- a/cmd/helm/get_manifest.go +++ b/cmd/helm/get_manifest.go @@ -19,11 +19,11 @@ package main import ( "fmt" "io" + "log" "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" ) @@ -43,6 +43,12 @@ func newGetManifestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command Short: "download the manifest for a named release", Long: getManifestHelp, Args: require.ExactArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compListReleases(toComplete, cfg) + }, RunE: func(cmd *cobra.Command, args []string) error { res, err := client.Run(args[0]) if err != nil { @@ -53,23 +59,17 @@ func newGetManifestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command }, } - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - if len(args) != 0 { - return nil, completion.BashCompDirectiveNoFileComp - } - return compListReleases(toComplete, cfg) - }) - - f := cmd.Flags() - f.IntVar(&client.Version, "revision", 0, "get the named release with revision") - flag := f.Lookup("revision") - completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { + cmd.Flags().IntVar(&client.Version, "revision", 0, "get the named release with revision") + err := cmd.RegisterFlagCompletionFunc("revision", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 1 { return compListRevisions(cfg, args[0]) } - return nil, completion.BashCompDirectiveNoFileComp + return nil, cobra.ShellCompDirectiveNoFileComp }) + if err != nil { + log.Fatal(err) + } + return cmd } diff --git a/cmd/helm/get_notes.go b/cmd/helm/get_notes.go index 4491bd9ba..88d494fc4 100644 --- a/cmd/helm/get_notes.go +++ b/cmd/helm/get_notes.go @@ -19,11 +19,11 @@ package main import ( "fmt" "io" + "log" "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" ) @@ -39,6 +39,12 @@ func newGetNotesCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Short: "download the notes for a named release", Long: getNotesHelp, Args: require.ExactArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compListReleases(toComplete, cfg) + }, RunE: func(cmd *cobra.Command, args []string) error { res, err := client.Run(args[0]) if err != nil { @@ -51,23 +57,18 @@ func newGetNotesCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { }, } - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - if len(args) != 0 { - return nil, completion.BashCompDirectiveNoFileComp - } - return compListReleases(toComplete, cfg) - }) - f := cmd.Flags() f.IntVar(&client.Version, "revision", 0, "get the named release with revision") - flag := f.Lookup("revision") - completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { + err := cmd.RegisterFlagCompletionFunc("revision", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 1 { return compListRevisions(cfg, args[0]) } - return nil, completion.BashCompDirectiveNoFileComp + return nil, cobra.ShellCompDirectiveNoFileComp }) + if err != nil { + log.Fatal(err) + } + return cmd } diff --git a/cmd/helm/get_values.go b/cmd/helm/get_values.go index a8c5acc5e..fa7b10fed 100644 --- a/cmd/helm/get_values.go +++ b/cmd/helm/get_values.go @@ -19,11 +19,11 @@ package main import ( "fmt" "io" + "log" "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/cli/output" ) @@ -46,6 +46,12 @@ func newGetValuesCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Short: "download the values file for a named release", Long: getValuesHelp, Args: require.ExactArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compListReleases(toComplete, cfg) + }, RunE: func(cmd *cobra.Command, args []string) error { vals, err := client.Run(args[0]) if err != nil { @@ -55,23 +61,19 @@ func newGetValuesCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { }, } - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - if len(args) != 0 { - return nil, completion.BashCompDirectiveNoFileComp - } - return compListReleases(toComplete, cfg) - }) - f := cmd.Flags() f.IntVar(&client.Version, "revision", 0, "get the named release with revision") - flag := f.Lookup("revision") - completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { + err := cmd.RegisterFlagCompletionFunc("revision", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 1 { return compListRevisions(cfg, args[0]) } - return nil, completion.BashCompDirectiveNoFileComp + return nil, cobra.ShellCompDirectiveNoFileComp }) + + if err != nil { + log.Fatal(err) + } + f.BoolVarP(&client.AllValues, "all", "a", false, "dump all (computed) values") bindOutputFlag(cmd, &outfmt) diff --git a/cmd/helm/history.go b/cmd/helm/history.go index 3ef542e58..b49c52990 100644 --- a/cmd/helm/history.go +++ b/cmd/helm/history.go @@ -26,7 +26,6 @@ import ( "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/cli/output" @@ -61,6 +60,12 @@ func newHistoryCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Short: "fetch release history", Aliases: []string{"hist"}, Args: require.ExactArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compListReleases(toComplete, cfg) + }, RunE: func(cmd *cobra.Command, args []string) error { history, err := getHistory(client, args[0]) if err != nil { @@ -71,14 +76,6 @@ func newHistoryCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { }, } - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - if len(args) != 0 { - return nil, completion.BashCompDirectiveNoFileComp - } - return compListReleases(toComplete, cfg) - }) - f := cmd.Flags() f.IntVar(&client.Max, "max", 256, "maximum number of revision to include in history") bindOutputFlag(cmd, &outfmt) @@ -187,7 +184,7 @@ func min(x, y int) int { return y } -func compListRevisions(cfg *action.Configuration, releaseName string) ([]string, completion.BashCompDirective) { +func compListRevisions(cfg *action.Configuration, releaseName string) ([]string, cobra.ShellCompDirective) { client := action.NewHistory(cfg) var revisions []string @@ -195,7 +192,7 @@ func compListRevisions(cfg *action.Configuration, releaseName string) ([]string, for _, release := range hist { revisions = append(revisions, strconv.Itoa(release.Version)) } - return revisions, completion.BashCompDirectiveDefault + return revisions, cobra.ShellCompDirectiveDefault } - return nil, completion.BashCompDirectiveError + return nil, cobra.ShellCompDirectiveError } diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 44f7336c0..b489c262d 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -26,7 +26,6 @@ import ( "github.com/spf13/pflag" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" @@ -114,6 +113,9 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Short: "install a chart", Long: installDesc, Args: require.MinimumNArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return compInstall(args, toComplete, client) + }, RunE: func(_ *cobra.Command, args []string) error { rel, err := runInstall(args, client, valueOpts, out) if err != nil { @@ -124,11 +126,6 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { }, } - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - return compInstall(args, toComplete, client) - }) - addInstallFlags(cmd.Flags(), client, valueOpts) bindOutputFlag(cmd, &outfmt) bindPostRenderFlag(cmd, &client.PostRenderer) @@ -242,7 +239,7 @@ func isChartInstallable(ch *chart.Chart) (bool, error) { } // Provide dynamic auto-completion for the install and template commands -func compInstall(args []string, toComplete string, client *action.Install) ([]string, completion.BashCompDirective) { +func compInstall(args []string, toComplete string, client *action.Install) ([]string, cobra.ShellCompDirective) { requiredArgs := 1 if client.GenerateName { requiredArgs = 0 @@ -250,5 +247,5 @@ func compInstall(args []string, toComplete string, client *action.Install) ([]st if len(args) == requiredArgs { return compListCharts(toComplete, true) } - return nil, completion.BashCompDirectiveNoFileComp + return nil, cobra.ShellCompDirectiveNoFileComp } diff --git a/cmd/helm/list.go b/cmd/helm/list.go index 08d6beb79..18e5ffe45 100644 --- a/cmd/helm/list.go +++ b/cmd/helm/list.go @@ -26,7 +26,6 @@ import ( "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v3/pkg/release" @@ -186,8 +185,8 @@ func (r *releaseListWriter) WriteYAML(out io.Writer) error { } // Provide dynamic auto-completion for release names -func compListReleases(toComplete string, cfg *action.Configuration) ([]string, completion.BashCompDirective) { - completion.CompDebugln(fmt.Sprintf("compListReleases with toComplete %s", toComplete)) +func compListReleases(toComplete string, cfg *action.Configuration) ([]string, cobra.ShellCompDirective) { + cobra.CompDebugln(fmt.Sprintf("compListReleases with toComplete %s", toComplete), settings.Debug) client := action.NewList(cfg) client.All = true @@ -197,7 +196,7 @@ func compListReleases(toComplete string, cfg *action.Configuration) ([]string, c client.SetStateMask() results, err := client.Run() if err != nil { - return nil, completion.BashCompDirectiveDefault + return nil, cobra.ShellCompDirectiveDefault } var choices []string @@ -205,5 +204,5 @@ func compListReleases(toComplete string, cfg *action.Configuration) ([]string, c choices = append(choices, res.Name) } - return choices, completion.BashCompDirectiveNoFileComp + return choices, cobra.ShellCompDirectiveNoFileComp } diff --git a/cmd/helm/load_plugins.go b/cmd/helm/load_plugins.go index 36de50135..e439c8407 100644 --- a/cmd/helm/load_plugins.go +++ b/cmd/helm/load_plugins.go @@ -32,7 +32,6 @@ import ( "github.com/spf13/cobra" "sigs.k8s.io/yaml" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/plugin" ) @@ -97,6 +96,7 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) { // This passes all the flags to the subcommand. DisableFlagParsing: true, } + // TODO: Make sure a command with this name does not already exist. baseCmd.AddCommand(c) @@ -105,7 +105,7 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) { // We only do this when necessary (for the "completion" and "__complete" commands) to avoid the // risk of a rogue plugin affecting Helm's normal behavior. subCmd, _, err := baseCmd.Find(os.Args[1:]) - if (err == nil && (subCmd.Name() == "completion" || subCmd.Name() == completion.CompRequestCmd)) || + if (err == nil && (subCmd.Name() == "completion" || subCmd.Name() == cobra.ShellCompRequestCmd)) || /* for the tests */ subCmd == baseCmd.Root() { loadCompletionForPlugin(c, plug) } @@ -247,9 +247,9 @@ func addPluginCommands(plugin *plugin.Plugin, baseCmd *cobra.Command, cmds *plug // Only setup dynamic completion if there are no sub-commands. This avoids // calling plugin.complete at every completion, which greatly simplifies // development of plugin.complete for plugin developers. - completion.RegisterValidArgsFunc(baseCmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { + baseCmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return pluginDynamicComp(plugin, cmd, args, toComplete) - }) + } } // Create fake flags. @@ -322,12 +322,12 @@ func loadFile(path string) (*pluginCommand, error) { // pluginDynamicComp call the plugin.complete script of the plugin (if available) // to obtain the dynamic completion choices. It must pass all the flags and sub-commands // specified in the command-line to the plugin.complete executable (except helm's global flags) -func pluginDynamicComp(plug *plugin.Plugin, cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { +func pluginDynamicComp(plug *plugin.Plugin, cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { md := plug.Metadata u, err := processParent(cmd, args) if err != nil { - return nil, completion.BashCompDirectiveError + return nil, cobra.ShellCompDirectiveError } // We will call the dynamic completion script of the plugin @@ -343,12 +343,12 @@ func pluginDynamicComp(plug *plugin.Plugin, cmd *cobra.Command, args []string, t } plugin.SetupPluginEnv(settings, md.Name, plug.Dir) - completion.CompDebugln(fmt.Sprintf("calling %s with args %v", main, argv)) + cobra.CompDebugln(fmt.Sprintf("calling %s with args %v", main, argv), settings.Debug) buf := new(bytes.Buffer) if err := callPluginExecutable(md.Name, main, argv, buf); err != nil { // The dynamic completion file is optional for a plugin, so this error is ok. - completion.CompDebugln(fmt.Sprintf("Unable to call %s: %v", main, err.Error())) - return nil, completion.BashCompDirectiveDefault + cobra.CompDebugln(fmt.Sprintf("Unable to call %s: %v", main, err.Error()), settings.Debug) + return nil, cobra.ShellCompDirectiveDefault } var completions []string @@ -361,12 +361,12 @@ func pluginDynamicComp(plug *plugin.Plugin, cmd *cobra.Command, args []string, t // Check if the last line of output is of the form :, which // indicates the BashCompletionDirective. - directive := completion.BashCompDirectiveDefault + directive := cobra.ShellCompDirectiveDefault if len(completions) > 0 { lastLine := completions[len(completions)-1] if len(lastLine) > 1 && lastLine[0] == ':' { if strInt, err := strconv.Atoi(lastLine[1:]); err == nil { - directive = completion.BashCompDirective(strInt) + directive = cobra.ShellCompDirective(strInt) completions = completions[:len(completions)-1] } } diff --git a/cmd/helm/plugin_uninstall.go b/cmd/helm/plugin_uninstall.go index 66cdaccdc..b2290fb9b 100644 --- a/cmd/helm/plugin_uninstall.go +++ b/cmd/helm/plugin_uninstall.go @@ -24,7 +24,6 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/plugin" ) @@ -39,6 +38,12 @@ func newPluginUninstallCmd(out io.Writer) *cobra.Command { Use: "uninstall ...", Aliases: []string{"rm", "remove"}, Short: "uninstall one or more Helm plugins", + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compListPlugins(toComplete), cobra.ShellCompDirectiveNoFileComp + }, PreRunE: func(cmd *cobra.Command, args []string) error { return o.complete(args) }, @@ -46,15 +51,6 @@ func newPluginUninstallCmd(out io.Writer) *cobra.Command { return o.run(out) }, } - - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - if len(args) != 0 { - return nil, completion.BashCompDirectiveNoFileComp - } - return compListPlugins(toComplete), completion.BashCompDirectiveNoFileComp - }) - return cmd } diff --git a/cmd/helm/plugin_update.go b/cmd/helm/plugin_update.go index 23f840b4a..c46444e0d 100644 --- a/cmd/helm/plugin_update.go +++ b/cmd/helm/plugin_update.go @@ -24,7 +24,6 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/plugin" "helm.sh/helm/v3/pkg/plugin/installer" ) @@ -40,6 +39,12 @@ func newPluginUpdateCmd(out io.Writer) *cobra.Command { Use: "update ...", Aliases: []string{"up"}, Short: "update one or more Helm plugins", + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compListPlugins(toComplete), cobra.ShellCompDirectiveNoFileComp + }, PreRunE: func(cmd *cobra.Command, args []string) error { return o.complete(args) }, @@ -47,15 +52,6 @@ func newPluginUpdateCmd(out io.Writer) *cobra.Command { return o.run(out) }, } - - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - if len(args) != 0 { - return nil, completion.BashCompDirectiveNoFileComp - } - return compListPlugins(toComplete), completion.BashCompDirectiveNoFileComp - }) - return cmd } diff --git a/cmd/helm/pull.go b/cmd/helm/pull.go index 16cd10467..d10c629db 100644 --- a/cmd/helm/pull.go +++ b/cmd/helm/pull.go @@ -23,7 +23,6 @@ import ( "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" ) @@ -51,6 +50,12 @@ func newPullCmd(out io.Writer) *cobra.Command { Aliases: []string{"fetch"}, Long: pullDesc, Args: require.MinimumNArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compListCharts(toComplete, false) + }, RunE: func(cmd *cobra.Command, args []string) error { client.Settings = settings if client.Version == "" && client.Devel { @@ -69,14 +74,6 @@ func newPullCmd(out io.Writer) *cobra.Command { }, } - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - if len(args) != 0 { - return nil, completion.BashCompDirectiveNoFileComp - } - return compListCharts(toComplete, false) - }) - f := cmd.Flags() f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.") f.BoolVar(&client.Untar, "untar", false, "if set to true, will untar the chart after downloading it") diff --git a/cmd/helm/release_testing.go b/cmd/helm/release_testing.go index 036d96794..37cac6186 100644 --- a/cmd/helm/release_testing.go +++ b/cmd/helm/release_testing.go @@ -24,7 +24,6 @@ import ( "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/cli/output" ) @@ -46,6 +45,12 @@ func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command Short: "run tests for a release", Long: releaseTestHelp, Args: require.ExactArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compListReleases(toComplete, cfg) + }, RunE: func(cmd *cobra.Command, args []string) error { client.Namespace = settings.Namespace() rel, runErr := client.Run(args[0]) @@ -72,14 +77,6 @@ func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command }, } - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - if len(args) != 0 { - return nil, completion.BashCompDirectiveNoFileComp - } - return compListReleases(toComplete, cfg) - }) - f := cmd.Flags() f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") f.BoolVar(&outputLogs, "logs", false, "dump the logs from test pods (this runs after all tests are complete, but before any cleanup)") diff --git a/cmd/helm/repo_remove.go b/cmd/helm/repo_remove.go index 5dad4e5e0..e6e9cb681 100644 --- a/cmd/helm/repo_remove.go +++ b/cmd/helm/repo_remove.go @@ -26,7 +26,6 @@ import ( "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v3/pkg/repo" ) @@ -45,6 +44,9 @@ func newRepoRemoveCmd(out io.Writer) *cobra.Command { Aliases: []string{"rm"}, Short: "remove one or more chart repositories", Args: require.MinimumNArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return compListRepos(toComplete, args), cobra.ShellCompDirectiveNoFileComp + }, RunE: func(cmd *cobra.Command, args []string) error { o.repoFile = settings.RepositoryConfig o.repoCache = settings.RepositoryCache @@ -52,12 +54,6 @@ func newRepoRemoveCmd(out io.Writer) *cobra.Command { return o.run(out) }, } - - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - return compListRepos(toComplete, args), completion.BashCompDirectiveNoFileComp - }) - return cmd } diff --git a/cmd/helm/rollback.go b/cmd/helm/rollback.go index 745e910b2..3b336d0ff 100644 --- a/cmd/helm/rollback.go +++ b/cmd/helm/rollback.go @@ -25,7 +25,6 @@ import ( "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" ) @@ -47,6 +46,12 @@ func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Short: "roll back a release to a previous revision", Long: rollbackDesc, Args: require.MinimumNArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compListReleases(toComplete, cfg) + }, RunE: func(cmd *cobra.Command, args []string) error { if len(args) > 1 { ver, err := strconv.Atoi(args[1]) @@ -65,14 +70,6 @@ func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { }, } - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - if len(args) != 0 { - return nil, completion.BashCompDirectiveNoFileComp - } - return compListReleases(toComplete, cfg) - }) - f := cmd.Flags() f.BoolVar(&client.DryRun, "dry-run", false, "simulate a rollback") f.BoolVar(&client.Recreate, "recreate-pods", false, "performs pods restart for the resource if applicable") diff --git a/cmd/helm/root.go b/cmd/helm/root.go index 143745f29..69f5855d9 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "io" + "log" "strings" "github.com/spf13/cobra" @@ -27,7 +28,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/clientcmd" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/internal/experimental/registry" "helm.sh/helm/v3/pkg/action" ) @@ -70,24 +70,22 @@ By default, the default directories depend on the Operating System. The defaults func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string) *cobra.Command { cmd := &cobra.Command{ - Use: "helm", - Short: "The Helm package manager for Kubernetes.", - Long: globalUsage, - SilenceUsage: true, - BashCompletionFunction: completion.GetBashCustomFunction(), + Use: "helm", + Short: "The Helm package manager for Kubernetes.", + Long: globalUsage, + SilenceUsage: true, } flags := cmd.PersistentFlags() settings.AddFlags(flags) // Setup shell completion for the namespace flag - flag := flags.Lookup("namespace") - completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { + err := cmd.RegisterFlagCompletionFunc("namespace", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if client, err := actionConfig.KubernetesClientSet(); err == nil { // Choose a long enough timeout that the user notices somethings is not working // but short enough that the user is not made to wait very long to := int64(3) - completion.CompDebugln(fmt.Sprintf("About to call kube client for namespaces with timeout of: %d", to)) + cobra.CompDebugln(fmt.Sprintf("About to call kube client for namespaces with timeout of: %d", to), settings.Debug) nsNames := []string{} if namespaces, err := client.CoreV1().Namespaces().List(context.Background(), metav1.ListOptions{TimeoutSeconds: &to}); err == nil { @@ -96,16 +94,19 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string nsNames = append(nsNames, ns.Name) } } - return nsNames, completion.BashCompDirectiveNoFileComp + return nsNames, cobra.ShellCompDirectiveNoFileComp } } - return nil, completion.BashCompDirectiveDefault + return nil, cobra.ShellCompDirectiveDefault }) + if err != nil { + log.Fatal(err) + } + // Setup shell completion for the kube-context flag - flag = flags.Lookup("kube-context") - completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - completion.CompDebugln("About to get the different kube-contexts") + err = cmd.RegisterFlagCompletionFunc("kube-context", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + cobra.CompDebugln("About to get the different kube-contexts", settings.Debug) loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() if len(settings.KubeConfig) > 0 { @@ -120,11 +121,15 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string ctxs = append(ctxs, name) } } - return ctxs, completion.BashCompDirectiveNoFileComp + return ctxs, cobra.ShellCompDirectiveNoFileComp } - return nil, completion.BashCompDirectiveNoFileComp + return nil, cobra.ShellCompDirectiveNoFileComp }) + if err != nil { + log.Fatal(err) + } + // We can safely ignore any errors that flags.Parse encounters since // those errors will be caught later during the call to cmd.Execution. // This call is required to gather configuration information prior to @@ -164,9 +169,6 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string // Hidden documentation generator command: 'helm docs' newDocsCmd(out), - - // Setup the special hidden __complete command to allow for dynamic auto-completion - completion.NewCompleteCmd(settings, out), ) // Add *experimental* subcommands diff --git a/cmd/helm/search_repo.go b/cmd/helm/search_repo.go index c7f0da974..dd530379b 100644 --- a/cmd/helm/search_repo.go +++ b/cmd/helm/search_repo.go @@ -32,7 +32,6 @@ import ( "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/search" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v3/pkg/repo" @@ -290,8 +289,8 @@ func compListChartsOfRepo(repoName string, prefix string) []string { // Provide dynamic auto-completion for commands that operate on charts (e.g., helm show) // When true, the includeFiles argument indicates that completion should include local files (e.g., local charts) -func compListCharts(toComplete string, includeFiles bool) ([]string, completion.BashCompDirective) { - completion.CompDebugln(fmt.Sprintf("compListCharts with toComplete %s", toComplete)) +func compListCharts(toComplete string, includeFiles bool) ([]string, cobra.ShellCompDirective) { + cobra.CompDebugln(fmt.Sprintf("compListCharts with toComplete %s", toComplete), settings.Debug) noSpace := false noFile := false @@ -312,7 +311,7 @@ func compListCharts(toComplete string, includeFiles bool) ([]string, completion. noSpace = true } } - completion.CompDebugln(fmt.Sprintf("Completions after repos: %v", completions)) + cobra.CompDebugln(fmt.Sprintf("Completions after repos: %v", completions), settings.Debug) // Now handle completions for url prefixes for _, url := range []string{"https://", "http://", "file://"} { @@ -328,7 +327,7 @@ func compListCharts(toComplete string, includeFiles bool) ([]string, completion. noSpace = true } } - completion.CompDebugln(fmt.Sprintf("Completions after urls: %v", completions)) + cobra.CompDebugln(fmt.Sprintf("Completions after urls: %v", completions), settings.Debug) // Finally, provide file completion if we need to. // We only do this if: @@ -347,22 +346,22 @@ func compListCharts(toComplete string, includeFiles bool) ([]string, completion. } } } - completion.CompDebugln(fmt.Sprintf("Completions after files: %v", completions)) + cobra.CompDebugln(fmt.Sprintf("Completions after files: %v", completions), settings.Debug) // If the user didn't provide any input to completion, // we provide a hint that a path can also be used if includeFiles && len(toComplete) == 0 { completions = append(completions, "./", "/") } - completion.CompDebugln(fmt.Sprintf("Completions after checking empty input: %v", completions)) + cobra.CompDebugln(fmt.Sprintf("Completions after checking empty input: %v", completions), settings.Debug) - directive := completion.BashCompDirectiveDefault + directive := cobra.ShellCompDirectiveDefault if noFile { - directive = directive | completion.BashCompDirectiveNoFileComp + directive = directive | cobra.ShellCompDirectiveNoFileComp } if noSpace { - directive = directive | completion.BashCompDirectiveNoSpace - // The completion.BashCompDirective flags do not work for zsh right now. + directive = directive | cobra.ShellCompDirectiveNoSpace + // The cobra.ShellCompDirective flags do not work for zsh right now. // We handle it ourselves instead. completions = compEnforceNoSpace(completions) } @@ -380,7 +379,7 @@ func compEnforceNoSpace(completions []string) []string { // We only do this if there is a single choice for completion. if len(completions) == 1 { completions = append(completions, completions[0]+".") - completion.CompDebugln(fmt.Sprintf("compEnforceNoSpace: completions now are %v", completions)) + cobra.CompDebugln(fmt.Sprintf("compEnforceNoSpace: completions now are %v", completions), settings.Debug) } return completions } diff --git a/cmd/helm/show.go b/cmd/helm/show.go index 91c35a53c..c78069a09 100644 --- a/cmd/helm/show.go +++ b/cmd/helm/show.go @@ -23,7 +23,6 @@ import ( "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" ) @@ -63,18 +62,19 @@ func newShowCmd(out io.Writer) *cobra.Command { } // Function providing dynamic auto-completion - validArgsFunc := func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { + validArgsFunc := func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { - return nil, completion.BashCompDirectiveNoFileComp + return nil, cobra.ShellCompDirectiveNoFileComp } return compListCharts(toComplete, true) } all := &cobra.Command{ - Use: "all [CHART]", - Short: "show all information of the chart", - Long: showAllDesc, - Args: require.ExactArgs(1), + Use: "all [CHART]", + Short: "show all information of the chart", + Long: showAllDesc, + Args: require.ExactArgs(1), + ValidArgsFunction: validArgsFunc, RunE: func(cmd *cobra.Command, args []string) error { client.OutputFormat = action.ShowAll output, err := runShow(args, client) @@ -87,10 +87,11 @@ func newShowCmd(out io.Writer) *cobra.Command { } valuesSubCmd := &cobra.Command{ - Use: "values [CHART]", - Short: "show the chart's values", - Long: showValuesDesc, - Args: require.ExactArgs(1), + Use: "values [CHART]", + Short: "show the chart's values", + Long: showValuesDesc, + Args: require.ExactArgs(1), + ValidArgsFunction: validArgsFunc, RunE: func(cmd *cobra.Command, args []string) error { client.OutputFormat = action.ShowValues output, err := runShow(args, client) @@ -103,10 +104,11 @@ func newShowCmd(out io.Writer) *cobra.Command { } chartSubCmd := &cobra.Command{ - Use: "chart [CHART]", - Short: "show the chart's definition", - Long: showChartDesc, - Args: require.ExactArgs(1), + Use: "chart [CHART]", + Short: "show the chart's definition", + Long: showChartDesc, + Args: require.ExactArgs(1), + ValidArgsFunction: validArgsFunc, RunE: func(cmd *cobra.Command, args []string) error { client.OutputFormat = action.ShowChart output, err := runShow(args, client) @@ -119,10 +121,11 @@ func newShowCmd(out io.Writer) *cobra.Command { } readmeSubCmd := &cobra.Command{ - Use: "readme [CHART]", - Short: "show the chart's README", - Long: readmeChartDesc, - Args: require.ExactArgs(1), + Use: "readme [CHART]", + Short: "show the chart's README", + Long: readmeChartDesc, + Args: require.ExactArgs(1), + ValidArgsFunction: validArgsFunc, RunE: func(cmd *cobra.Command, args []string) error { client.OutputFormat = action.ShowReadme output, err := runShow(args, client) @@ -138,9 +141,6 @@ func newShowCmd(out io.Writer) *cobra.Command { for _, subCmd := range cmds { addShowFlags(subCmd, client) showCommand.AddCommand(subCmd) - - // Register the completion function for each subcommand - completion.RegisterValidArgsFunc(subCmd, validArgsFunc) } return showCommand diff --git a/cmd/helm/status.go b/cmd/helm/status.go index 2efb2006c..5913d08df 100644 --- a/cmd/helm/status.go +++ b/cmd/helm/status.go @@ -19,13 +19,13 @@ package main import ( "fmt" "io" + "log" "strings" "time" "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/cli/output" @@ -53,6 +53,12 @@ func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Short: "display the status of the named release", Long: statusHelp, Args: require.ExactArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compListReleases(toComplete, cfg) + }, RunE: func(cmd *cobra.Command, args []string) error { rel, err := client.Run(args[0]) if err != nil { @@ -66,25 +72,21 @@ func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { }, } - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - if len(args) != 0 { - return nil, completion.BashCompDirectiveNoFileComp - } - return compListReleases(toComplete, cfg) - }) - f := cmd.Flags() f.IntVar(&client.Version, "revision", 0, "if set, display the status of the named release with revision") - flag := f.Lookup("revision") - completion.RegisterFlagCompletionFunc(flag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { + + err := cmd.RegisterFlagCompletionFunc("revision", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 1 { return compListRevisions(cfg, args[0]) } - return nil, completion.BashCompDirectiveNoFileComp + return nil, cobra.ShellCompDirectiveNoFileComp }) + if err != nil { + log.Fatal(err) + } + bindOutputFlag(cmd, &outfmt) return cmd diff --git a/cmd/helm/template.go b/cmd/helm/template.go index a4438b50c..0fc29e189 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -28,7 +28,6 @@ import ( "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/cli/values" @@ -56,6 +55,9 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Short: "locally render templates", Long: templateDesc, Args: require.MinimumNArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return compInstall(args, toComplete, client) + }, RunE: func(_ *cobra.Command, args []string) error { client.DryRun = true client.ReleaseName = "RELEASE-NAME" @@ -136,11 +138,6 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { }, } - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - return compInstall(args, toComplete, client) - }) - f := cmd.Flags() addInstallFlags(f, client, valueOpts) f.StringArrayVarP(&showFiles, "show-only", "s", []string{}, "only show manifests rendered from the given templates") diff --git a/cmd/helm/testdata/output/output-comp.txt b/cmd/helm/testdata/output/output-comp.txt index de5f16f1d..be574756b 100644 --- a/cmd/helm/testdata/output/output-comp.txt +++ b/cmd/helm/testdata/output/output-comp.txt @@ -2,3 +2,4 @@ table json yaml :0 +Completion ended with directive: ShellCompDirectiveDefault diff --git a/cmd/helm/testdata/output/plugin_args_comp.txt b/cmd/helm/testdata/output/plugin_args_comp.txt index 8fb01cc23..007112d31 100644 --- a/cmd/helm/testdata/output/plugin_args_comp.txt +++ b/cmd/helm/testdata/output/plugin_args_comp.txt @@ -3,3 +3,4 @@ Namespace: default Num args received: 1 Args received: :4 +Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/cmd/helm/testdata/output/plugin_args_flag_comp.txt b/cmd/helm/testdata/output/plugin_args_flag_comp.txt index 92f0e58a8..c7a09e3fa 100644 --- a/cmd/helm/testdata/output/plugin_args_flag_comp.txt +++ b/cmd/helm/testdata/output/plugin_args_flag_comp.txt @@ -3,3 +3,4 @@ Namespace: default Num args received: 2 Args received: --myflag :4 +Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/cmd/helm/testdata/output/plugin_args_many_args_comp.txt b/cmd/helm/testdata/output/plugin_args_many_args_comp.txt index 86fa768bb..f3c386b6d 100644 --- a/cmd/helm/testdata/output/plugin_args_many_args_comp.txt +++ b/cmd/helm/testdata/output/plugin_args_many_args_comp.txt @@ -3,3 +3,4 @@ Namespace: mynamespace Num args received: 2 Args received: --myflag start :2 +Completion ended with directive: ShellCompDirectiveNoSpace diff --git a/cmd/helm/testdata/output/plugin_args_ns_comp.txt b/cmd/helm/testdata/output/plugin_args_ns_comp.txt index e12867daa..26cd79b98 100644 --- a/cmd/helm/testdata/output/plugin_args_ns_comp.txt +++ b/cmd/helm/testdata/output/plugin_args_ns_comp.txt @@ -3,3 +3,4 @@ Namespace: mynamespace Num args received: 1 Args received: :2 +Completion ended with directive: ShellCompDirectiveNoSpace diff --git a/cmd/helm/testdata/output/plugin_echo_bad_directive.txt b/cmd/helm/testdata/output/plugin_echo_bad_directive.txt index f4b86cd47..8038b9525 100644 --- a/cmd/helm/testdata/output/plugin_echo_bad_directive.txt +++ b/cmd/helm/testdata/output/plugin_echo_bad_directive.txt @@ -3,3 +3,4 @@ Namespace: default Num args received: 1 Args received: :0 +Completion ended with directive: ShellCompDirectiveDefault diff --git a/cmd/helm/testdata/output/plugin_echo_no_directive.txt b/cmd/helm/testdata/output/plugin_echo_no_directive.txt index 6266dd4d9..7001be0e9 100644 --- a/cmd/helm/testdata/output/plugin_echo_no_directive.txt +++ b/cmd/helm/testdata/output/plugin_echo_no_directive.txt @@ -3,3 +3,4 @@ Namespace: mynamespace Num args received: 1 Args received: :0 +Completion ended with directive: ShellCompDirectiveDefault diff --git a/cmd/helm/testdata/output/revision-comp.txt b/cmd/helm/testdata/output/revision-comp.txt index b4799f059..d06947d9d 100644 --- a/cmd/helm/testdata/output/revision-comp.txt +++ b/cmd/helm/testdata/output/revision-comp.txt @@ -3,3 +3,4 @@ 10 11 :0 +Completion ended with directive: ShellCompDirectiveDefault diff --git a/cmd/helm/testdata/output/revision-wrong-args-comp.txt b/cmd/helm/testdata/output/revision-wrong-args-comp.txt index b6f867176..8d9fad576 100644 --- a/cmd/helm/testdata/output/revision-wrong-args-comp.txt +++ b/cmd/helm/testdata/output/revision-wrong-args-comp.txt @@ -1 +1,2 @@ :4 +Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/cmd/helm/testdata/output/status-comp.txt b/cmd/helm/testdata/output/status-comp.txt index c97882964..8d4d21df7 100644 --- a/cmd/helm/testdata/output/status-comp.txt +++ b/cmd/helm/testdata/output/status-comp.txt @@ -1,3 +1,4 @@ aramis athos :4 +Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/cmd/helm/testdata/output/status-wrong-args-comp.txt b/cmd/helm/testdata/output/status-wrong-args-comp.txt index b6f867176..8d9fad576 100644 --- a/cmd/helm/testdata/output/status-wrong-args-comp.txt +++ b/cmd/helm/testdata/output/status-wrong-args-comp.txt @@ -1 +1,2 @@ :4 +Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/cmd/helm/uninstall.go b/cmd/helm/uninstall.go index 85fa822bd..509918e53 100644 --- a/cmd/helm/uninstall.go +++ b/cmd/helm/uninstall.go @@ -24,7 +24,6 @@ import ( "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" ) @@ -48,6 +47,12 @@ func newUninstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Short: "uninstall a release", Long: uninstallDesc, Args: require.MinimumNArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compListReleases(toComplete, cfg) + }, RunE: func(cmd *cobra.Command, args []string) error { for i := 0; i < len(args); i++ { @@ -65,14 +70,6 @@ func newUninstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { }, } - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - if len(args) != 0 { - return nil, completion.BashCompDirectiveNoFileComp - } - return compListReleases(toComplete, cfg) - }) - f := cmd.Flags() f.BoolVar(&client.DryRun, "dry-run", false, "simulate a uninstall") f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during uninstallation") diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index f8103b485..1db899eae 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -25,7 +25,6 @@ import ( "github.com/spf13/cobra" "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/internal/completion" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/cli/output" @@ -72,6 +71,15 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Short: "upgrade a release", Long: upgradeDesc, Args: require.ExactArgs(2), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) == 0 { + return compListReleases(toComplete, cfg) + } + if len(args) == 1 { + return compListCharts(toComplete, true) + } + return nil, cobra.ShellCompDirectiveNoFileComp + }, RunE: func(cmd *cobra.Command, args []string) error { client.Namespace = settings.Namespace() @@ -155,17 +163,6 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { }, } - // Function providing dynamic auto-completion - completion.RegisterValidArgsFunc(cmd, func(cmd *cobra.Command, args []string, toComplete string) ([]string, completion.BashCompDirective) { - if len(args) == 0 { - return compListReleases(toComplete, cfg) - } - if len(args) == 1 { - return compListCharts(toComplete, true) - } - return nil, completion.BashCompDirectiveNoFileComp - }) - f := cmd.Flags() f.BoolVar(&createNamespace, "create-namespace", false, "if --install is set, create the release namespace if not present") f.BoolVarP(&client.Install, "install", "i", false, "if a release by this name doesn't already exist, run an install") diff --git a/internal/completion/complete.go b/internal/completion/complete.go deleted file mode 100644 index 545f5b0dd..000000000 --- a/internal/completion/complete.go +++ /dev/null @@ -1,399 +0,0 @@ -/* -Copyright The Helm Authors. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package completion - -import ( - "errors" - "fmt" - "io" - "log" - "os" - "strings" - - "github.com/spf13/cobra" - "github.com/spf13/pflag" - - "helm.sh/helm/v3/cmd/helm/require" - "helm.sh/helm/v3/pkg/cli" -) - -// ================================================================================== -// The below code supports dynamic shell completion in Go. -// This should ultimately be pushed down into Cobra. -// ================================================================================== - -// CompRequestCmd Hidden command to request completion results from the program. -// Used by the shell completion script. -const CompRequestCmd = "__complete" - -// Global map allowing to find completion functions for commands or flags. -var validArgsFunctions = map[interface{}]func(cmd *cobra.Command, args []string, toComplete string) ([]string, BashCompDirective){} - -// BashCompDirective is a bit map representing the different behaviors the shell -// can be instructed to have once completions have been provided. -type BashCompDirective int - -const ( - // BashCompDirectiveError indicates an error occurred and completions should be ignored. - BashCompDirectiveError BashCompDirective = 1 << iota - - // BashCompDirectiveNoSpace indicates that the shell should not add a space - // after the completion even if there is a single completion provided. - BashCompDirectiveNoSpace - - // BashCompDirectiveNoFileComp indicates that the shell should not provide - // file completion even when no completion is provided. - // This currently does not work for zsh or bash < 4 - BashCompDirectiveNoFileComp - - // BashCompDirectiveDefault indicates to let the shell perform its default - // behavior after completions have been provided. - BashCompDirectiveDefault BashCompDirective = 0 -) - -// GetBashCustomFunction returns the bash code to handle custom go completion -// This should eventually be provided by Cobra -func GetBashCustomFunction() string { - return fmt.Sprintf(` -__helm_custom_func() -{ - __helm_debug "${FUNCNAME[0]}: c is $c, words[@] is ${words[@]}, #words[@] is ${#words[@]}" - __helm_debug "${FUNCNAME[0]}: cur is ${cur}, cword is ${cword}, words is ${words}" - - local out requestComp lastParam lastChar - requestComp="${words[0]} %[1]s ${words[@]:1}" - - lastParam=${words[$((${#words[@]}-1))]} - lastChar=${lastParam:$((${#lastParam}-1)):1} - __helm_debug "${FUNCNAME[0]}: lastParam ${lastParam}, lastChar ${lastChar}" - - if [ -z "${cur}" ] && [ "${lastChar}" != "=" ]; then - # If the last parameter is complete (there is a space following it) - # We add an extra empty parameter so we can indicate this to the go method. - __helm_debug "${FUNCNAME[0]}: Adding extra empty parameter" - requestComp="${requestComp} \"\"" - fi - - __helm_debug "${FUNCNAME[0]}: calling ${requestComp}" - # Use eval to handle any environment variables and such - out=$(eval ${requestComp} 2>/dev/null) - - # Extract the directive int at the very end of the output following a : - directive=${out##*:} - # Remove the directive - out=${out%%:*} - if [ "${directive}" = "${out}" ]; then - # There is not directive specified - directive=0 - fi - __helm_debug "${FUNCNAME[0]}: the completion directive is: ${directive}" - __helm_debug "${FUNCNAME[0]}: the completions are: ${out[*]}" - - if [ $((${directive} & %[2]d)) -ne 0 ]; then - __helm_debug "${FUNCNAME[0]}: received error, completion failed" - else - if [ $((${directive} & %[3]d)) -ne 0 ]; then - if [[ $(type -t compopt) = "builtin" ]]; then - __helm_debug "${FUNCNAME[0]}: activating no space" - compopt -o nospace - fi - fi - if [ $((${directive} & %[4]d)) -ne 0 ]; then - if [[ $(type -t compopt) = "builtin" ]]; then - __helm_debug "${FUNCNAME[0]}: activating no file completion" - compopt +o default - fi - fi - - while IFS='' read -r comp; do - COMPREPLY+=("$comp") - done < <(compgen -W "${out[*]}" -- "$cur") - fi -} -`, CompRequestCmd, BashCompDirectiveError, BashCompDirectiveNoSpace, BashCompDirectiveNoFileComp) -} - -// RegisterValidArgsFunc should be called to register a function to provide argument completion for a command -func RegisterValidArgsFunc(cmd *cobra.Command, f func(cmd *cobra.Command, args []string, toComplete string) ([]string, BashCompDirective)) { - if _, exists := validArgsFunctions[cmd]; exists { - log.Fatal(fmt.Sprintf("RegisterValidArgsFunc: command '%s' already registered", cmd.Name())) - } - validArgsFunctions[cmd] = f -} - -// RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag -func RegisterFlagCompletionFunc(flag *pflag.Flag, f func(cmd *cobra.Command, args []string, toComplete string) ([]string, BashCompDirective)) { - if _, exists := validArgsFunctions[flag]; exists { - log.Fatal(fmt.Sprintf("RegisterFlagCompletionFunc: flag '%s' already registered", flag.Name)) - } - validArgsFunctions[flag] = f - - // Make sure the completion script call the __helm_custom_func for the registered flag. - // This is essential to make the = form work. E.g., helm -n= or helm status --output= - if flag.Annotations == nil { - flag.Annotations = map[string][]string{} - } - flag.Annotations[cobra.BashCompCustom] = []string{"__helm_custom_func"} -} - -var debug = true - -// Returns a string listing the different directive enabled in the specified parameter -func (d BashCompDirective) string() string { - var directives []string - if d&BashCompDirectiveError != 0 { - directives = append(directives, "BashCompDirectiveError") - } - if d&BashCompDirectiveNoSpace != 0 { - directives = append(directives, "BashCompDirectiveNoSpace") - } - if d&BashCompDirectiveNoFileComp != 0 { - directives = append(directives, "BashCompDirectiveNoFileComp") - } - if len(directives) == 0 { - directives = append(directives, "BashCompDirectiveDefault") - } - - if d > BashCompDirectiveError+BashCompDirectiveNoSpace+BashCompDirectiveNoFileComp { - return fmt.Sprintf("ERROR: unexpected BashCompDirective value: %d", d) - } - return strings.Join(directives, ", ") -} - -// NewCompleteCmd add a special hidden command that an be used to request completions -func NewCompleteCmd(settings *cli.EnvSettings, out io.Writer) *cobra.Command { - debug = settings.Debug - return &cobra.Command{ - Use: fmt.Sprintf("%s [command-line]", CompRequestCmd), - DisableFlagsInUseLine: true, - Hidden: true, - DisableFlagParsing: true, - Args: require.MinimumNArgs(1), - Short: "Request shell completion choices for the specified command-line", - Long: fmt.Sprintf("%s is a special command that is used by the shell completion logic\n%s", - CompRequestCmd, "to request completion choices for the specified command-line."), - Run: func(cmd *cobra.Command, args []string) { - CompDebugln(fmt.Sprintf("%s was called with args %v", cmd.Name(), args)) - - // The last argument, which is not complete, should not be part of the list of arguments - toComplete := args[len(args)-1] - trimmedArgs := args[:len(args)-1] - - // Find the real command for which completion must be performed - finalCmd, finalArgs, err := cmd.Root().Find(trimmedArgs) - if err != nil { - // Unable to find the real command. E.g., helm invalidCmd - CompDebugln(fmt.Sprintf("Unable to find a command for arguments: %v", trimmedArgs)) - return - } - - CompDebugln(fmt.Sprintf("Found final command '%s', with finalArgs %v", finalCmd.Name(), finalArgs)) - - var flag *pflag.Flag - if !finalCmd.DisableFlagParsing { - // We only do flag completion if we are allowed to parse flags - // This is important for helm plugins which need to do their own flag completion. - flag, finalArgs, toComplete, err = checkIfFlagCompletion(finalCmd, finalArgs, toComplete) - if err != nil { - // Error while attempting to parse flags - CompErrorln(err.Error()) - return - } - } - - // Parse the flags and extract the arguments to prepare for calling the completion function - if err = finalCmd.ParseFlags(finalArgs); err != nil { - CompErrorln(fmt.Sprintf("Error while parsing flags from args %v: %s", finalArgs, err.Error())) - return - } - - // We only remove the flags from the arguments if DisableFlagParsing is not set. - // This is important for helm plugins, which need to receive all flags. - // The plugin completion code will do its own flag parsing. - if !finalCmd.DisableFlagParsing { - finalArgs = finalCmd.Flags().Args() - CompDebugln(fmt.Sprintf("Args without flags are '%v' with length %d", finalArgs, len(finalArgs))) - } - - // Find completion function for the flag or command - var key interface{} - var keyStr string - if flag != nil { - key = flag - keyStr = flag.Name - } else { - key = finalCmd - keyStr = finalCmd.Name() - } - completionFn, ok := validArgsFunctions[key] - if !ok { - CompErrorln(fmt.Sprintf("Dynamic completion not supported/needed for flag or command: %s", keyStr)) - return - } - - CompDebugln(fmt.Sprintf("Calling completion method for subcommand '%s' with args '%v' and toComplete '%s'", finalCmd.Name(), finalArgs, toComplete)) - completions, directive := completionFn(finalCmd, finalArgs, toComplete) - for _, comp := range completions { - // Print each possible completion to stdout for the completion script to consume. - fmt.Fprintln(out, comp) - } - - if directive > BashCompDirectiveError+BashCompDirectiveNoSpace+BashCompDirectiveNoFileComp { - directive = BashCompDirectiveDefault - } - - // As the last printout, print the completion directive for the - // completion script to parse. - // The directive integer must be that last character following a single : - // The completion script expects :directive - fmt.Fprintf(out, ":%d\n", directive) - - // Print some helpful info to stderr for the user to understand. - // Output from stderr should be ignored from the completion script. - fmt.Fprintf(os.Stderr, "Completion ended with directive: %s\n", directive.string()) - }, - } -} - -func isFlag(arg string) bool { - return len(arg) > 0 && arg[0] == '-' -} - -func checkIfFlagCompletion(finalCmd *cobra.Command, args []string, lastArg string) (*pflag.Flag, []string, string, error) { - var flagName string - trimmedArgs := args - flagWithEqual := false - if isFlag(lastArg) { - if index := strings.Index(lastArg, "="); index >= 0 { - flagName = strings.TrimLeft(lastArg[:index], "-") - lastArg = lastArg[index+1:] - flagWithEqual = true - } else { - return nil, nil, "", errors.New("Unexpected completion request for flag") - } - } - - if len(flagName) == 0 { - if len(args) > 0 { - prevArg := args[len(args)-1] - if isFlag(prevArg) { - // If the flag contains an = it means it has already been fully processed - if index := strings.Index(prevArg, "="); index < 0 { - flagName = strings.TrimLeft(prevArg, "-") - - // Remove the uncompleted flag or else Cobra could complain about - // an invalid value for that flag e.g., helm status --output j - trimmedArgs = args[:len(args)-1] - } - } - } - } - - if len(flagName) == 0 { - // Not doing flag completion - return nil, trimmedArgs, lastArg, nil - } - - flag := findFlag(finalCmd, flagName) - if flag == nil { - // Flag not supported by this command, nothing to complete - err := fmt.Errorf("Subcommand '%s' does not support flag '%s'", finalCmd.Name(), flagName) - return nil, nil, "", err - } - - if !flagWithEqual { - if len(flag.NoOptDefVal) != 0 { - // We had assumed dealing with a two-word flag but the flag is a boolean flag. - // In that case, there is no value following it, so we are not really doing flag completion. - // Reset everything to do argument completion. - trimmedArgs = args - flag = nil - } - } - - return flag, trimmedArgs, lastArg, nil -} - -func findFlag(cmd *cobra.Command, name string) *pflag.Flag { - flagSet := cmd.Flags() - if len(name) == 1 { - // First convert the short flag into a long flag - // as the cmd.Flag() search only accepts long flags - if short := flagSet.ShorthandLookup(name); short != nil { - CompDebugln(fmt.Sprintf("checkIfFlagCompletion: found flag '%s' which we will change to '%s'", name, short.Name)) - name = short.Name - } else { - set := cmd.InheritedFlags() - if short = set.ShorthandLookup(name); short != nil { - CompDebugln(fmt.Sprintf("checkIfFlagCompletion: found inherited flag '%s' which we will change to '%s'", name, short.Name)) - name = short.Name - } else { - return nil - } - } - } - return cmd.Flag(name) -} - -// CompDebug prints the specified string to the same file as where the -// completion script prints its logs. -// Note that completion printouts should never be on stdout as they would -// be wrongly interpreted as actual completion choices by the completion script. -func CompDebug(msg string) { - msg = fmt.Sprintf("[Debug] %s", msg) - - // Such logs are only printed when the user has set the environment - // variable BASH_COMP_DEBUG_FILE to the path of some file to be used. - if path := os.Getenv("BASH_COMP_DEBUG_FILE"); path != "" { - f, err := os.OpenFile(path, - os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err == nil { - defer f.Close() - f.WriteString(msg) - } - } - - if debug { - // Must print to stderr for this not to be read by the completion script. - fmt.Fprintln(os.Stderr, msg) - } -} - -// CompDebugln prints the specified string with a newline at the end -// to the same file as where the completion script prints its logs. -// Such logs are only printed when the user has set the environment -// variable BASH_COMP_DEBUG_FILE to the path of some file to be used. -func CompDebugln(msg string) { - CompDebug(fmt.Sprintf("%s\n", msg)) -} - -// CompError prints the specified completion message to stderr. -func CompError(msg string) { - msg = fmt.Sprintf("[Error] %s", msg) - - CompDebug(msg) - - // If not already printed by the call to CompDebug(). - if !debug { - // Must print to stderr for this not to be read by the completion script. - fmt.Fprintln(os.Stderr, msg) - } -} - -// CompErrorln prints the specified completion message to stderr with a newline at the end. -func CompErrorln(msg string) { - CompError(fmt.Sprintf("%s\n", msg)) -} From 9249530b7739a738e16d5e46195c82df63f00127 Mon Sep 17 00:00:00 2001 From: ZouYu Date: Fri, 12 Jun 2020 09:29:58 +0800 Subject: [PATCH 077/159] Add unit test case Signed-off-by: ZouYu --- internal/urlutil/urlutil_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/urlutil/urlutil_test.go b/internal/urlutil/urlutil_test.go index 8e99c1bfb..82acc40fe 100644 --- a/internal/urlutil/urlutil_test.go +++ b/internal/urlutil/urlutil_test.go @@ -56,6 +56,9 @@ func TestEqual(t *testing.T) { {"/foo", "/foo", true}, {"/foo", "/foo/", true}, {"/foo/.", "/foo/", true}, + {"%/1234", "%/1234", true}, + {"%/1234", "%/123", false}, + {"/1234", "%/1234", false}, } { if tt.match != Equal(tt.a, tt.b) { t.Errorf("Expected %q==%q to be %t", tt.a, tt.b, tt.match) From aa033196692ea9c4416fbb3859bebf05aded6bef Mon Sep 17 00:00:00 2001 From: Adam Reese Date: Fri, 12 Jun 2020 08:39:26 -0700 Subject: [PATCH 078/159] fix(chartutil): do not set helpers.tpl filetype for vim Helpers filetype is not mustache Signed-off-by: Adam Reese --- pkg/chartutil/create.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index 0e87c7b47..e74761b3f 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -386,8 +386,7 @@ const defaultNotes = `1. Get the application URL by running these commands: {{- end }} ` -const defaultHelpers = `{{/* vim: set filetype=mustache: */}} -{{/* +const defaultHelpers = `{{/* Expand the name of the chart. */}} {{- define ".name" -}} From f7c882d55e26958d03c34c9718a964b9a8180da2 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Sun, 14 Jun 2020 11:29:29 -0400 Subject: [PATCH 079/159] feat(cmd): Subcommands for the completion command Making each shell a subcommand of the 'completion' has multiple advantages: - simplifies the code, - allows to have different flags for each shell, for example, a future `--no-descriptions` flag for fish only, - allows to tailor the help text per shell. Signed-off-by: Marc Khouzam --- cmd/helm/completion.go | 81 ++++++++++++++++++++++------------------ cmd/helm/load_plugins.go | 3 +- 2 files changed, 47 insertions(+), 37 deletions(-) diff --git a/cmd/helm/completion.go b/cmd/helm/completion.go index c1f7790bc..696021363 100644 --- a/cmd/helm/completion.go +++ b/cmd/helm/completion.go @@ -21,61 +21,70 @@ import ( "os" "path/filepath" - "github.com/pkg/errors" "github.com/spf13/cobra" + + "helm.sh/helm/v3/cmd/helm/require" ) const completionDesc = ` -Generate autocompletions script for Helm for the specified shell (bash or zsh). +Generate autocompletions script for Helm for the specified shell. +` +const bashCompDesc = ` +Generate the autocompletion script for Helm for the bash shell. -This command can generate shell autocompletions. e.g. +To load completions in your current shell session: +$ source <(helm completion bash) - $ helm completion bash +To load completions for every new session, execute once: +Linux: + $ helm completion bash > /etc/bash_completion.d/helm +MacOS: + $ helm completion bash > /usr/local/etc/bash_completion.d/helm +` -Can be sourced as such +const zshCompDesc = ` +Generate the autocompletion script for Helm for the zsh shell. - $ source <(helm completion bash) -` +To load completions in your current shell session: +$ source <(helm completion zsh) -var ( - completionShells = map[string]func(out io.Writer, cmd *cobra.Command) error{ - "bash": runCompletionBash, - "zsh": runCompletionZsh, - } -) +To load completions for every new session, execute once: +$ helm completion zsh > "${fpath[1]}/_helm" +` func newCompletionCmd(out io.Writer) *cobra.Command { - shells := []string{} - for s := range completionShells { - shells = append(shells, s) - } - cmd := &cobra.Command{ - Use: "completion SHELL", - Short: "generate autocompletions script for the specified shell (bash or zsh)", + Use: "completion", + Short: "generate autocompletions script for the specified shell", Long: completionDesc, + Args: require.NoArgs, + } + + bash := &cobra.Command{ + Use: "bash", + Short: "generate autocompletions script for bash", + Long: bashCompDesc, + Args: require.NoArgs, + DisableFlagsInUseLine: true, RunE: func(cmd *cobra.Command, args []string) error { - return runCompletion(out, cmd, args) + return runCompletionBash(out, cmd) }, - ValidArgs: shells, } - return cmd -} - -func runCompletion(out io.Writer, cmd *cobra.Command, args []string) error { - if len(args) == 0 { - return errors.New("shell not specified") - } - if len(args) > 1 { - return errors.New("too many arguments, expected only the shell type") - } - run, found := completionShells[args[0]] - if !found { - return errors.Errorf("unsupported shell type %q", args[0]) + zsh := &cobra.Command{ + Use: "zsh", + Short: "generate autocompletions script for zsh", + Long: zshCompDesc, + Args: require.NoArgs, + DisableFlagsInUseLine: true, + RunE: func(cmd *cobra.Command, args []string) error { + return runCompletionZsh(out, cmd) + }, } - return run(out, cmd) + cmd.AddCommand(bash, zsh) + + return cmd } func runCompletionBash(out io.Writer, cmd *cobra.Command) error { diff --git a/cmd/helm/load_plugins.go b/cmd/helm/load_plugins.go index e439c8407..a6e0c4eae 100644 --- a/cmd/helm/load_plugins.go +++ b/cmd/helm/load_plugins.go @@ -105,7 +105,8 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) { // We only do this when necessary (for the "completion" and "__complete" commands) to avoid the // risk of a rogue plugin affecting Helm's normal behavior. subCmd, _, err := baseCmd.Find(os.Args[1:]) - if (err == nil && (subCmd.Name() == "completion" || subCmd.Name() == cobra.ShellCompRequestCmd)) || + if (err == nil && + ((subCmd.HasParent() && subCmd.Parent().Name() == "completion") || subCmd.Name() == cobra.ShellCompRequestCmd)) || /* for the tests */ subCmd == baseCmd.Root() { loadCompletionForPlugin(c, plug) } From 4c9972cb7260e6424890c8d839c53ddb5460a6c5 Mon Sep 17 00:00:00 2001 From: Eric Lemieux Date: Mon, 18 Nov 2019 10:19:53 -0500 Subject: [PATCH 080/159] Add HelmVersion to Capabilities Signed-off-by: Eric Lemieux --- pkg/chartutil/capabilities.go | 5 +++++ pkg/chartutil/capabilities_test.go | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/pkg/chartutil/capabilities.go b/pkg/chartutil/capabilities.go index ce968c5d7..adfe2363d 100644 --- a/pkg/chartutil/capabilities.go +++ b/pkg/chartutil/capabilities.go @@ -20,6 +20,8 @@ import ( apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + + helmversion "helm.sh/helm/v3/internal/version" ) var ( @@ -34,6 +36,7 @@ var ( Minor: "18", }, APIVersions: DefaultVersionSet, + HelmVersion: helmversion.Get(), } ) @@ -43,6 +46,8 @@ type Capabilities struct { KubeVersion KubeVersion // APIversions are supported Kubernetes API versions. APIVersions VersionSet + // HelmVersion is the build information for this helm version + HelmVersion helmversion.BuildInfo } // KubeVersion is the Kubernetes version. diff --git a/pkg/chartutil/capabilities_test.go b/pkg/chartutil/capabilities_test.go index 416eea06d..489a472be 100644 --- a/pkg/chartutil/capabilities_test.go +++ b/pkg/chartutil/capabilities_test.go @@ -58,3 +58,11 @@ func TestDefaultCapabilities(t *testing.T) { t.Errorf("Expected default KubeVersion.Minor to be 16, got %q", kv.Minor) } } + +func TestDefaultCapabilitiesHelmVersion(t *testing.T) { + hv := DefaultCapabilities.HelmVersion + + if hv.Version != "v3.2" { + t.Errorf("Expected default HelmVerison to be v3.2, got %q", hv.Version) + } +} From b6bbe4f08bbb98eadd6c9cd726b08a5c639908b3 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Mon, 15 Jun 2020 16:39:39 -0600 Subject: [PATCH 081/159] Improve the extractor and add tests (#8317) Signed-off-by: Matt Butcher --- pkg/plugin/installer/http_installer.go | 61 ++++++++++++++++++++- pkg/plugin/installer/http_installer_test.go | 30 ++++++++++ 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/pkg/plugin/installer/http_installer.go b/pkg/plugin/installer/http_installer.go index c07cad80a..28e50b72b 100644 --- a/pkg/plugin/installer/http_installer.go +++ b/pkg/plugin/installer/http_installer.go @@ -21,10 +21,12 @@ import ( "compress/gzip" "io" "os" + "path" "path/filepath" "regexp" "strings" + securejoin "github.com/cyphar/filepath-securejoin" "github.com/pkg/errors" "helm.sh/helm/v3/internal/third_party/dep/fs" @@ -118,7 +120,7 @@ func (i *HTTPInstaller) Install() error { } if err := i.extractor.Extract(pluginData, i.CacheDir); err != nil { - return err + return errors.Wrap(err, "extracting files from archive") } if !isPlugin(i.CacheDir) { @@ -148,6 +150,58 @@ func (i HTTPInstaller) Path() string { return helmpath.DataPath("plugins", i.PluginName) } +// CleanJoin resolves dest as a subpath of root. +// +// This function runs several security checks on the path, generating an error if +// the supplied `dest` looks suspicious or would result in dubious behavior on the +// filesystem. +// +// CleanJoin assumes that any attempt by `dest` to break out of the CWD is an attempt +// to be malicious. (If you don't care about this, use the securejoin-filepath library.) +// It will emit an error if it detects paths that _look_ malicious, operating on the +// assumption that we don't actually want to do anything with files that already +// appear to be nefarious. +// +// - The character `:` is considered illegal because it is a separator on UNIX and a +// drive designator on Windows. +// - The path component `..` is considered suspicions, and therefore illegal +// - The character \ (backslash) is treated as a path separator and is converted to /. +// - Beginning a path with a path separator is illegal +// - Rudimentary symlink protects are offered by SecureJoin. +func cleanJoin(root, dest string) (string, error) { + + // On Windows, this is a drive separator. On UNIX-like, this is the path list separator. + // In neither case do we want to trust a TAR that contains these. + if strings.Contains(dest, ":") { + return "", errors.New("path contains ':', which is illegal") + } + + // The Go tar library does not convert separators for us. + // We assume here, as we do elsewhere, that `\\` means a Windows path. + dest = strings.ReplaceAll(dest, "\\", "/") + + // We want to alert the user that something bad was attempted. Cleaning it + // is not a good practice. + for _, part := range strings.Split(dest, "/") { + if part == ".." { + return "", errors.New("path contains '..', which is illegal") + } + } + + // If a path is absolute, the creator of the TAR is doing something shady. + if path.IsAbs(dest) { + return "", errors.New("path is absolute, which is illegal") + } + + // SecureJoin will do some cleaning, as well as some rudimentary checking of symlinks. + newpath, err := securejoin.SecureJoin(root, dest) + if err != nil { + return "", err + } + + return filepath.ToSlash(newpath), nil +} + // Extract extracts compressed archives // // Implements Extractor. @@ -171,7 +225,10 @@ func (g *TarGzExtractor) Extract(buffer *bytes.Buffer, targetDir string) error { return err } - path := filepath.Join(targetDir, header.Name) + path, err := cleanJoin(targetDir, header.Name) + if err != nil { + return err + } switch header.Typeflag { case tar.TypeDir: diff --git a/pkg/plugin/installer/http_installer_test.go b/pkg/plugin/installer/http_installer_test.go index 99470ace6..3eb92ee77 100644 --- a/pkg/plugin/installer/http_installer_test.go +++ b/pkg/plugin/installer/http_installer_test.go @@ -277,3 +277,33 @@ func TestExtract(t *testing.T) { } } + +func TestCleanJoin(t *testing.T) { + for i, fixture := range []struct { + path string + expect string + expectError bool + }{ + {"foo/bar.txt", "/tmp/foo/bar.txt", false}, + {"/foo/bar.txt", "", true}, + {"./foo/bar.txt", "/tmp/foo/bar.txt", false}, + {"./././././foo/bar.txt", "/tmp/foo/bar.txt", false}, + {"../../../../foo/bar.txt", "", true}, + {"foo/../../../../bar.txt", "", true}, + {"c:/foo/bar.txt", "/tmp/c:/foo/bar.txt", true}, + {"foo\\bar.txt", "/tmp/foo/bar.txt", false}, + {"c:\\foo\\bar.txt", "", true}, + } { + out, err := cleanJoin("/tmp", fixture.path) + if err != nil { + if !fixture.expectError { + t.Errorf("Test %d: Path was not cleaned: %s", i, err) + } + continue + } + if fixture.expect != out { + t.Errorf("Test %d: Expected %q but got %q", i, fixture.expect, out) + } + } + +} From fd99c9055d3d2bbe2b5a790d5d355f496c4a73f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Tue, 16 Jun 2020 14:34:00 +0200 Subject: [PATCH 082/159] chore(Makefile): Remove unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dep was replaced by go mod Signed-off-by: Manuel Rüger --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 446fbc0ed..524421279 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,6 @@ TARGET_OBJS ?= darwin-amd64.tar.gz darwin-amd64.tar.gz.sha256 darwin-amd64.tar.g BINNAME ?= helm GOPATH = $(shell go env GOPATH) -DEP = $(GOPATH)/bin/dep GOX = $(GOPATH)/bin/gox GOIMPORTS = $(GOPATH)/bin/goimports ARCH = $(shell uname -p) From 561cc4280830af4a40f2e60c5f17fb3ee69b4e39 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Fri, 12 Jun 2020 08:24:55 -0400 Subject: [PATCH 083/159] feat(comp): Provide completion for --version flag This commit allows to use shell completion to obtain the list of available versions of a chart referenced in a 'repo/chart' format. It applies to: - helm install - helm template - helm upgrade - helm show - helm pull The 'repo/chart' argument must be present for completion to be triggered (or else we don't yet know which chart to fetch the versions for). The completion can be slow for the 'stable' repo because its index file takes some time to parse. Signed-off-by: Marc Khouzam --- cmd/helm/flags.go | 27 +++++++++++++ cmd/helm/install.go | 20 +++++++++- cmd/helm/install_test.go | 31 +++++++++++++++ cmd/helm/pull.go | 12 ++++++ cmd/helm/pull_test.go | 26 +++++++++++++ cmd/helm/show.go | 12 ++++++ cmd/helm/show_test.go | 38 +++++++++++++++++++ cmd/helm/template.go | 2 +- cmd/helm/template_test.go | 30 +++++++++++++++ cmd/helm/testdata/output/version-comp.txt | 5 +++ .../testdata/output/version-invalid-comp.txt | 2 + cmd/helm/upgrade.go | 12 ++++++ cmd/helm/upgrade_test.go | 26 +++++++++++++ 13 files changed, 240 insertions(+), 3 deletions(-) create mode 100644 cmd/helm/testdata/output/version-comp.txt create mode 100644 cmd/helm/testdata/output/version-invalid-comp.txt diff --git a/cmd/helm/flags.go b/cmd/helm/flags.go index d4cd88fef..040773d7b 100644 --- a/cmd/helm/flags.go +++ b/cmd/helm/flags.go @@ -19,6 +19,7 @@ package main import ( "fmt" "log" + "path/filepath" "strings" "github.com/spf13/cobra" @@ -27,7 +28,9 @@ import ( "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v3/pkg/cli/values" + "helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v3/pkg/postrender" + "helm.sh/helm/v3/pkg/repo" ) const outputFlag = "output" @@ -127,3 +130,27 @@ func (p postRenderer) Set(s string) error { *p.renderer = pr return nil } + +func compVersionFlag(chartRef string, toComplete string) ([]string, cobra.ShellCompDirective) { + chartInfo := strings.Split(chartRef, "/") + if len(chartInfo) != 2 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + + repoName := chartInfo[0] + chartName := chartInfo[1] + + path := filepath.Join(settings.RepositoryCache, helmpath.CacheIndexFile(repoName)) + + var versions []string + if indexFile, err := repo.LoadIndexFile(path); err == nil { + for _, details := range indexFile.Entries[chartName] { + version := details.Metadata.Version + if strings.HasPrefix(version, toComplete) { + versions = append(versions, version) + } + } + } + + return versions, cobra.ShellCompDirectiveNoFileComp +} diff --git a/cmd/helm/install.go b/cmd/helm/install.go index b489c262d..9024add2f 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -19,6 +19,7 @@ package main import ( "fmt" "io" + "log" "time" "github.com/pkg/errors" @@ -126,14 +127,14 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { }, } - addInstallFlags(cmd.Flags(), client, valueOpts) + addInstallFlags(cmd, cmd.Flags(), client, valueOpts) bindOutputFlag(cmd, &outfmt) bindPostRenderFlag(cmd, &client.PostRenderer) return cmd } -func addInstallFlags(f *pflag.FlagSet, client *action.Install, valueOpts *values.Options) { +func addInstallFlags(cmd *cobra.Command, f *pflag.FlagSet, client *action.Install, valueOpts *values.Options) { f.BoolVar(&client.CreateNamespace, "create-namespace", false, "create the release namespace if not present") f.BoolVar(&client.DryRun, "dry-run", false, "simulate an install") f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during install") @@ -151,6 +152,21 @@ func addInstallFlags(f *pflag.FlagSet, client *action.Install, valueOpts *values f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent") addValueOptionsFlags(f, valueOpts) addChartPathOptionsFlags(f, &client.ChartPathOptions) + + err := cmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + requiredArgs := 2 + if client.GenerateName { + requiredArgs = 1 + } + if len(args) != requiredArgs { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compVersionFlag(args[requiredArgs-1], toComplete) + }) + + if err != nil { + log.Fatal(err) + } } func runInstall(args []string, client *action.Install, valueOpts *values.Options, out io.Writer) (*release.Release, error) { diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go index 7a101940f..36de648f9 100644 --- a/cmd/helm/install_test.go +++ b/cmd/helm/install_test.go @@ -17,6 +17,7 @@ limitations under the License. package main import ( + "fmt" "testing" ) @@ -208,3 +209,33 @@ func TestInstall(t *testing.T) { func TestInstallOutputCompletion(t *testing.T) { outputFlagCompletionTest(t, "install") } + +func TestInstallVersionCompletion(t *testing.T) { + repoFile := "testdata/helmhome/helm/repositories.yaml" + repoCache := "testdata/helmhome/helm/repository" + + repoSetup := fmt.Sprintf("--repository-config %s --repository-cache %s", repoFile, repoCache) + + tests := []cmdTestCase{{ + name: "completion for install version flag with release name", + cmd: fmt.Sprintf("%s __complete install releasename testing/alpine --version ''", repoSetup), + golden: "output/version-comp.txt", + }, { + name: "completion for install version flag with generate-name", + cmd: fmt.Sprintf("%s __complete install --generate-name testing/alpine --version ''", repoSetup), + golden: "output/version-comp.txt", + }, { + name: "completion for install version flag too few args", + cmd: fmt.Sprintf("%s __complete install testing/alpine --version ''", repoSetup), + golden: "output/version-invalid-comp.txt", + }, { + name: "completion for install version flag too many args", + cmd: fmt.Sprintf("%s __complete install releasename testing/alpine badarg --version ''", repoSetup), + golden: "output/version-invalid-comp.txt", + }, { + name: "completion for install version flag invalid chart", + cmd: fmt.Sprintf("%s __complete install releasename invalid/invalid --version ''", repoSetup), + golden: "output/version-invalid-comp.txt", + }} + runTestCmd(t, tests) +} diff --git a/cmd/helm/pull.go b/cmd/helm/pull.go index d10c629db..3f62bf0c7 100644 --- a/cmd/helm/pull.go +++ b/cmd/helm/pull.go @@ -19,6 +19,7 @@ package main import ( "fmt" "io" + "log" "github.com/spf13/cobra" @@ -82,5 +83,16 @@ func newPullCmd(out io.Writer) *cobra.Command { f.StringVarP(&client.DestDir, "destination", "d", ".", "location to write the chart. If this and tardir are specified, tardir is appended to this") addChartPathOptionsFlags(f, &client.ChartPathOptions) + err := cmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 1 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compVersionFlag(args[0], toComplete) + }) + + if err != nil { + log.Fatal(err) + } + return cmd } diff --git a/cmd/helm/pull_test.go b/cmd/helm/pull_test.go index d4661f928..435df51f1 100644 --- a/cmd/helm/pull_test.go +++ b/cmd/helm/pull_test.go @@ -195,3 +195,29 @@ func TestPullCmd(t *testing.T) { }) } } + +func TestPullVersionCompletion(t *testing.T) { + repoFile := "testdata/helmhome/helm/repositories.yaml" + repoCache := "testdata/helmhome/helm/repository" + + repoSetup := fmt.Sprintf("--repository-config %s --repository-cache %s", repoFile, repoCache) + + tests := []cmdTestCase{{ + name: "completion for pull version flag", + cmd: fmt.Sprintf("%s __complete pull testing/alpine --version ''", repoSetup), + golden: "output/version-comp.txt", + }, { + name: "completion for pull version flag too few args", + cmd: fmt.Sprintf("%s __complete pull --version ''", repoSetup), + golden: "output/version-invalid-comp.txt", + }, { + name: "completion for pull version flag too many args", + cmd: fmt.Sprintf("%s __complete pull testing/alpine badarg --version ''", repoSetup), + golden: "output/version-invalid-comp.txt", + }, { + name: "completion for pull version flag invalid chart", + cmd: fmt.Sprintf("%s __complete pull invalid/invalid --version ''", repoSetup), + golden: "output/version-invalid-comp.txt", + }} + runTestCmd(t, tests) +} diff --git a/cmd/helm/show.go b/cmd/helm/show.go index c78069a09..c122d8476 100644 --- a/cmd/helm/show.go +++ b/cmd/helm/show.go @@ -19,6 +19,7 @@ package main import ( "fmt" "io" + "log" "github.com/spf13/cobra" @@ -151,6 +152,17 @@ func addShowFlags(subCmd *cobra.Command, client *action.Show) { f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored") addChartPathOptionsFlags(f, &client.ChartPathOptions) + + err := subCmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 1 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compVersionFlag(args[0], toComplete) + }) + + if err != nil { + log.Fatal(err) + } } func runShow(args []string, client *action.Show) (string, error) { diff --git a/cmd/helm/show_test.go b/cmd/helm/show_test.go index 00d7c8145..6c550282f 100644 --- a/cmd/helm/show_test.go +++ b/cmd/helm/show_test.go @@ -80,3 +80,41 @@ func TestShowPreReleaseChart(t *testing.T) { }) } } + +func TestShowVersionCompletion(t *testing.T) { + repoFile := "testdata/helmhome/helm/repositories.yaml" + repoCache := "testdata/helmhome/helm/repository" + + repoSetup := fmt.Sprintf("--repository-config %s --repository-cache %s", repoFile, repoCache) + + tests := []cmdTestCase{{ + name: "completion for show version flag", + cmd: fmt.Sprintf("%s __complete show chart testing/alpine --version ''", repoSetup), + golden: "output/version-comp.txt", + }, { + name: "completion for show version flag too few args", + cmd: fmt.Sprintf("%s __complete show chart --version ''", repoSetup), + golden: "output/version-invalid-comp.txt", + }, { + name: "completion for show version flag too many args", + cmd: fmt.Sprintf("%s __complete show chart testing/alpine badarg --version ''", repoSetup), + golden: "output/version-invalid-comp.txt", + }, { + name: "completion for show version flag invalid chart", + cmd: fmt.Sprintf("%s __complete show chart invalid/invalid --version ''", repoSetup), + golden: "output/version-invalid-comp.txt", + }, { + name: "completion for show version flag with all", + cmd: fmt.Sprintf("%s __complete show all testing/alpine --version ''", repoSetup), + golden: "output/version-comp.txt", + }, { + name: "completion for show version flag with readme", + cmd: fmt.Sprintf("%s __complete show readme testing/alpine --version ''", repoSetup), + golden: "output/version-comp.txt", + }, { + name: "completion for show version flag with values", + cmd: fmt.Sprintf("%s __complete show values testing/alpine --version ''", repoSetup), + golden: "output/version-comp.txt", + }} + runTestCmd(t, tests) +} diff --git a/cmd/helm/template.go b/cmd/helm/template.go index 0fc29e189..83ad61f22 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -139,7 +139,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } f := cmd.Flags() - addInstallFlags(f, client, valueOpts) + addInstallFlags(cmd, f, client, valueOpts) f.StringArrayVarP(&showFiles, "show-only", "s", []string{}, "only show manifests rendered from the given templates") f.StringVar(&client.OutputDir, "output-dir", "", "writes the executed templates to files in output-dir instead of stdout") f.BoolVar(&validate, "validate", false, "validate your manifests against the Kubernetes cluster you are currently pointing at. This is the same validation performed on an install") diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go index 92dd9825e..f8cd31347 100644 --- a/cmd/helm/template_test.go +++ b/cmd/helm/template_test.go @@ -124,3 +124,33 @@ func TestTemplateCmd(t *testing.T) { } runTestCmd(t, tests) } + +func TestTemplateVersionCompletion(t *testing.T) { + repoFile := "testdata/helmhome/helm/repositories.yaml" + repoCache := "testdata/helmhome/helm/repository" + + repoSetup := fmt.Sprintf("--repository-config %s --repository-cache %s", repoFile, repoCache) + + tests := []cmdTestCase{{ + name: "completion for template version flag with release name", + cmd: fmt.Sprintf("%s __complete template releasename testing/alpine --version ''", repoSetup), + golden: "output/version-comp.txt", + }, { + name: "completion for template version flag with generate-name", + cmd: fmt.Sprintf("%s __complete template --generate-name testing/alpine --version ''", repoSetup), + golden: "output/version-comp.txt", + }, { + name: "completion for template version flag too few args", + cmd: fmt.Sprintf("%s __complete template testing/alpine --version ''", repoSetup), + golden: "output/version-invalid-comp.txt", + }, { + name: "completion for template version flag too many args", + cmd: fmt.Sprintf("%s __complete template releasename testing/alpine badarg --version ''", repoSetup), + golden: "output/version-invalid-comp.txt", + }, { + name: "completion for template version flag invalid chart", + cmd: fmt.Sprintf("%s __complete template releasename invalid/invalid --version ''", repoSetup), + golden: "output/version-invalid-comp.txt", + }} + runTestCmd(t, tests) +} diff --git a/cmd/helm/testdata/output/version-comp.txt b/cmd/helm/testdata/output/version-comp.txt new file mode 100644 index 000000000..098e2cec2 --- /dev/null +++ b/cmd/helm/testdata/output/version-comp.txt @@ -0,0 +1,5 @@ +0.3.0-rc.1 +0.2.0 +0.1.0 +:4 +Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/cmd/helm/testdata/output/version-invalid-comp.txt b/cmd/helm/testdata/output/version-invalid-comp.txt new file mode 100644 index 000000000..8d9fad576 --- /dev/null +++ b/cmd/helm/testdata/output/version-invalid-comp.txt @@ -0,0 +1,2 @@ +:4 +Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index 1db899eae..dc3bc9a58 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -19,6 +19,7 @@ package main import ( "fmt" "io" + "log" "time" "github.com/pkg/errors" @@ -188,5 +189,16 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { bindOutputFlag(cmd, &outfmt) bindPostRenderFlag(cmd, &client.PostRenderer) + err := cmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 2 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compVersionFlag(args[1], toComplete) + }) + + if err != nil { + log.Fatal(err) + } + return cmd } diff --git a/cmd/helm/upgrade_test.go b/cmd/helm/upgrade_test.go index 6f260ae57..7e88bc0df 100644 --- a/cmd/helm/upgrade_test.go +++ b/cmd/helm/upgrade_test.go @@ -381,3 +381,29 @@ func prepareMockRelease(releaseName string, t *testing.T) (func(n string, v int, func TestUpgradeOutputCompletion(t *testing.T) { outputFlagCompletionTest(t, "upgrade") } + +func TestUpgradeVersionCompletion(t *testing.T) { + repoFile := "testdata/helmhome/helm/repositories.yaml" + repoCache := "testdata/helmhome/helm/repository" + + repoSetup := fmt.Sprintf("--repository-config %s --repository-cache %s", repoFile, repoCache) + + tests := []cmdTestCase{{ + name: "completion for upgrade version flag", + cmd: fmt.Sprintf("%s __complete upgrade releasename testing/alpine --version ''", repoSetup), + golden: "output/version-comp.txt", + }, { + name: "completion for upgrade version flag too few args", + cmd: fmt.Sprintf("%s __complete upgrade releasename --version ''", repoSetup), + golden: "output/version-invalid-comp.txt", + }, { + name: "completion for upgrade version flag too many args", + cmd: fmt.Sprintf("%s __complete upgrade releasename testing/alpine badarg --version ''", repoSetup), + golden: "output/version-invalid-comp.txt", + }, { + name: "completion for upgrade version flag invalid chart", + cmd: fmt.Sprintf("%s __complete upgrade releasename invalid/invalid --version ''", repoSetup), + golden: "output/version-invalid-comp.txt", + }} + runTestCmd(t, tests) +} From 569ad27f2bc16b7b407e8a464e70e70cac9a43a8 Mon Sep 17 00:00:00 2001 From: vitt-bagal <31851690+vitt-bagal@users.noreply.github.com> Date: Mon, 22 Jun 2020 20:50:54 +0530 Subject: [PATCH 084/159] remove s390x arch check Signed-off-by: vitthalb@us.ibm.com --- scripts/get-helm-3 | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/get-helm-3 b/scripts/get-helm-3 index 22a93aa0e..ce9411edc 100755 --- a/scripts/get-helm-3 +++ b/scripts/get-helm-3 @@ -33,7 +33,6 @@ initArch() { x86_64) ARCH="amd64";; i686) ARCH="386";; i386) ARCH="386";; - s390x) ARCH="s390x";; esac } From 148d94bcf781bdbf4c735ad0defdee15961389ec Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 23 Jun 2020 11:07:48 -0700 Subject: [PATCH 085/159] version bump Signed-off-by: Matthew Fisher --- .../helm/repository/test-name-charts.txt | 0 .../helm/repository/test-name-index.yaml | 3 + .../testdata/output/schema-negative-cli.txt | 2 +- cmd/helm/testdata/output/schema-negative.txt | 2 +- .../output/subchart-schema-cli-negative.txt | 2 +- go.mod | 32 +-- go.sum | 244 +++++++++++++++--- pkg/chartutil/jsonschema_test.go | 2 +- 8 files changed, 238 insertions(+), 49 deletions(-) create mode 100644 cmd/helm/testdata/helmhome/helm/repository/test-name-charts.txt create mode 100644 cmd/helm/testdata/helmhome/helm/repository/test-name-index.yaml diff --git a/cmd/helm/testdata/helmhome/helm/repository/test-name-charts.txt b/cmd/helm/testdata/helmhome/helm/repository/test-name-charts.txt new file mode 100644 index 000000000..e69de29bb diff --git a/cmd/helm/testdata/helmhome/helm/repository/test-name-index.yaml b/cmd/helm/testdata/helmhome/helm/repository/test-name-index.yaml new file mode 100644 index 000000000..895e79d39 --- /dev/null +++ b/cmd/helm/testdata/helmhome/helm/repository/test-name-index.yaml @@ -0,0 +1,3 @@ +apiVersion: v1 +entries: {} +generated: "2020-06-23T10:01:59.2530763-07:00" diff --git a/cmd/helm/testdata/output/schema-negative-cli.txt b/cmd/helm/testdata/output/schema-negative-cli.txt index 26bc92b1b..d6f096e14 100644 --- a/cmd/helm/testdata/output/schema-negative-cli.txt +++ b/cmd/helm/testdata/output/schema-negative-cli.txt @@ -1,4 +1,4 @@ Error: values don't meet the specifications of the schema(s) in the following chart(s): empty: -- age: Must be greater than or equal to 0/1 +- age: Must be greater than or equal to 0 diff --git a/cmd/helm/testdata/output/schema-negative.txt b/cmd/helm/testdata/output/schema-negative.txt index 2ea97b7d0..f7c89dd56 100644 --- a/cmd/helm/testdata/output/schema-negative.txt +++ b/cmd/helm/testdata/output/schema-negative.txt @@ -1,5 +1,5 @@ Error: values don't meet the specifications of the schema(s) in the following chart(s): empty: - (root): employmentInfo is required -- age: Must be greater than or equal to 0/1 +- age: Must be greater than or equal to 0 diff --git a/cmd/helm/testdata/output/subchart-schema-cli-negative.txt b/cmd/helm/testdata/output/subchart-schema-cli-negative.txt index 86f6e87a2..c0883a8e8 100644 --- a/cmd/helm/testdata/output/subchart-schema-cli-negative.txt +++ b/cmd/helm/testdata/output/subchart-schema-cli-negative.txt @@ -1,4 +1,4 @@ Error: values don't meet the specifications of the schema(s) in the following chart(s): subchart-with-schema: -- age: Must be greater than or equal to 0/1 +- age: Must be greater than or equal to 0 diff --git a/go.mod b/go.mod index f23d152a2..08eae92fa 100644 --- a/go.mod +++ b/go.mod @@ -7,10 +7,10 @@ require ( github.com/DATA-DOG/go-sqlmock v1.4.1 github.com/Masterminds/semver/v3 v3.1.0 github.com/Masterminds/sprig/v3 v3.1.0 - github.com/Masterminds/squirrel v1.2.0 + github.com/Masterminds/squirrel v1.4.0 github.com/Masterminds/vcs v1.13.1 - github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 - github.com/containerd/containerd v1.3.2 + github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 + github.com/containerd/containerd v1.3.4 github.com/cyphar/filepath-securejoin v0.2.2 github.com/deislabs/oras v0.8.1 github.com/docker/distribution v2.7.1+incompatible @@ -21,26 +21,26 @@ require ( github.com/gofrs/flock v0.7.1 github.com/gosuri/uitable v0.0.4 github.com/jmoiron/sqlx v1.2.0 - github.com/lib/pq v1.3.0 + github.com/lib/pq v1.7.0 github.com/mattn/go-shellwords v1.0.10 github.com/mitchellh/copystructure v1.0.0 - github.com/opencontainers/go-digest v1.0.0-rc1 + github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.1 github.com/pkg/errors v0.9.1 - github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3 - github.com/sirupsen/logrus v1.4.2 + github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 + github.com/sirupsen/logrus v1.6.0 github.com/spf13/cobra v1.0.0 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.5.1 - github.com/xeipuuv/gojsonschema v1.1.0 - golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 - k8s.io/api v0.18.2 - k8s.io/apiextensions-apiserver v0.18.2 - k8s.io/apimachinery v0.18.2 - k8s.io/cli-runtime v0.18.2 - k8s.io/client-go v0.18.2 + github.com/stretchr/testify v1.6.1 + github.com/xeipuuv/gojsonschema v1.2.0 + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 + k8s.io/api v0.18.4 + k8s.io/apiextensions-apiserver v0.18.4 + k8s.io/apimachinery v0.18.4 + k8s.io/cli-runtime v0.18.4 + k8s.io/client-go v0.18.4 k8s.io/klog v1.0.0 - k8s.io/kubectl v0.18.2 + k8s.io/kubectl v0.18.4 sigs.k8s.io/yaml v1.2.0 ) diff --git a/go.sum b/go.sum index 2908f3eb8..0d0ef8c83 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,7 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM= github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= @@ -33,8 +34,8 @@ github.com/Masterminds/semver/v3 v3.1.0 h1:Y2lUDsFKVRSYGojLJ1yLxSXdMmMYTYls0rCvo github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/sprig/v3 v3.1.0 h1:j7GpgZ7PdFqNsmncycTHsLmVPf5/3wJtlgW9TNDYD9Y= github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA= -github.com/Masterminds/squirrel v1.2.0 h1:K1NhbTO21BWG47IVR0OnIZuE0LZcXAYqywrC3Ko53KI= -github.com/Masterminds/squirrel v1.2.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA= +github.com/Masterminds/squirrel v1.4.0 h1:he5i/EXixZxrBUWcxzDYMiju9WZ3ld/l7QBNuo/eN3w= +github.com/Masterminds/squirrel v1.4.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA= github.com/Masterminds/vcs v1.13.1 h1:NL3G1X7/7xduQtA2sJLpVpfHTNBALVNSjob6KEjPXNQ= github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA= @@ -52,21 +53,37 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 h1:zV3ejI06GQ59hwDQAvmK1qxOQGB3WuVTRoY0okPTAv0= -github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= +github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= @@ -82,23 +99,35 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembj github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.2 h1:ForxmXkA6tPIvffbrDAcPUIB32QgXkt2XFj+F0UxetA= github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.4 h1:3o0smo5SKY7H6AJCmJhsnCjR2/V2T8VmiHt7seN2/kI= +github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41 h1:kIFnQBO7rQ0XkMe6xEwbybYHBEaWmh/f++laI6Emt7M= github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448 h1:PUD50EuOMkXVcpBIA/R95d56duJR9VxhwncsFbNnxW4= github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de h1:dlfGmNcE3jDAecLqwKPMNX6nk2qh1c1Vg1/YTzpOOF4= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd h1:JNn81o/xG+8NEo3bC/vx9pbi/g2WI8mtP2/nXzu297Y= github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -113,6 +142,7 @@ github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfc github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -153,13 +183,19 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QL github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -168,6 +204,8 @@ github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZM github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7 h1:LofdAjjjqCSXMwLGgOgnE+rdPuvX9DxCqaHwKy7i/ko= @@ -179,8 +217,11 @@ github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0 github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= @@ -245,9 +286,12 @@ github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kE github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godror/godror v0.13.3/go.mod h1:2ouUT4kdhUBk7TAkHWD4SN0CdI0pgEQbo8FVHhbSKWg= github.com/gofrs/flock v0.7.1 h1:DP+LD/t0njgoPBvT5MJLeliUIVQR03hiKR6vezdwHlc= github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -258,6 +302,8 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 h1:LbsanbbD6LieF github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -265,6 +311,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= @@ -273,6 +320,7 @@ github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= @@ -281,6 +329,7 @@ github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -292,10 +341,14 @@ github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTV github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 h1:893HsJqtxp9z1SF76gg6hY70hRY1wVlTSnC/h1yUDCo= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.2 h1:zoNxOV7WjqXptQOVngLmcSQgXmgk4NMz1HibBchjl/I= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= @@ -307,25 +360,44 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= @@ -344,6 +416,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -357,11 +431,14 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhR github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= -github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY= +github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -376,6 +453,7 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-oci8 v0.0.7/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -386,12 +464,18 @@ github.com/mattn/go-sqlite3 v1.12.0 h1:u/x3mp++qUxvYfulZ4HKOvVO0JWhk7HtE8lWhbGz/ github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f h1:2+myh5ml7lgEU/51gbeLHfKGNfgEQQIWrlbdaOsidbQ= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= @@ -409,84 +493,128 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700 h1:eNUVfm/RFLIi1G7flU5/ZRTHvd4kcVuzfRnL6OFlzCI= github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0 h1:miYCvYqFXtl/J9FIy8eNpBfYthAEFg+Ys0XyUVEcDsc= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.4.0 h1:LUa41nrWTQNGhzdsZ5lTnkwbNjj6rXTdazA1cSdjkOY= github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3 h1:xkBtI5JktwbW/vf4vopBbhYsRFTGfQWHYXzC0/qYwxI= -github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3/go.mod h1:rtQlpHw+eR6UrqaS3kX1VYeaCxzCVdimDS7g5Ln4pPc= +github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 h1:HXr/qUllAWv9riaI4zh2eXWKmCSDqVS/XH1MRHLKRwk= +github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351/go.mod h1:DCgfY80j8GYL7MLEfvcpSFvjD0L5yZq/aZUJmhZklyg= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -495,9 +623,13 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= @@ -520,8 +652,12 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -529,6 +665,9 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8 h1:zLV6q4e8Jv9EHjNg/iHfzwDkCve6Ua5jCygptrtXHvI= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -537,14 +676,15 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= -github.com/xeipuuv/gojsonschema v1.1.0 h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg= -github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= @@ -562,42 +702,62 @@ go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mI go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEBT6lE4eh+jOh886GHrn6V8= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -628,8 +788,10 @@ golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -641,11 +803,14 @@ golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7 h1:HmbHVPwrPEKPGLAcHSrMe6+hqSUlvZU0rab6x5EXfGU= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f h1:68K/z8GLUxV76xGSqwTWw2gyk/jwn79LUL43rES2g8o= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -655,7 +820,10 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -668,14 +836,21 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= @@ -685,12 +860,16 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -706,6 +885,7 @@ gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/gorp.v1 v1.7.2 h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw= gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= @@ -716,6 +896,7 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -723,37 +904,41 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.18.2 h1:wG5g5ZmSVgm5B+eHMIbI9EGATS2L8Z72rda19RIEgY8= -k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= -k8s.io/apiextensions-apiserver v0.18.2 h1:I4v3/jAuQC+89L3Z7dDgAiN4EOjN6sbm6iBqQwHTah8= -k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= -k8s.io/apimachinery v0.18.2 h1:44CmtbmkzVDAhCpRVSiP2R5PPrC2RtlIv/MoB8xpdRA= -k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= -k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= -k8s.io/cli-runtime v0.18.2 h1:JiTN5RgkFNTiMxHBRyrl6n26yKWAuNRlei1ZJALUmC8= -k8s.io/cli-runtime v0.18.2/go.mod h1:yfFR2sQQzDsV0VEKGZtrJwEy4hLZ2oj4ZIfodgxAHWQ= -k8s.io/client-go v0.18.2 h1:aLB0iaD4nmwh7arT2wIn+lMnAq7OswjaejkQ8p9bBYE= -k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= -k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= -k8s.io/component-base v0.18.2 h1:SJweNZAGcUvsypLGNPNGeJ9UgPZQ6+bW+gEHe8uyh/Y= -k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.18.4 h1:8x49nBRxuXGUlDlwlWd3RMY1SayZrzFfxea3UZSkFw4= +k8s.io/api v0.18.4/go.mod h1:lOIQAKYgai1+vz9J7YcDZwC26Z0zQewYOGWdyIPUUQ4= +k8s.io/apiextensions-apiserver v0.18.4 h1:Y3HGERmS8t9u12YNUFoOISqefaoGRuTc43AYCLzWmWE= +k8s.io/apiextensions-apiserver v0.18.4/go.mod h1:NYeyeYq4SIpFlPxSAB6jHPIdvu3hL0pc36wuRChybio= +k8s.io/apimachinery v0.18.4 h1:ST2beySjhqwJoIFk6p7Hp5v5O0hYY6Gngq/gUYXTPIA= +k8s.io/apimachinery v0.18.4/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= +k8s.io/apiserver v0.18.4/go.mod h1:q+zoFct5ABNnYkGIaGQ3bcbUNdmPyOCoEBcg51LChY8= +k8s.io/cli-runtime v0.18.4 h1:IUx7quIOb4gbQ4M+B1ksF/PTBovQuL5tXWzplX3t+FM= +k8s.io/cli-runtime v0.18.4/go.mod h1:9/hS/Cuf7NVzWR5F/5tyS6xsnclxoPLVtwhnkJG1Y4g= +k8s.io/client-go v0.18.4 h1:un55V1Q/B3JO3A76eS0kUSywgGK/WR3BQ8fHQjNa6Zc= +k8s.io/client-go v0.18.4/go.mod h1:f5sXwL4yAZRkAtzOxRWUhA/N8XzGCb+nPZI8PfobZ9g= +k8s.io/code-generator v0.18.4/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= +k8s.io/component-base v0.18.4 h1:Kr53Fp1iCGNsl9Uv4VcRvLy7YyIqi9oaJOQ7SXtKI98= +k8s.io/component-base v0.18.4/go.mod h1:7jr/Ef5PGmKwQhyAz/pjByxJbC58mhKAhiaDu0vXfPk= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c h1:/KUFqjjqAcY4Us6luF5RDNZ16KJtb49HfR3ZHB9qYXM= -k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/kubectl v0.18.2 h1:9jnGSOC2DDVZmMUTMi0D1aed438mfQcgqa5TAzVjA1k= -k8s.io/kubectl v0.18.2/go.mod h1:OdgFa3AlsPKRpFFYE7ICTwulXOcMGXHTc+UKhHKvrb4= +k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOECPVeXsVot0UkiaCGVyfGQY= +k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +k8s.io/kubectl v0.18.4 h1:l9DUYPTEMs1+qNtoqPpTyaJOosvj7l7tQqphCO1K52s= +k8s.io/kubectl v0.18.4/go.mod h1:EzB+nfeUWk6fm6giXQ8P4Fayw3dsN+M7Wjy23mTRtB0= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= -k8s.io/metrics v0.18.2/go.mod h1:qga8E7QfYNR9Q89cSCAjinC9pTZ7yv1XSVGUB0vJypg= +k8s.io/metrics v0.18.4/go.mod h1:luze4fyI9JG4eLDZy0kFdYEebqNfi0QrG4xNEbPkHOs= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= @@ -766,4 +951,5 @@ sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/pkg/chartutil/jsonschema_test.go b/pkg/chartutil/jsonschema_test.go index 33f009259..a0acd5a7f 100644 --- a/pkg/chartutil/jsonschema_test.go +++ b/pkg/chartutil/jsonschema_test.go @@ -56,7 +56,7 @@ func TestValidateAgainstSingleSchemaNegative(t *testing.T) { } expectedErrString := `- (root): employmentInfo is required -- age: Must be greater than or equal to 0/1 +- age: Must be greater than or equal to 0 ` if errString != expectedErrString { t.Errorf("Error string :\n`%s`\ndoes not match expected\n`%s`", errString, expectedErrString) From 4f136861d397ec37b18c92ceee8027333ba1bc24 Mon Sep 17 00:00:00 2001 From: ShenXinkang <610716076@qq.com> Date: Tue, 9 Jun 2020 13:57:43 +0800 Subject: [PATCH 086/159] fix template command use --show-only flags error in windows environment Signed-off-by: ShenXinkang <610716076@qq.com> --- cmd/helm/template.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd/helm/template.go b/cmd/helm/template.go index 83ad61f22..9ea61b17a 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -102,6 +102,8 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { var manifestsToRender []string for _, f := range showFiles { missing := true + // Use linux-style filepath separators to unify user's input path + f = filepath.ToSlash(f) for _, manifestKey := range manifestsKeys { manifest := splitManifests[manifestKey] submatch := manifestNameRegex.FindStringSubmatch(manifest) @@ -112,7 +114,9 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { // manifest.Name is rendered using linux-style filepath separators on Windows as // well as macOS/linux. manifestPathSplit := strings.Split(manifestName, "/") - manifestPath := filepath.Join(manifestPathSplit...) + // manifest.Path is connected using linux-style filepath separators on Windows as + // well as macOS/linux + manifestPath := strings.Join(manifestPathSplit, "/") // if the filepath provided matches a manifest path in the // chart, render that manifest From 05beedd671027b227b44968e6a961be5b200a465 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Sun, 28 Jun 2020 19:53:29 -0400 Subject: [PATCH 087/159] feat(comp): Complete revision for rollback command Signed-off-by: Marc Khouzam --- cmd/helm/get_all.go | 2 +- cmd/helm/get_hooks.go | 2 +- cmd/helm/get_manifest.go | 2 +- cmd/helm/get_notes.go | 2 +- cmd/helm/get_values.go | 2 +- cmd/helm/history.go | 10 ++++-- cmd/helm/rollback.go | 11 ++++-- cmd/helm/rollback_test.go | 36 +++++++++++++++++++ cmd/helm/status.go | 2 +- cmd/helm/testdata/output/revision-comp.txt | 4 +-- cmd/helm/testdata/output/rollback-comp.txt | 4 +++ .../output/rollback-wrong-args-comp.txt | 2 ++ 12 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 cmd/helm/testdata/output/rollback-comp.txt create mode 100644 cmd/helm/testdata/output/rollback-wrong-args-comp.txt diff --git a/cmd/helm/get_all.go b/cmd/helm/get_all.go index 1ebc7e387..a5037e4df 100644 --- a/cmd/helm/get_all.go +++ b/cmd/helm/get_all.go @@ -67,7 +67,7 @@ func newGetAllCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.IntVar(&client.Version, "revision", 0, "get the named release with revision") err := cmd.RegisterFlagCompletionFunc("revision", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 1 { - return compListRevisions(cfg, args[0]) + return compListRevisions(toComplete, cfg, args[0]) } return nil, cobra.ShellCompDirectiveNoFileComp }) diff --git a/cmd/helm/get_hooks.go b/cmd/helm/get_hooks.go index 6453c30eb..8b78653b5 100644 --- a/cmd/helm/get_hooks.go +++ b/cmd/helm/get_hooks.go @@ -62,7 +62,7 @@ func newGetHooksCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { cmd.Flags().IntVar(&client.Version, "revision", 0, "get the named release with revision") err := cmd.RegisterFlagCompletionFunc("revision", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 1 { - return compListRevisions(cfg, args[0]) + return compListRevisions(toComplete, cfg, args[0]) } return nil, cobra.ShellCompDirectiveNoFileComp }) diff --git a/cmd/helm/get_manifest.go b/cmd/helm/get_manifest.go index 048bf36b0..8ffeb3676 100644 --- a/cmd/helm/get_manifest.go +++ b/cmd/helm/get_manifest.go @@ -62,7 +62,7 @@ func newGetManifestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command cmd.Flags().IntVar(&client.Version, "revision", 0, "get the named release with revision") err := cmd.RegisterFlagCompletionFunc("revision", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 1 { - return compListRevisions(cfg, args[0]) + return compListRevisions(toComplete, cfg, args[0]) } return nil, cobra.ShellCompDirectiveNoFileComp }) diff --git a/cmd/helm/get_notes.go b/cmd/helm/get_notes.go index 88d494fc4..a9d29ce49 100644 --- a/cmd/helm/get_notes.go +++ b/cmd/helm/get_notes.go @@ -61,7 +61,7 @@ func newGetNotesCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.IntVar(&client.Version, "revision", 0, "get the named release with revision") err := cmd.RegisterFlagCompletionFunc("revision", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 1 { - return compListRevisions(cfg, args[0]) + return compListRevisions(toComplete, cfg, args[0]) } return nil, cobra.ShellCompDirectiveNoFileComp }) diff --git a/cmd/helm/get_values.go b/cmd/helm/get_values.go index fa7b10fed..c8c87c033 100644 --- a/cmd/helm/get_values.go +++ b/cmd/helm/get_values.go @@ -65,7 +65,7 @@ func newGetValuesCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.IntVar(&client.Version, "revision", 0, "get the named release with revision") err := cmd.RegisterFlagCompletionFunc("revision", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 1 { - return compListRevisions(cfg, args[0]) + return compListRevisions(toComplete, cfg, args[0]) } return nil, cobra.ShellCompDirectiveNoFileComp }) diff --git a/cmd/helm/history.go b/cmd/helm/history.go index b49c52990..f55eea9fd 100644 --- a/cmd/helm/history.go +++ b/cmd/helm/history.go @@ -20,6 +20,7 @@ import ( "fmt" "io" "strconv" + "strings" "time" "github.com/gosuri/uitable" @@ -184,15 +185,18 @@ func min(x, y int) int { return y } -func compListRevisions(cfg *action.Configuration, releaseName string) ([]string, cobra.ShellCompDirective) { +func compListRevisions(toComplete string, cfg *action.Configuration, releaseName string) ([]string, cobra.ShellCompDirective) { client := action.NewHistory(cfg) var revisions []string if hist, err := client.Run(releaseName); err == nil { for _, release := range hist { - revisions = append(revisions, strconv.Itoa(release.Version)) + version := strconv.Itoa(release.Version) + if strings.HasPrefix(version, toComplete) { + revisions = append(revisions, version) + } } - return revisions, cobra.ShellCompDirectiveDefault + return revisions, cobra.ShellCompDirectiveNoFileComp } return nil, cobra.ShellCompDirectiveError } diff --git a/cmd/helm/rollback.go b/cmd/helm/rollback.go index 3b336d0ff..4849913a1 100644 --- a/cmd/helm/rollback.go +++ b/cmd/helm/rollback.go @@ -47,10 +47,15 @@ func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Long: rollbackDesc, Args: require.MinimumNArgs(1), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp + if len(args) == 0 { + return compListReleases(toComplete, cfg) } - return compListReleases(toComplete, cfg) + + if len(args) == 1 { + return compListRevisions(toComplete, cfg, args[0]) + } + + return nil, cobra.ShellCompDirectiveNoFileComp }, RunE: func(cmd *cobra.Command, args []string) error { if len(args) > 1 { diff --git a/cmd/helm/rollback_test.go b/cmd/helm/rollback_test.go index fdc627b5f..c11a7fca6 100644 --- a/cmd/helm/rollback_test.go +++ b/cmd/helm/rollback_test.go @@ -68,3 +68,39 @@ func TestRollbackCmd(t *testing.T) { }} runTestCmd(t, tests) } + +func TestRollbackRevisionCompletion(t *testing.T) { + mk := func(name string, vers int, status release.Status) *release.Release { + return release.Mock(&release.MockReleaseOptions{ + Name: name, + Version: vers, + Status: status, + }) + } + + releases := []*release.Release{ + mk("musketeers", 11, release.StatusDeployed), + mk("musketeers", 10, release.StatusSuperseded), + mk("musketeers", 9, release.StatusSuperseded), + mk("musketeers", 8, release.StatusSuperseded), + mk("carabins", 1, release.StatusSuperseded), + } + + tests := []cmdTestCase{{ + name: "completion for release parameter", + cmd: "__complete rollback ''", + rels: releases, + golden: "output/rollback-comp.txt", + }, { + name: "completion for revision parameter", + cmd: "__complete rollback musketeers ''", + rels: releases, + golden: "output/revision-comp.txt", + }, { + name: "completion for with too many args", + cmd: "__complete rollback musketeers 11 ''", + rels: releases, + golden: "output/rollback-wrong-args-comp.txt", + }} + runTestCmd(t, tests) +} diff --git a/cmd/helm/status.go b/cmd/helm/status.go index 5913d08df..abd32a9c2 100644 --- a/cmd/helm/status.go +++ b/cmd/helm/status.go @@ -78,7 +78,7 @@ func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { err := cmd.RegisterFlagCompletionFunc("revision", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) == 1 { - return compListRevisions(cfg, args[0]) + return compListRevisions(toComplete, cfg, args[0]) } return nil, cobra.ShellCompDirectiveNoFileComp }) diff --git a/cmd/helm/testdata/output/revision-comp.txt b/cmd/helm/testdata/output/revision-comp.txt index d06947d9d..50f7a9092 100644 --- a/cmd/helm/testdata/output/revision-comp.txt +++ b/cmd/helm/testdata/output/revision-comp.txt @@ -2,5 +2,5 @@ 9 10 11 -:0 -Completion ended with directive: ShellCompDirectiveDefault +:4 +Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/cmd/helm/testdata/output/rollback-comp.txt b/cmd/helm/testdata/output/rollback-comp.txt new file mode 100644 index 000000000..f7741af12 --- /dev/null +++ b/cmd/helm/testdata/output/rollback-comp.txt @@ -0,0 +1,4 @@ +carabins +musketeers +:4 +Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/cmd/helm/testdata/output/rollback-wrong-args-comp.txt b/cmd/helm/testdata/output/rollback-wrong-args-comp.txt new file mode 100644 index 000000000..8d9fad576 --- /dev/null +++ b/cmd/helm/testdata/output/rollback-wrong-args-comp.txt @@ -0,0 +1,2 @@ +:4 +Completion ended with directive: ShellCompDirectiveNoFileComp From 7ec501155d082d2e2cc314d7fd03729b5873f21c Mon Sep 17 00:00:00 2001 From: Guangwen Feng Date: Mon, 29 Jun 2020 15:20:23 +0800 Subject: [PATCH 088/159] Fix golint issue Signed-off-by: Guangwen Feng --- internal/experimental/registry/client_opts.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/experimental/registry/client_opts.go b/internal/experimental/registry/client_opts.go index 76b527492..e2f742aec 100644 --- a/internal/experimental/registry/client_opts.go +++ b/internal/experimental/registry/client_opts.go @@ -61,7 +61,7 @@ func ClientOptCache(cache *Cache) ClientOption { } } -// ClientOptCache returns a function that sets the cache setting on a client options set +// ClientOptCredentialsFile returns a function that sets the cache setting on a client options set func ClientOptCredentialsFile(credentialsFile string) ClientOption { return func(client *Client) { client.credentialsFile = credentialsFile From c6a00e63ef638c14be5560534c339484e35eb7ba Mon Sep 17 00:00:00 2001 From: zouyu Date: Mon, 29 Jun 2020 16:36:27 +0800 Subject: [PATCH 089/159] Fix some go-lint warnings Signed-off-by: zouyu --- pkg/postrender/postrender.go | 2 +- pkg/storage/storage.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/postrender/postrender.go b/pkg/postrender/postrender.go index 76f0f5a74..3af384290 100644 --- a/pkg/postrender/postrender.go +++ b/pkg/postrender/postrender.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -// package postrender contains an interface that can be implemented for custom +// Package postrender contains an interface that can be implemented for custom // post-renderers and an exec implementation that can be used for arbitrary // binaries and scripts package postrender diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index c195120cd..2dfa3f615 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -27,7 +27,7 @@ import ( "helm.sh/helm/v3/pkg/storage/driver" ) -// The type field of the Kubernetes storage object which stores the Helm release +// HelmStorageType is the type field of the Kubernetes storage object which stores the Helm release // version. It is modified slightly replacing the '/': sh.helm/release.v1 // Note: The version 'v1' is incremented if the release object metadata is // modified between major releases. From 7e9a83184c32864d3d296f3439bb8ffbc1c0d3a3 Mon Sep 17 00:00:00 2001 From: Peter Engelbert <36644727+pmengelbert@users.noreply.github.com> Date: Mon, 29 Jun 2020 16:55:01 -0500 Subject: [PATCH 090/159] Determine chart digest by manifest (#8249) Currently, whenever the chart is printed, the digest of the .tar.gz content layer is printed as the digest. The manifest digest is important for OCI purposes, particularly in pushing to a registry. Resolves #8248. Signed-off-by: Peter Engelbert --- internal/experimental/registry/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/experimental/registry/client.go b/internal/experimental/registry/client.go index 540eddfa3..5756030c0 100644 --- a/internal/experimental/registry/client.go +++ b/internal/experimental/registry/client.go @@ -240,7 +240,7 @@ func (c *Client) PrintChartTable() error { // printCacheRefSummary prints out chart ref summary func (c *Client) printCacheRefSummary(r *CacheRefSummary) { fmt.Fprintf(c.out, "ref: %s\n", r.Name) - fmt.Fprintf(c.out, "digest: %s\n", r.Digest.Hex()) + fmt.Fprintf(c.out, "digest: %s\n", r.Manifest.Digest.Hex()) fmt.Fprintf(c.out, "size: %s\n", byteCountBinary(r.Size)) fmt.Fprintf(c.out, "name: %s\n", r.Chart.Metadata.Name) fmt.Fprintf(c.out, "version: %s\n", r.Chart.Metadata.Version) @@ -257,7 +257,7 @@ func (c *Client) getChartTableRows() ([][]interface{}, error) { refsMap[r.Name] = map[string]string{ "name": r.Chart.Metadata.Name, "version": r.Chart.Metadata.Version, - "digest": shortDigest(r.Digest.Hex()), + "digest": shortDigest(r.Manifest.Digest.Hex()), "size": byteCountBinary(r.Size), "created": timeAgo(r.CreatedAt), } From 863588ca69209153863f72327fe8c818c963904a Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 9 Jun 2020 11:44:04 -0700 Subject: [PATCH 091/159] fix(cmd): display warnings on stderr The warnings introduced when a chart has been deprecated is displayed on standard out. This is a regression for users piping the output of `helm template` from a deprecated chart to `kubectl`. This changes the error message to display on standard error instead. Signed-off-by: Matthew Fisher --- cmd/helm/helm.go | 5 +++++ cmd/helm/install.go | 3 +-- cmd/helm/testdata/output/deprecated-chart.txt | 1 - cmd/helm/upgrade.go | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index fcc7315f5..d4e82bb01 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -56,6 +56,11 @@ func debug(format string, v ...interface{}) { } } +func warning(format string, v ...interface{}) { + format = fmt.Sprintf("WARNING: %s\n", format) + fmt.Fprintf(os.Stderr, format, v...) +} + func initKubeLogs() { pflag.CommandLine.SetNormalizeFunc(wordSepNormalizeFunc) gofs := flag.NewFlagSet("klog", flag.ExitOnError) diff --git a/cmd/helm/install.go b/cmd/helm/install.go index 9024add2f..cdb38a10a 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -17,7 +17,6 @@ limitations under the License. package main import ( - "fmt" "io" "log" "time" @@ -207,7 +206,7 @@ func runInstall(args []string, client *action.Install, valueOpts *values.Options } if chartRequested.Metadata.Deprecated { - fmt.Fprintln(out, "WARNING: This chart is deprecated") + warning("This chart is deprecated") } if req := chartRequested.Metadata.Dependencies; req != nil { diff --git a/cmd/helm/testdata/output/deprecated-chart.txt b/cmd/helm/testdata/output/deprecated-chart.txt index e5be2c3f1..039d6aef6 100644 --- a/cmd/helm/testdata/output/deprecated-chart.txt +++ b/cmd/helm/testdata/output/deprecated-chart.txt @@ -1,4 +1,3 @@ -WARNING: This chart is deprecated NAME: aeneas LAST DEPLOYED: Fri Sep 2 22:04:05 1977 NAMESPACE: default diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index dc3bc9a58..c992e2f6b 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -148,7 +148,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } if ch.Metadata.Deprecated { - fmt.Fprintln(out, "WARNING: This chart is deprecated") + warning("This chart is deprecated") } rel, err := client.Run(args[0], ch, vals) From 5396df2e282c61ffb1fc8fa65240c36a0216055f Mon Sep 17 00:00:00 2001 From: zwwhdls Date: Sun, 8 Dec 2019 00:30:16 +0800 Subject: [PATCH 092/159] fix #6116 Signed-off-by: zwwhdls --- pkg/strvals/parser.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go index c735412e9..3c585cbea 100644 --- a/pkg/strvals/parser.go +++ b/pkg/strvals/parser.go @@ -305,8 +305,15 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) { if err != nil { return list, errors.Wrap(err, "error parsing index") } + var crtList []interface{} + if len(list) > i { + // If nested list already exists, take the value of list to next cycle. + crtList = list[i].([]interface{}) + } else { + crtList = list + } // Now we need to get the value after the ]. - list2, err := t.listItem(list, i) + list2, err := t.listItem(crtList, i) if err != nil { return list, err } From c41c72cee980b8763a3701450b4b5da8ebf343a2 Mon Sep 17 00:00:00 2001 From: zwwhdls Date: Sun, 8 Dec 2019 00:41:35 +0800 Subject: [PATCH 093/159] add test case Signed-off-by: zwwhdls --- pkg/strvals/parser_test.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go index 742256153..7c6e6f73b 100644 --- a/pkg/strvals/parser_test.go +++ b/pkg/strvals/parser_test.go @@ -427,7 +427,7 @@ func TestParseInto(t *testing.T) { "inner2": "value2", }, } - input := "outer.inner1=value1,outer.inner3=value3,outer.inner4=4" + input := "outer.inner1=value1,outer.inner3=value3,outer.inner4=4,listOuter[0][0].type=listValue" expect := map[string]interface{}{ "outer": map[string]interface{}{ "inner1": "value1", @@ -435,12 +435,22 @@ func TestParseInto(t *testing.T) { "inner3": "value3", "inner4": 4, }, + "listOuter": [][]interface{}{{map[string]string{ + "type": "listValue", + "status": "alive", + }}, + }, } if err := ParseInto(input, got); err != nil { t.Fatal(err) } + input2 := "listOuter[0][0].status=alive" + if err := ParseInto(input2, got); err != nil { + t.Fatal(err) + } + y1, err := yaml.Marshal(expect) if err != nil { t.Fatal(err) From 4532485fd03a8cb56186c93ffeba285431073429 Mon Sep 17 00:00:00 2001 From: zwwhdls Date: Sun, 8 Dec 2019 10:37:46 +0800 Subject: [PATCH 094/159] fix another extreme case Signed-off-by: zwwhdls --- pkg/strvals/parser.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go index 3c585cbea..cc5c509da 100644 --- a/pkg/strvals/parser.go +++ b/pkg/strvals/parser.go @@ -301,7 +301,7 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) { } case last == '[': // now we have a nested list. Read the index and handle. - i, err := t.keyIndex() + nextI, err := t.keyIndex() if err != nil { return list, errors.Wrap(err, "error parsing index") } @@ -309,15 +309,18 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) { if len(list) > i { // If nested list already exists, take the value of list to next cycle. crtList = list[i].([]interface{}) - } else { - crtList = list } // Now we need to get the value after the ]. +<<<<<<< HEAD list2, err := t.listItem(crtList, i) if err != nil { return list, err } return setIndex(list, i, list2) +======= + list2, err := t.listItem(crtList, nextI) + return setIndex(list, i, list2), err +>>>>>>> fix another extreme case case last == '.': // We have a nested object. Send to t.key inner := map[string]interface{}{} From 1b39857ac32165db1ad64f66a03d74f1fa09a3f7 Mon Sep 17 00:00:00 2001 From: zwwhdls Date: Sun, 8 Dec 2019 11:30:11 +0800 Subject: [PATCH 095/159] add test case Signed-off-by: zwwhdls --- pkg/strvals/parser.go | 5 +- pkg/strvals/parser_test.go | 137 ++++++++++++++++++++++++++++--------- 2 files changed, 107 insertions(+), 35 deletions(-) diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go index cc5c509da..45aa65eac 100644 --- a/pkg/strvals/parser.go +++ b/pkg/strvals/parser.go @@ -308,7 +308,10 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) { var crtList []interface{} if len(list) > i { // If nested list already exists, take the value of list to next cycle. - crtList = list[i].([]interface{}) + existed := list[i] + if existed != nil { + crtList = list[i].([]interface{}) + } } // Now we need to get the value after the ]. <<<<<<< HEAD diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go index 7c6e6f73b..cef98ba0a 100644 --- a/pkg/strvals/parser_test.go +++ b/pkg/strvals/parser_test.go @@ -421,49 +421,118 @@ func TestParseSet(t *testing.T) { } func TestParseInto(t *testing.T) { - got := map[string]interface{}{ - "outer": map[string]interface{}{ - "inner1": "overwrite", - "inner2": "value2", + tests := []struct { + input string + input2 string + got map[string]interface{} + expect map[string]interface{} + err bool + }{ + { + input: "outer.inner1=value1,outer.inner3=value3,outer.inner4=4", + got: map[string]interface{}{ + "outer": map[string]interface{}{ + "inner1": "overwrite", + "inner2": "value2", + }, + }, + expect: map[string]interface{}{ + "outer": map[string]interface{}{ + "inner1": "value1", + "inner2": "value2", + "inner3": "value3", + "inner4": 4, + }}, + err: false, }, - } - input := "outer.inner1=value1,outer.inner3=value3,outer.inner4=4,listOuter[0][0].type=listValue" - expect := map[string]interface{}{ - "outer": map[string]interface{}{ - "inner1": "value1", - "inner2": "value2", - "inner3": "value3", - "inner4": 4, + { + input: "listOuter[0][0].type=listValue", + input2: "listOuter[0][0].status=alive", + got: map[string]interface{}{}, + expect: map[string]interface{}{ + "listOuter": [][]interface{}{{map[string]string{ + "type": "listValue", + "status": "alive", + }}}, + }, + err: false, }, - "listOuter": [][]interface{}{{map[string]string{ - "type": "listValue", - "status": "alive", - }}, + { + input: "listOuter[0][0].type=listValue", + input2: "listOuter[1][0].status=alive", + got: map[string]interface{}{}, + expect: map[string]interface{}{ + "listOuter": [][]interface{}{ + { + map[string]string{"type": "listValue"}, + }, + { + map[string]string{"status": "alive"}, + }, + }, + }, + err: false, + }, + { + input: "listOuter[0][1][0].type=listValue", + input2: "listOuter[0][0][1].status=alive", + got: map[string]interface{}{ + "listOuter": []interface{}{ + []interface{}{ + []interface{}{ + map[string]string{"exited": "old"}, + }, + }, + }, + }, + expect: map[string]interface{}{ + "listOuter": [][][]interface{}{ + { + { + map[string]string{"exited": "old"}, + map[string]string{"status": "alive"}, + }, + { + map[string]string{"type": "listValue"}, + }, + }, + }, + }, + err: false, }, } + for _, tt := range tests { + if err := ParseInto(tt.input, tt.got); err != nil { + t.Fatal(err) + } + if tt.err { + t.Errorf("%s: Expected error. Got nil", tt.input) + } - if err := ParseInto(input, got); err != nil { - t.Fatal(err) - } - - input2 := "listOuter[0][0].status=alive" - if err := ParseInto(input2, got); err != nil { - t.Fatal(err) - } + if tt.input2 != "" { + if err := ParseInto(tt.input2, tt.got); err != nil { + t.Fatal(err) + } + if tt.err { + t.Errorf("%s: Expected error. Got nil", tt.input2) + } + } - y1, err := yaml.Marshal(expect) - if err != nil { - t.Fatal(err) - } - y2, err := yaml.Marshal(got) - if err != nil { - t.Fatalf("Error serializing parsed value: %s", err) - } + y1, err := yaml.Marshal(tt.expect) + if err != nil { + t.Fatal(err) + } + y2, err := yaml.Marshal(tt.got) + if err != nil { + t.Fatalf("Error serializing parsed value: %s", err) + } - if string(y1) != string(y2) { - t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2) + if string(y1) != string(y2) { + t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.input, y1, y2) + } } } + func TestParseIntoString(t *testing.T) { got := map[string]interface{}{ "outer": map[string]interface{}{ From d58a984878ea290e04a135ef037b75e13b7b8df5 Mon Sep 17 00:00:00 2001 From: zwwhdls Date: Wed, 1 Jul 2020 21:29:20 +0800 Subject: [PATCH 096/159] fix conflict Signed-off-by: zwwhdls --- pkg/strvals/parser.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go index 45aa65eac..457b99f94 100644 --- a/pkg/strvals/parser.go +++ b/pkg/strvals/parser.go @@ -314,16 +314,11 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) { } } // Now we need to get the value after the ]. -<<<<<<< HEAD - list2, err := t.listItem(crtList, i) + list2, err := t.listItem(crtList, nextI) if err != nil { return list, err } return setIndex(list, i, list2) -======= - list2, err := t.listItem(crtList, nextI) - return setIndex(list, i, list2), err ->>>>>>> fix another extreme case case last == '.': // We have a nested object. Send to t.key inner := map[string]interface{}{} From 4ad76e1be278bdf8b842c3775f34301cbed08b72 Mon Sep 17 00:00:00 2001 From: Bridget Kromhout Date: Mon, 6 Jul 2020 14:57:41 -0500 Subject: [PATCH 097/159] Updating for today's actual milestone practices Signed-off-by: Bridget Kromhout --- CONTRIBUTING.md | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e27fa7d19..e4493d24c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,22 +96,16 @@ that we're already aware of. It is also worth asking on the Slack channels. ## Milestones -We use milestones to track progress of releases. There are also 2 special milestones used for -helping us keep work organized: `Upcoming - Minor` and `Upcoming - Major` - -`Upcoming - Minor` is used for keeping track of issues that aren't assigned to a specific release -but could easily be addressed in a minor release. `Upcoming - Major` keeps track of issues that will -need to be addressed in a major release. For example, if the current version is `3.2.0` an issue/PR -could fall in to one of 4 different active milestones: `3.2.1`, `3.3.0`, `Upcoming - Minor`, or -`Upcoming - Major`. If an issue pertains to a specific upcoming bug or minor release, it would go -into `3.2.1` or `3.3.0`. If the issue/PR does not have a specific milestone yet, but it is likely -that it will land in a `3.X` release, it should go into `Upcoming - Minor`. If the issue/PR is a -large functionality add or change and/or it breaks compatibility, then it should be added to the -`Upcoming - Major` milestone. An issue that we are not sure we will be doing will not be added to -any milestone. - -A milestone (and hence release) is considered done when all outstanding issues/PRs have been closed -or moved to another milestone. +We use milestones to track progress of specific planned releases. + +For example, if the latest currently-released version is `3.2.1`, an issue/PR which pertains to a +specific upcoming bugfix or feature release could fall into one of two different active milestones: +`3.2.2` or `3.3.0`. + +An issue that we are not sure we will be addressing will not be added to any milestone. + +A milestone (and hence release) can be closed when all outstanding issues/PRs have been closed +or moved to another milestone and the associated release has been published. ## Semantic Versioning From 3d05f96b7e505e1f36c3f0f2842d021d879f3231 Mon Sep 17 00:00:00 2001 From: Bridget Kromhout Date: Mon, 6 Jul 2020 19:43:01 -0500 Subject: [PATCH 098/159] Adding v4 link Signed-off-by: Bridget Kromhout --- CONTRIBUTING.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e4493d24c..a8028dd01 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -102,7 +102,9 @@ For example, if the latest currently-released version is `3.2.1`, an issue/PR wh specific upcoming bugfix or feature release could fall into one of two different active milestones: `3.2.2` or `3.3.0`. -An issue that we are not sure we will be addressing will not be added to any milestone. +Issues and PRs which are deemed backwards-incompatible may be added to the discussion items for +Helm 4 with [label:v4.x](https://github.com/helm/helm/labels/v4.x). An issue or PR that we are not +sure we will be addressing will not be added to any milestone. A milestone (and hence release) can be closed when all outstanding issues/PRs have been closed or moved to another milestone and the associated release has been published. From ceff32d5f8aa173549426625b608137a47981447 Mon Sep 17 00:00:00 2001 From: DongGang Date: Tue, 7 Jul 2020 23:44:22 +0800 Subject: [PATCH 099/159] fix(template):Issue:helm template with --output-dir (#8156) * fix(template):Issue:helm template with --output-dir doesn't write template with a hook to file Close #7836 Signed-off-by: Dong Gang * fix go file style Signed-off-by: Dong Gang * fix go file style Signed-off-by: Dong Gang --- cmd/helm/template.go | 6 ------ pkg/action/action.go | 20 +++++++++++++++++++- pkg/action/install.go | 2 +- pkg/action/install_test.go | 6 ++++++ pkg/action/upgrade.go | 2 +- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/cmd/helm/template.go b/cmd/helm/template.go index 9ea61b17a..5a8a25102 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -80,12 +80,6 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { var manifests bytes.Buffer fmt.Fprintln(&manifests, strings.TrimSpace(rel.Manifest)) - if !client.DisableHooks { - for _, m := range rel.Hooks { - fmt.Fprintf(&manifests, "---\n# Source: %s\n%s\n", m.Path, m.Manifest) - } - } - // if we have a list of files to render, then check that each of the // provided files exists in the chart. if len(showFiles) > 0 { diff --git a/pkg/action/action.go b/pkg/action/action.go index bb9ef5f71..698ebd23f 100644 --- a/pkg/action/action.go +++ b/pkg/action/action.go @@ -97,7 +97,7 @@ type Configuration struct { // renderResources renders the templates in a chart // // TODO: This function is badly in need of a refactor. -func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values, releaseName, outputDir string, subNotes, useReleaseName, includeCrds bool, pr postrender.PostRenderer, dryRun bool) ([]*release.Hook, *bytes.Buffer, string, error) { +func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values, releaseName, outputDir string, subNotes, useReleaseName, includeCrds bool, disableHooks bool, pr postrender.PostRenderer, dryRun bool) ([]*release.Hook, *bytes.Buffer, string, error) { hs := []*release.Hook{} b := bytes.NewBuffer(nil) @@ -210,6 +210,24 @@ func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values } } + if !disableHooks && len(hs) > 0 { + for _, h := range hs { + if outputDir == "" { + fmt.Fprintf(b, "---\n# Source: %s\n%s\n", h.Path, h.Manifest) + } else { + newDir := outputDir + if useReleaseName { + newDir = filepath.Join(outputDir, releaseName) + } + err = writeToFile(newDir, h.Path, h.Manifest, fileWritten[h.Path]) + if err != nil { + return hs, b, "", err + } + fileWritten[h.Path] = true + } + } + } + if pr != nil { b, err = pr.Run(b) if err != nil { diff --git a/pkg/action/install.go b/pkg/action/install.go index 00fb208b0..48a3aeeca 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -236,7 +236,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. rel := i.createRelease(chrt, vals) var manifestDoc *bytes.Buffer - rel.Hooks, manifestDoc, rel.Info.Notes, err = i.cfg.renderResources(chrt, valuesToRender, i.ReleaseName, i.OutputDir, i.SubNotes, i.UseReleaseName, i.IncludeCRDs, i.PostRenderer, i.DryRun) + rel.Hooks, manifestDoc, rel.Info.Notes, err = i.cfg.renderResources(chrt, valuesToRender, i.ReleaseName, i.OutputDir, i.SubNotes, i.UseReleaseName, i.IncludeCRDs, i.DisableHooks, i.PostRenderer, i.DryRun) // Even for errors, attach this if available if manifestDoc != nil { rel.Manifest = manifestDoc.String() diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 6c4012cfd..4366889ce 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -499,6 +499,9 @@ func TestInstallReleaseOutputDir(t *testing.T) { _, err = os.Stat(filepath.Join(dir, "hello/templates/with-partials")) is.NoError(err) + _, err = os.Stat(filepath.Join(dir, "hello/templates/hooks")) + is.NoError(err) + _, err = os.Stat(filepath.Join(dir, "hello/templates/rbac")) is.NoError(err) @@ -539,6 +542,9 @@ func TestInstallOutputDirWithReleaseName(t *testing.T) { _, err = os.Stat(filepath.Join(newDir, "hello/templates/with-partials")) is.NoError(err) + _, err = os.Stat(filepath.Join(newDir, "hello/templates/hooks")) + is.NoError(err) + _, err = os.Stat(filepath.Join(newDir, "hello/templates/rbac")) is.NoError(err) diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index fc289dbab..921a0eba5 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -217,7 +217,7 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chart.Chart, vals map[strin return nil, nil, err } - hooks, manifestDoc, notesTxt, err := u.cfg.renderResources(chart, valuesToRender, "", "", u.SubNotes, false, false, u.PostRenderer, u.DryRun) + hooks, manifestDoc, notesTxt, err := u.cfg.renderResources(chart, valuesToRender, "", "", u.SubNotes, false, false, false, u.PostRenderer, u.DryRun) if err != nil { return nil, nil, err } From fc4a11c131822df4dcb4c8a1e5a1448cc109c39d Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Tue, 7 Jul 2020 10:39:45 -0700 Subject: [PATCH 100/159] bump version to v3.3 Signed-off-by: Matthew Fisher (cherry picked from commit 5c2dfaad847df2ac8f289d278186d048f446c70c) --- cmd/helm/testdata/output/version-client-shorthand.txt | 2 +- cmd/helm/testdata/output/version-client.txt | 2 +- cmd/helm/testdata/output/version-short.txt | 2 +- cmd/helm/testdata/output/version-template.txt | 2 +- cmd/helm/testdata/output/version.txt | 2 +- internal/version/version.go | 2 +- pkg/chartutil/capabilities_test.go | 4 ++-- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmd/helm/testdata/output/version-client-shorthand.txt b/cmd/helm/testdata/output/version-client-shorthand.txt index d613309fe..910493bc4 100644 --- a/cmd/helm/testdata/output/version-client-shorthand.txt +++ b/cmd/helm/testdata/output/version-client-shorthand.txt @@ -1 +1 @@ -version.BuildInfo{Version:"v3.2", GitCommit:"", GitTreeState:"", GoVersion:""} +version.BuildInfo{Version:"v3.3", GitCommit:"", GitTreeState:"", GoVersion:""} diff --git a/cmd/helm/testdata/output/version-client.txt b/cmd/helm/testdata/output/version-client.txt index d613309fe..910493bc4 100644 --- a/cmd/helm/testdata/output/version-client.txt +++ b/cmd/helm/testdata/output/version-client.txt @@ -1 +1 @@ -version.BuildInfo{Version:"v3.2", GitCommit:"", GitTreeState:"", GoVersion:""} +version.BuildInfo{Version:"v3.3", GitCommit:"", GitTreeState:"", GoVersion:""} diff --git a/cmd/helm/testdata/output/version-short.txt b/cmd/helm/testdata/output/version-short.txt index 4d5034cea..a6c626024 100644 --- a/cmd/helm/testdata/output/version-short.txt +++ b/cmd/helm/testdata/output/version-short.txt @@ -1 +1 @@ -v3.2 +v3.3 diff --git a/cmd/helm/testdata/output/version-template.txt b/cmd/helm/testdata/output/version-template.txt index 7c09e8d57..48c6d2b04 100644 --- a/cmd/helm/testdata/output/version-template.txt +++ b/cmd/helm/testdata/output/version-template.txt @@ -1 +1 @@ -Version: v3.2 \ No newline at end of file +Version: v3.3 \ No newline at end of file diff --git a/cmd/helm/testdata/output/version.txt b/cmd/helm/testdata/output/version.txt index d613309fe..910493bc4 100644 --- a/cmd/helm/testdata/output/version.txt +++ b/cmd/helm/testdata/output/version.txt @@ -1 +1 @@ -version.BuildInfo{Version:"v3.2", GitCommit:"", GitTreeState:"", GoVersion:""} +version.BuildInfo{Version:"v3.3", GitCommit:"", GitTreeState:"", GoVersion:""} diff --git a/internal/version/version.go b/internal/version/version.go index baa65a028..712aae640 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -30,7 +30,7 @@ var ( // Increment major number for new feature additions and behavioral changes. // Increment minor number for bug fixes and performance enhancements. // Increment patch number for critical fixes to existing releases. - version = "v3.2" + version = "v3.3" // metadata is extra build time data metadata = "" diff --git a/pkg/chartutil/capabilities_test.go b/pkg/chartutil/capabilities_test.go index 489a472be..ae9624bca 100644 --- a/pkg/chartutil/capabilities_test.go +++ b/pkg/chartutil/capabilities_test.go @@ -62,7 +62,7 @@ func TestDefaultCapabilities(t *testing.T) { func TestDefaultCapabilitiesHelmVersion(t *testing.T) { hv := DefaultCapabilities.HelmVersion - if hv.Version != "v3.2" { - t.Errorf("Expected default HelmVerison to be v3.2, got %q", hv.Version) + if hv.Version != "v3.3" { + t.Errorf("Expected default HelmVerison to be v3.3, got %q", hv.Version) } } From ebe6abd660eda59b497d683d418e658b323ca4ea Mon Sep 17 00:00:00 2001 From: Michelle Noorali Date: Tue, 7 Jul 2020 19:18:00 -0400 Subject: [PATCH 101/159] chore(OWNERS): move michelleN to emeritus Thank you. Signed-off-by: Michelle Noorali --- OWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OWNERS b/OWNERS index d7dac5514..e7c953077 100644 --- a/OWNERS +++ b/OWNERS @@ -6,7 +6,6 @@ maintainers: - jdolitsky - marckhouzam - mattfarina - - michelleN - prydonius - SlickNik - technosophos @@ -14,6 +13,7 @@ maintainers: - viglesiasce emeritus: - jascott1 + - michelleN - migmartri - nebril - seh From 637a5c649469935e9d0e69873190dc014ce4d9cf Mon Sep 17 00:00:00 2001 From: wawa0210 Date: Mon, 29 Jun 2020 23:51:57 +0800 Subject: [PATCH 102/159] Environment variable for setting the max history for an environment Signed-off-by: wawa0210 --- cmd/helm/root.go | 1 + cmd/helm/upgrade.go | 2 +- pkg/cli/environment.go | 19 +++++++++++++++++++ pkg/cli/environment_test.go | 38 ++++++++++++++++++++++--------------- 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/cmd/helm/root.go b/cmd/helm/root.go index 20dd1d93b..449009cb5 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -50,6 +50,7 @@ Environment variables: | $HELM_DATA_HOME | set an alternative location for storing Helm data. | | $HELM_DRIVER | set the backend storage driver. Values are: configmap, secret, memory, postgres | | $HELM_DRIVER_SQL_CONNECTION_STRING | set the connection string the SQL storage driver should use. | +| $HELM_MAX_HISTORY | set the maximum number of helm release history. | | $HELM_NO_PLUGINS | disable plugins. Set HELM_NO_PLUGINS=1 to disable plugins. | | $KUBECONFIG | set an alternative Kubernetes configuration file (default "~/.kube/config") | diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index c992e2f6b..dbddaa368 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -180,7 +180,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.BoolVar(&client.ReuseValues, "reuse-values", false, "when upgrading, reuse the last release's values and merge in any overrides from the command line via --set and -f. If '--reset-values' is specified, this is ignored") f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as --timeout") f.BoolVar(&client.Atomic, "atomic", false, "if set, upgrade process rolls back changes made in case of failed upgrade. The --wait flag will be set automatically if --atomic is used") - f.IntVar(&client.MaxHistory, "history-max", 10, "limit the maximum number of revisions saved per release. Use 0 for no limit") + f.IntVar(&client.MaxHistory, "history-max", settings.MaxHistory, "limit the maximum number of revisions saved per release. Use 0 for no limit") f.BoolVar(&client.CleanupOnFail, "cleanup-on-fail", false, "allow deletion of new resources created in this upgrade when upgrade fails") f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent") f.StringVar(&client.Description, "description", "", "add a custom description") diff --git a/pkg/cli/environment.go b/pkg/cli/environment.go index d62f57a55..a9994f03d 100644 --- a/pkg/cli/environment.go +++ b/pkg/cli/environment.go @@ -33,6 +33,9 @@ import ( "helm.sh/helm/v3/pkg/helmpath" ) +// defaultMaxHistory sets the maximum number of releases to 0: unlimited +const defaultMaxHistory = 10 + // EnvSettings describes all of the environment settings. type EnvSettings struct { namespace string @@ -56,11 +59,14 @@ type EnvSettings struct { RepositoryCache string // PluginsDirectory is the path to the plugins directory. PluginsDirectory string + // MaxHistory is the max release history maintained. + MaxHistory int } func New() *EnvSettings { env := &EnvSettings{ namespace: os.Getenv("HELM_NAMESPACE"), + MaxHistory: envIntOr("HELM_MAX_HISTORY", defaultMaxHistory), KubeContext: os.Getenv("HELM_KUBECONTEXT"), KubeToken: os.Getenv("HELM_KUBETOKEN"), KubeAPIServer: os.Getenv("HELM_KUBEAPISERVER"), @@ -102,6 +108,18 @@ func envOr(name, def string) string { return def } +func envIntOr(name string, def int) int { + if name == "" { + return def + } + envVal := envOr(name, strconv.Itoa(def)) + ret, err := strconv.Atoi(envVal) + if err != nil { + return def + } + return ret +} + func (s *EnvSettings) EnvVars() map[string]string { envvars := map[string]string{ "HELM_BIN": os.Args[0], @@ -114,6 +132,7 @@ func (s *EnvSettings) EnvVars() map[string]string { "HELM_REPOSITORY_CACHE": s.RepositoryCache, "HELM_REPOSITORY_CONFIG": s.RepositoryConfig, "HELM_NAMESPACE": s.Namespace(), + "HELM_MAX_HISTORY": strconv.Itoa(s.MaxHistory), // broken, these are populated from helm flags and not kubeconfig. "HELM_KUBECONTEXT": s.KubeContext, diff --git a/pkg/cli/environment_test.go b/pkg/cli/environment_test.go index fadc2981e..3234a133b 100644 --- a/pkg/cli/environment_test.go +++ b/pkg/cli/environment_test.go @@ -35,29 +35,34 @@ func TestEnvSettings(t *testing.T) { // expected values ns, kcontext string debug bool + maxhistory int }{ { - name: "defaults", - ns: "default", + name: "defaults", + ns: "default", + maxhistory: defaultMaxHistory, }, { - name: "with flags set", - args: "--debug --namespace=myns", - ns: "myns", - debug: true, + name: "with flags set", + args: "--debug --namespace=myns", + ns: "myns", + debug: true, + maxhistory: defaultMaxHistory, }, { - name: "with envvars set", - envvars: map[string]string{"HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns"}, - ns: "yourns", - debug: true, + name: "with envvars set", + envvars: map[string]string{"HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns", "HELM_MAX_HISTORY": "5"}, + ns: "yourns", + maxhistory: 5, + debug: true, }, { - name: "with flags and envvars set", - args: "--debug --namespace=myns", - envvars: map[string]string{"HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns"}, - ns: "myns", - debug: true, + name: "with flags and envvars set", + args: "--debug --namespace=myns", + envvars: map[string]string{"HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns"}, + ns: "myns", + debug: true, + maxhistory: defaultMaxHistory, }, } @@ -84,6 +89,9 @@ func TestEnvSettings(t *testing.T) { if settings.KubeContext != tt.kcontext { t.Errorf("expected kube-context %q, got %q", tt.kcontext, settings.KubeContext) } + if settings.MaxHistory != tt.maxhistory { + t.Errorf("expected maxHistory %d, got %d", tt.maxhistory, settings.MaxHistory) + } }) } } From 2750e4d78181b614776d82031f6ddfece8d020e2 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Thu, 9 Jul 2020 14:31:51 -0600 Subject: [PATCH 103/159] Lint dependencies (#7970) * feat: add dependency tests Signed-off-by: Matt Butcher * replaced on-disk fixtures with in-memory fixtures Signed-off-by: Matt Butcher --- cmd/helm/lint_test.go | 2 +- ...hart-with-bad-subcharts-with-subcharts.txt | 6 +- .../output/lint-chart-with-bad-subcharts.txt | 4 +- .../charts/bad-subchart/Chart.yaml | 2 +- pkg/chartutil/save_test.go | 6 +- pkg/lint/lint.go | 1 + pkg/lint/lint_test.go | 12 ++- pkg/lint/rules/dependencies.go | 82 +++++++++++++++ pkg/lint/rules/dependencies_test.go | 99 +++++++++++++++++++ 9 files changed, 202 insertions(+), 12 deletions(-) create mode 100644 pkg/lint/rules/dependencies.go create mode 100644 pkg/lint/rules/dependencies_test.go diff --git a/cmd/helm/lint_test.go b/cmd/helm/lint_test.go index 7638acb84..9079935d4 100644 --- a/cmd/helm/lint_test.go +++ b/cmd/helm/lint_test.go @@ -27,7 +27,7 @@ func TestLintCmdWithSubchartsFlag(t *testing.T) { name: "lint good chart with bad subcharts", cmd: fmt.Sprintf("lint %s", testChart), golden: "output/lint-chart-with-bad-subcharts.txt", - wantError: false, + wantError: true, }, { name: "lint good chart with bad subcharts using --with-subcharts flag", cmd: fmt.Sprintf("lint --with-subcharts %s", testChart), diff --git a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt index cda011b57..e77aa387f 100644 --- a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt +++ b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt @@ -1,6 +1,8 @@ ==> Linting testdata/testcharts/chart-with-bad-subcharts [INFO] Chart.yaml: icon is recommended [WARNING] templates/: directory not found +[ERROR] : unable to load chart + error unpacking bad-subchart in chart-with-bad-subcharts: validation: chart.metadata.name is required ==> Linting testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart [ERROR] Chart.yaml: name is required @@ -8,9 +10,11 @@ [ERROR] Chart.yaml: version is required [INFO] Chart.yaml: icon is recommended [WARNING] templates/: directory not found +[ERROR] : unable to load chart + validation: chart.metadata.name is required ==> Linting testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart [INFO] Chart.yaml: icon is recommended [WARNING] templates/: directory not found -Error: 3 chart(s) linted, 1 chart(s) failed +Error: 3 chart(s) linted, 2 chart(s) failed diff --git a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt index 51f3f3718..265e555f7 100644 --- a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt +++ b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt @@ -1,5 +1,7 @@ ==> Linting testdata/testcharts/chart-with-bad-subcharts [INFO] Chart.yaml: icon is recommended [WARNING] templates/: directory not found +[ERROR] : unable to load chart + error unpacking bad-subchart in chart-with-bad-subcharts: validation: chart.metadata.name is required -1 chart(s) linted, 0 chart(s) failed +Error: 1 chart(s) linted, 1 chart(s) failed diff --git a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/Chart.yaml b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/Chart.yaml index 0daa5c188..a6754b24f 100644 --- a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/Chart.yaml +++ b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/Chart.yaml @@ -1 +1 @@ -description: Bad subchart \ No newline at end of file +description: Bad subchart diff --git a/pkg/chartutil/save_test.go b/pkg/chartutil/save_test.go index 306c13cee..3a45b2992 100644 --- a/pkg/chartutil/save_test.go +++ b/pkg/chartutil/save_test.go @@ -30,15 +30,13 @@ import ( "testing" "time" + "helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" ) func TestSave(t *testing.T) { - tmp, err := ioutil.TempDir("", "helm-") - if err != nil { - t.Fatal(err) - } + tmp := ensure.TempDir(t) defer os.RemoveAll(tmp) for _, dest := range []string{tmp, path.Join(tmp, "newdir")} { diff --git a/pkg/lint/lint.go b/pkg/lint/lint.go index 223ead75a..67e76bd3d 100644 --- a/pkg/lint/lint.go +++ b/pkg/lint/lint.go @@ -32,5 +32,6 @@ func All(basedir string, values map[string]interface{}, namespace string, strict rules.Chartfile(&linter) rules.ValuesWithOverrides(&linter, values) rules.Templates(&linter, values, namespace, strict) + rules.Dependencies(&linter) return linter } diff --git a/pkg/lint/lint_test.go b/pkg/lint/lint_test.go index e7ff4cd7a..29ed67026 100644 --- a/pkg/lint/lint_test.go +++ b/pkg/lint/lint_test.go @@ -38,12 +38,12 @@ const goodChartDir = "rules/testdata/goodone" func TestBadChart(t *testing.T) { m := All(badChartDir, values, namespace, strict).Messages - if len(m) != 7 { + if len(m) != 8 { t.Errorf("Number of errors %v", len(m)) t.Errorf("All didn't fail with expected errors, got %#v", m) } - // There should be one INFO, 2 WARNINGs and one ERROR messages, check for them - var i, w, e, e2, e3, e4, e5 bool + // There should be one INFO, 2 WARNINGs and 2 ERROR messages, check for them + var i, w, e, e2, e3, e4, e5, e6 bool for _, msg := range m { if msg.Severity == support.InfoSev { if strings.Contains(msg.Err.Error(), "icon is recommended") { @@ -74,9 +74,13 @@ func TestBadChart(t *testing.T) { if strings.Contains(msg.Err.Error(), "dependencies are not valid in the Chart file with apiVersion") { e5 = true } + // This comes from the dependency check, which loads dependency info from the Chart.yaml + if strings.Contains(msg.Err.Error(), "unable to load chart") { + e6 = true + } } } - if !e || !e2 || !e3 || !e4 || !e5 || !w || !i { + if !e || !e2 || !e3 || !e4 || !e5 || !w || !i || !e6 { t.Errorf("Didn't find all the expected errors, got %#v", m) } } diff --git a/pkg/lint/rules/dependencies.go b/pkg/lint/rules/dependencies.go new file mode 100644 index 000000000..abecd1feb --- /dev/null +++ b/pkg/lint/rules/dependencies.go @@ -0,0 +1,82 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package rules // import "helm.sh/helm/v3/pkg/lint/rules" + +import ( + "fmt" + "strings" + + "github.com/pkg/errors" + + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/lint/support" +) + +// Dependencies runs lints against a chart's dependencies +// +// See https://github.com/helm/helm/issues/7910 +func Dependencies(linter *support.Linter) { + c, err := loader.LoadDir(linter.ChartDir) + if !linter.RunLinterRule(support.ErrorSev, "", validateChartFormat(err)) { + return + } + + linter.RunLinterRule(support.ErrorSev, linter.ChartDir, validateDependencyInMetadata(c)) + linter.RunLinterRule(support.WarningSev, linter.ChartDir, validateDependencyInChartsDir(c)) +} + +func validateChartFormat(chartError error) error { + if chartError != nil { + return errors.Errorf("unable to load chart\n\t%s", chartError) + } + return nil +} + +func validateDependencyInChartsDir(c *chart.Chart) (err error) { + dependencies := map[string]struct{}{} + missing := []string{} + for _, dep := range c.Dependencies() { + dependencies[dep.Metadata.Name] = struct{}{} + } + for _, dep := range c.Metadata.Dependencies { + if _, ok := dependencies[dep.Name]; !ok { + missing = append(missing, dep.Name) + } + } + if len(missing) > 0 { + err = fmt.Errorf("chart directory is missing these dependencies: %s", strings.Join(missing, ",")) + } + return err +} + +func validateDependencyInMetadata(c *chart.Chart) (err error) { + dependencies := map[string]struct{}{} + missing := []string{} + for _, dep := range c.Metadata.Dependencies { + dependencies[dep.Name] = struct{}{} + } + for _, dep := range c.Dependencies() { + if _, ok := dependencies[dep.Metadata.Name]; !ok { + missing = append(missing, dep.Metadata.Name) + } + } + if len(missing) > 0 { + err = fmt.Errorf("chart metadata is missing these dependencies: %s", strings.Join(missing, ",")) + } + return err +} diff --git a/pkg/lint/rules/dependencies_test.go b/pkg/lint/rules/dependencies_test.go new file mode 100644 index 000000000..075190eac --- /dev/null +++ b/pkg/lint/rules/dependencies_test.go @@ -0,0 +1,99 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package rules + +import ( + "os" + "path/filepath" + "testing" + + "helm.sh/helm/v3/internal/test/ensure" + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chartutil" + "helm.sh/helm/v3/pkg/lint/support" +) + +func chartWithBadDependencies() chart.Chart { + badChartDeps := chart.Chart{ + Metadata: &chart.Metadata{ + Name: "badchart", + Version: "0.1.0", + APIVersion: "v2", + Dependencies: []*chart.Dependency{ + { + Name: "sub2", + }, + { + Name: "sub3", + }, + }, + }, + } + + badChartDeps.SetDependencies( + &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "sub1", + Version: "0.1.0", + APIVersion: "v2", + }, + }, + &chart.Chart{ + Metadata: &chart.Metadata{ + Name: "sub2", + Version: "0.1.0", + APIVersion: "v2", + }, + }, + ) + return badChartDeps +} + +func TestValidateDependencyInChartsDir(t *testing.T) { + c := chartWithBadDependencies() + + if err := validateDependencyInChartsDir(&c); err == nil { + t.Error("chart should have been flagged for missing deps in chart directory") + } +} + +func TestValidateDependencyInMetadata(t *testing.T) { + c := chartWithBadDependencies() + + if err := validateDependencyInMetadata(&c); err == nil { + t.Errorf("chart should have been flagged for missing deps in chart metadata") + } +} + +func TestDependencies(t *testing.T) { + tmp := ensure.TempDir(t) + defer os.RemoveAll(tmp) + + c := chartWithBadDependencies() + err := chartutil.SaveDir(&c, tmp) + if err != nil { + t.Fatal(err) + } + linter := support.Linter{ChartDir: filepath.Join(tmp, c.Metadata.Name)} + + Dependencies(&linter) + if l := len(linter.Messages); l != 2 { + t.Errorf("expected 2 linter errors for bad chart dependencies. Got %d.", l) + for i, msg := range linter.Messages { + t.Logf("Message: %d, Error: %#v", i, msg) + } + } +} From 971c9215d19ea5ab63f6e3eca971e186442564d6 Mon Sep 17 00:00:00 2001 From: Jack Weldon Date: Fri, 10 Jul 2020 15:44:39 -0400 Subject: [PATCH 104/159] feat(helm): prompt for password with helm repo add Previously in Helm 2, 'helm repo add' would prompt for your password if you only provided the --username flag. This helps prevent someone's credentials from being logged in their shell's history, from showing up in process lists, and from being seen by others nearby. Closes #7174 Signed-off-by: Jack Weldon --- cmd/helm/repo_add.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cmd/helm/repo_add.go b/cmd/helm/repo_add.go index 9c67641e5..3abb58334 100644 --- a/cmd/helm/repo_add.go +++ b/cmd/helm/repo_add.go @@ -24,11 +24,13 @@ import ( "os" "path/filepath" "strings" + "syscall" "time" "github.com/gofrs/flock" "github.com/pkg/errors" "github.com/spf13/cobra" + "golang.org/x/crypto/ssh/terminal" "sigs.k8s.io/yaml" "helm.sh/helm/v3/cmd/helm/require" @@ -114,6 +116,16 @@ func (o *repoAddOptions) run(out io.Writer) error { return errors.Errorf("repository name (%s) already exists, please specify a different name", o.name) } + if o.username != "" && o.password == "" { + fmt.Fprint(out, "Password:") + password, err := terminal.ReadPassword(syscall.Stdin) + fmt.Fprintln(out) + if err != nil { + return err + } + o.password = string(password) + } + c := repo.Entry{ Name: o.name, URL: o.url, From ac1a25517b5ee5c13556a2d4eff313a2909ee497 Mon Sep 17 00:00:00 2001 From: Jack Weldon Date: Fri, 10 Jul 2020 17:59:20 -0400 Subject: [PATCH 105/159] address PR comment, adding whitespace for formatting Signed-off-by: Jack Weldon --- cmd/helm/repo_add.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/repo_add.go b/cmd/helm/repo_add.go index 3abb58334..2fc697ff0 100644 --- a/cmd/helm/repo_add.go +++ b/cmd/helm/repo_add.go @@ -117,7 +117,7 @@ func (o *repoAddOptions) run(out io.Writer) error { } if o.username != "" && o.password == "" { - fmt.Fprint(out, "Password:") + fmt.Fprint(out, "Password: ") password, err := terminal.ReadPassword(syscall.Stdin) fmt.Fprintln(out) if err != nil { From 7ba8343b8d0edc1a3de96ee15003b072c7e72627 Mon Sep 17 00:00:00 2001 From: Jack Weldon Date: Fri, 10 Jul 2020 19:51:38 -0400 Subject: [PATCH 106/159] fix windows build failure caused by #8431 No longer using the 'syscall' package, as further reading into this issue has shown that 'syscall' is deprecated/locked down. Additional issues posted on Golang's github indicates that the newer preferred mechanism to get the file descriptor for stdin is: int(os.Stdin.Fd()) Signed-off-by: Jack Weldon --- cmd/helm/repo_add.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/helm/repo_add.go b/cmd/helm/repo_add.go index 2fc697ff0..418a549c6 100644 --- a/cmd/helm/repo_add.go +++ b/cmd/helm/repo_add.go @@ -24,7 +24,6 @@ import ( "os" "path/filepath" "strings" - "syscall" "time" "github.com/gofrs/flock" @@ -117,8 +116,9 @@ func (o *repoAddOptions) run(out io.Writer) error { } if o.username != "" && o.password == "" { + fd := int(os.Stdin.Fd()) fmt.Fprint(out, "Password: ") - password, err := terminal.ReadPassword(syscall.Stdin) + password, err := terminal.ReadPassword(fd) fmt.Fprintln(out) if err != nil { return err From 8217aba4a6cf04bac538ba2178603ec1378dbaef Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Mon, 13 Jul 2020 10:53:26 +0200 Subject: [PATCH 107/159] fix(kube): use logger instead of fmt.Printf Signed-off-by: Hidde Beydals --- pkg/kube/client.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index f908611db..62e1b104b 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -542,14 +542,14 @@ func (c *Client) waitForPodSuccess(obj runtime.Object, name string) (bool, error switch o.Status.Phase { case v1.PodSucceeded: - fmt.Printf("Pod %s succeeded\n", o.Name) + c.Log("Pod %s succeeded", o.Name) return true, nil case v1.PodFailed: return true, errors.Errorf("pod %s failed", o.Name) case v1.PodPending: - fmt.Printf("Pod %s pending\n", o.Name) + c.Log("Pod %s pending", o.Name) case v1.PodRunning: - fmt.Printf("Pod %s running\n", o.Name) + c.Log("Pod %s running", o.Name) } return false, nil From 57bd8a71b0002b00a13b6a4bfa17e45839b73795 Mon Sep 17 00:00:00 2001 From: Dong Gang Date: Mon, 13 Jul 2020 18:59:09 +0800 Subject: [PATCH 108/159] feature(show): support jsonpath output for `helm show value` Signed-off-by: Dong Gang --- cmd/helm/show.go | 3 +++ pkg/action/show.go | 24 +++++++++++++++++------- pkg/action/show_test.go | 14 ++++++++++++++ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/cmd/helm/show.go b/cmd/helm/show.go index c122d8476..b374a3594 100644 --- a/cmd/helm/show.go +++ b/cmd/helm/show.go @@ -151,6 +151,9 @@ func addShowFlags(subCmd *cobra.Command, client *action.Show) { f := subCmd.Flags() f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored") + if subCmd.Name() == "values" { + f.StringVar(&client.JsonPathTemplate, "jsonpath", "", "use jsonpath output format") + } addChartPathOptionsFlags(f, &client.ChartPathOptions) err := subCmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { diff --git a/pkg/action/show.go b/pkg/action/show.go index 9baa9cf43..a5544492b 100644 --- a/pkg/action/show.go +++ b/pkg/action/show.go @@ -20,11 +20,12 @@ import ( "fmt" "strings" + "helm.sh/helm/v3/pkg/chartutil" + "k8s.io/cli-runtime/pkg/printers" "sigs.k8s.io/yaml" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" - "helm.sh/helm/v3/pkg/chartutil" ) // ShowOutputFormat is the format of the output of `helm show` @@ -52,9 +53,10 @@ func (o ShowOutputFormat) String() string { // It provides the implementation of 'helm show' and its respective subcommands. type Show struct { ChartPathOptions - Devel bool - OutputFormat ShowOutputFormat - chart *chart.Chart // for testing + Devel bool + OutputFormat ShowOutputFormat + JsonPathTemplate string + chart *chart.Chart // for testing } // NewShow creates a new Show object with the given configuration. @@ -87,9 +89,17 @@ func (s *Show) Run(chartpath string) (string, error) { if s.OutputFormat == ShowAll { fmt.Fprintln(&out, "---") } - for _, f := range s.chart.Raw { - if f.Name == chartutil.ValuesfileName { - fmt.Fprintln(&out, string(f.Data)) + if s.JsonPathTemplate != "" { + printer, err := printers.NewJSONPathPrinter(s.JsonPathTemplate) + if err != nil { + return "", fmt.Errorf("error parsing jsonpath %s, %v\n", s.JsonPathTemplate, err) + } + printer.Execute(&out, s.chart.Values) + } else { + for _, f := range s.chart.Raw { + if f.Name == chartutil.ValuesfileName { + fmt.Fprintln(&out, string(f.Data)) + } } } } diff --git a/pkg/action/show_test.go b/pkg/action/show_test.go index 7be9daaa5..0251a528d 100644 --- a/pkg/action/show_test.go +++ b/pkg/action/show_test.go @@ -69,3 +69,17 @@ func TestShowNoValues(t *testing.T) { t.Errorf("expected empty values buffer, got %s", output) } } + +func TestShowValuesByJsonPathFormat(t *testing.T) { + client := NewShow(ShowValues) + client.JsonPathTemplate = "{$.nestedKey.simpleKey}" + client.chart = buildChart(withSampleValues()) + output, err := client.Run("") + if err != nil { + t.Fatal(err) + } + expect := "simpleValue" + if output != expect { + t.Errorf("Expected\n%q\nGot\n%q\n", expect, output) + } +} From 1dfe66aa85bf09cd1f09271c2810c5deb9f22454 Mon Sep 17 00:00:00 2001 From: Dong Gang Date: Mon, 13 Jul 2020 19:11:40 +0800 Subject: [PATCH 109/159] fix the code style error Signed-off-by: Dong Gang --- cmd/helm/show.go | 2 +- pkg/action/show.go | 10 +++++----- pkg/action/show_test.go | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd/helm/show.go b/cmd/helm/show.go index b374a3594..60ed0ab8e 100644 --- a/cmd/helm/show.go +++ b/cmd/helm/show.go @@ -152,7 +152,7 @@ func addShowFlags(subCmd *cobra.Command, client *action.Show) { f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored") if subCmd.Name() == "values" { - f.StringVar(&client.JsonPathTemplate, "jsonpath", "", "use jsonpath output format") + f.StringVar(&client.JSONPathTemplate, "jsonpath", "", "use jsonpath output format") } addChartPathOptionsFlags(f, &client.ChartPathOptions) diff --git a/pkg/action/show.go b/pkg/action/show.go index a5544492b..73d989884 100644 --- a/pkg/action/show.go +++ b/pkg/action/show.go @@ -20,12 +20,12 @@ import ( "fmt" "strings" - "helm.sh/helm/v3/pkg/chartutil" "k8s.io/cli-runtime/pkg/printers" "sigs.k8s.io/yaml" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/chartutil" ) // ShowOutputFormat is the format of the output of `helm show` @@ -55,7 +55,7 @@ type Show struct { ChartPathOptions Devel bool OutputFormat ShowOutputFormat - JsonPathTemplate string + JSONPathTemplate string chart *chart.Chart // for testing } @@ -89,10 +89,10 @@ func (s *Show) Run(chartpath string) (string, error) { if s.OutputFormat == ShowAll { fmt.Fprintln(&out, "---") } - if s.JsonPathTemplate != "" { - printer, err := printers.NewJSONPathPrinter(s.JsonPathTemplate) + if s.JSONPathTemplate != "" { + printer, err := printers.NewJSONPathPrinter(s.JSONPathTemplate) if err != nil { - return "", fmt.Errorf("error parsing jsonpath %s, %v\n", s.JsonPathTemplate, err) + return "", fmt.Errorf("error parsing jsonpath %s, %v", s.JSONPathTemplate, err) } printer.Execute(&out, s.chart.Values) } else { diff --git a/pkg/action/show_test.go b/pkg/action/show_test.go index 0251a528d..a2efdc8ac 100644 --- a/pkg/action/show_test.go +++ b/pkg/action/show_test.go @@ -72,7 +72,7 @@ func TestShowNoValues(t *testing.T) { func TestShowValuesByJsonPathFormat(t *testing.T) { client := NewShow(ShowValues) - client.JsonPathTemplate = "{$.nestedKey.simpleKey}" + client.JSONPathTemplate = "{$.nestedKey.simpleKey}" client.chart = buildChart(withSampleValues()) output, err := client.Run("") if err != nil { From fe40c4bf844feee87c3b3c1163b7f5f40dc9a793 Mon Sep 17 00:00:00 2001 From: Bridget Kromhout Date: Mon, 13 Jul 2020 15:31:26 -0500 Subject: [PATCH 110/159] Clarify comments to match practice Signed-off-by: Bridget Kromhout --- internal/version/version.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/version/version.go b/internal/version/version.go index 712aae640..6154ff3a4 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -25,11 +25,9 @@ import ( var ( // version is the current version of Helm. // Update this whenever making a new release. - // The version is of the format Major.Minor.Patch[-Prerelease][+BuildMetadata] // // Increment major number for new feature additions and behavioral changes. // Increment minor number for bug fixes and performance enhancements. - // Increment patch number for critical fixes to existing releases. version = "v3.3" // metadata is extra build time data From 5684c864908819ad43dfa6efb6f474611d721e7c Mon Sep 17 00:00:00 2001 From: Bridget Kromhout Date: Mon, 13 Jul 2020 15:37:12 -0500 Subject: [PATCH 111/159] Fixing version and spelling errors Signed-off-by: Bridget Kromhout --- pkg/chartutil/capabilities_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/chartutil/capabilities_test.go b/pkg/chartutil/capabilities_test.go index ae9624bca..66eeee755 100644 --- a/pkg/chartutil/capabilities_test.go +++ b/pkg/chartutil/capabilities_test.go @@ -55,7 +55,7 @@ func TestDefaultCapabilities(t *testing.T) { t.Errorf("Expected default KubeVersion.Major to be 1, got %q", kv.Major) } if kv.Minor != "18" { - t.Errorf("Expected default KubeVersion.Minor to be 16, got %q", kv.Minor) + t.Errorf("Expected default KubeVersion.Minor to be 18, got %q", kv.Minor) } } @@ -63,6 +63,6 @@ func TestDefaultCapabilitiesHelmVersion(t *testing.T) { hv := DefaultCapabilities.HelmVersion if hv.Version != "v3.3" { - t.Errorf("Expected default HelmVerison to be v3.3, got %q", hv.Version) + t.Errorf("Expected default HelmVersion to be v3.3, got %q", hv.Version) } } From 9a4f4ec64b8092d2ba3d7493001837df4737e36c Mon Sep 17 00:00:00 2001 From: Cristian Klein Date: Thu, 2 Jan 2020 00:23:10 +0100 Subject: [PATCH 112/159] fix(helm): Avoid corrupting storage via a lock If two `helm upgrade`s are executed at the exact same time, then one of the invocations will fail with "already exists". If one `helm upgrade` is executed and a second one is started while the first is in `pending-upgrade`, then the second invocation will create a new release. Effectively, two helm invocations will simultaneously change the state of Kubernetes resources -- which is scary -- then two releases will be in `deployed` state -- which can cause other issues. This commit fixes the corrupted storage problem, by introducting a poor person's lock. If the last release is in a pending state, then helm will abort. If the last release is in a pending state, due to a previously killed helm, then the user is expected to do `helm rollback`. Closes #7274 Signed-off-by: Cristian Klein --- pkg/action/action.go | 2 ++ pkg/action/upgrade.go | 5 +++++ pkg/release/status.go | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/pkg/action/action.go b/pkg/action/action.go index 698ebd23f..fec86cd42 100644 --- a/pkg/action/action.go +++ b/pkg/action/action.go @@ -60,6 +60,8 @@ var ( errInvalidRevision = errors.New("invalid release revision") // errInvalidName indicates that an invalid release name was provided errInvalidName = errors.New("invalid release name, must match regex ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+$ and the length must not longer than 53") + // errPending indicates that another instance of Helm is already applying an operation on a release. + errPending = errors.New("another operation (install/upgrade/rollback) is in progress") ) // ValidName is a regular expression for resource names. diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index 921a0eba5..949aebcae 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -170,6 +170,11 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chart.Chart, vals map[strin return nil, nil, err } + // Concurrent `helm upgrade`s will either fail here with `errPending` or when creating the release with "already exists". This should act as a pessimistic lock. + if lastRelease.Info.Status.IsPending() { + return nil, nil, errPending + } + var currentRelease *release.Release if lastRelease.Info.Status == release.StatusDeployed { // no need to retrieve the last deployed release from storage as the last release is deployed diff --git a/pkg/release/status.go b/pkg/release/status.go index 49b0f1544..e0e3ed62a 100644 --- a/pkg/release/status.go +++ b/pkg/release/status.go @@ -42,3 +42,8 @@ const ( ) func (x Status) String() string { return string(x) } + +// IsPending determines if this status is a state or a transition. +func (x Status) IsPending() bool { + return x == StatusPendingInstall || x == StatusPendingUpgrade || x == StatusPendingRollback +} From 20fb7bac4e9001751a0b04c71006b4bb506378cf Mon Sep 17 00:00:00 2001 From: Cristian Klein Date: Thu, 9 Jan 2020 00:38:47 +0100 Subject: [PATCH 113/159] fix(helm): Added test for concurrent upgrades Signed-off-by: Cristian Klein --- pkg/action/upgrade_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pkg/action/upgrade_test.go b/pkg/action/upgrade_test.go index f25d115c4..f16de6479 100644 --- a/pkg/action/upgrade_test.go +++ b/pkg/action/upgrade_test.go @@ -253,3 +253,23 @@ func TestUpgradeRelease_ReuseValues(t *testing.T) { is.Equal(expectedValues, updatedRes.Config) }) } + +func TestUpgradeRelease_Pending(t *testing.T) { + req := require.New(t) + + upAction := upgradeAction(t) + rel := releaseStub() + rel.Name = "come-fail-away" + rel.Info.Status = release.StatusDeployed + upAction.cfg.Releases.Create(rel) + rel2 := releaseStub() + rel2.Name = "come-fail-away" + rel2.Info.Status = release.StatusPendingUpgrade + rel2.Version = 2 + upAction.cfg.Releases.Create(rel2) + + vals := map[string]interface{}{} + + _, err := upAction.Run(rel.Name, buildChart(), vals) + req.Contains(err.Error(), "progress", err) +} From 08517a9ec0abbf238d56ec97de80e6ecc8946ab6 Mon Sep 17 00:00:00 2001 From: Bridget Kromhout Date: Mon, 13 Jul 2020 16:04:15 -0500 Subject: [PATCH 114/159] Correct make target in Makefile Signed-off-by: Bridget Kromhout --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 524421279..f8325480a 100644 --- a/Makefile +++ b/Makefile @@ -183,7 +183,7 @@ clean: .PHONY: release-notes release-notes: @if [ ! -d "./_dist" ]; then \ - echo "please run 'make fetch-release' first" && \ + echo "please run 'make fetch-dist' first" && \ exit 1; \ fi @if [ -z "${PREVIOUS_RELEASE}" ]; then \ From 0d70c63396083f868963797632715f06c9b90ca9 Mon Sep 17 00:00:00 2001 From: Cristian Klein Date: Mon, 13 Jul 2020 23:41:25 +0200 Subject: [PATCH 115/159] fix(helm): Update test during pending install Signed-off-by: Cristian Klein --- cmd/helm/testdata/output/upgrade-with-pending-install.txt | 1 + cmd/helm/upgrade_test.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 cmd/helm/testdata/output/upgrade-with-pending-install.txt diff --git a/cmd/helm/testdata/output/upgrade-with-pending-install.txt b/cmd/helm/testdata/output/upgrade-with-pending-install.txt new file mode 100644 index 000000000..57a8e7873 --- /dev/null +++ b/cmd/helm/testdata/output/upgrade-with-pending-install.txt @@ -0,0 +1 @@ +Error: UPGRADE FAILED: another operation (install/upgrade/rollback) is in progress diff --git a/cmd/helm/upgrade_test.go b/cmd/helm/upgrade_test.go index 7e88bc0df..64daf2934 100644 --- a/cmd/helm/upgrade_test.go +++ b/cmd/helm/upgrade_test.go @@ -158,7 +158,7 @@ func TestUpgradeCmd(t *testing.T) { { name: "upgrade a pending install release", cmd: fmt.Sprintf("upgrade funny-bunny '%s'", chartPath), - golden: "output/upgrade-with-bad-or-missing-existing-release.txt", + golden: "output/upgrade-with-pending-install.txt", wantError: true, rels: []*release.Release{relWithStatusMock("funny-bunny", 2, ch, release.StatusPendingInstall)}, }, From 4be3804c50e4a4260e8e49680e2826c66e32d898 Mon Sep 17 00:00:00 2001 From: wawa0210 Date: Thu, 9 Jul 2020 17:40:36 +0800 Subject: [PATCH 116/159] Rollback command support for max history Signed-off-by: wawa0210 --- cmd/helm/rollback.go | 1 + pkg/action/rollback.go | 3 +++ 2 files changed, 4 insertions(+) diff --git a/cmd/helm/rollback.go b/cmd/helm/rollback.go index 4849913a1..2cd6fa2cb 100644 --- a/cmd/helm/rollback.go +++ b/cmd/helm/rollback.go @@ -83,6 +83,7 @@ func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)") f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment, StatefulSet, or ReplicaSet are in a ready state before marking the release as successful. It will wait for as long as --timeout") f.BoolVar(&client.CleanupOnFail, "cleanup-on-fail", false, "allow deletion of new resources created in this rollback when rollback fails") + f.IntVar(&client.MaxHistory, "history-max", settings.MaxHistory, "limit the maximum number of revisions saved per release. Use 0 for no limit") return cmd } diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index 81812983f..8773b6271 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -42,6 +42,7 @@ type Rollback struct { Recreate bool // will (if true) recreate pods after a rollback. Force bool // will (if true) force resource upgrade through uninstall/recreate if needed CleanupOnFail bool + MaxHistory int // MaxHistory limits the maximum number of revisions saved per release } // NewRollback creates a new Rollback object with the given configuration. @@ -57,6 +58,8 @@ func (r *Rollback) Run(name string) error { return err } + r.cfg.Releases.MaxHistory = r.MaxHistory + r.cfg.Log("preparing rollback of %s", name) currentRelease, targetRelease, err := r.prepareRollback(name) if err != nil { From c709e10b3204b823f7e00bae8ca59b6db65e9865 Mon Sep 17 00:00:00 2001 From: Bridget Kromhout Date: Tue, 14 Jul 2020 11:05:37 -0500 Subject: [PATCH 117/159] Reinstating comment that is still accurate Signed-off-by: Bridget Kromhout --- internal/version/version.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/version/version.go b/internal/version/version.go index 6154ff3a4..2941bb489 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -25,6 +25,7 @@ import ( var ( // version is the current version of Helm. // Update this whenever making a new release. + // The version is of the format Major.Minor.Patch[-Prerelease][+BuildMetadata] // // Increment major number for new feature additions and behavioral changes. // Increment minor number for bug fixes and performance enhancements. From 3ee7047827b0fc5b87fb2d8bde6bb64fa93fcf73 Mon Sep 17 00:00:00 2001 From: Dong Gang Date: Wed, 15 Jul 2020 11:09:01 +0800 Subject: [PATCH 118/159] polish the help text of flag Signed-off-by: Dong Gang --- cmd/helm/show.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/show.go b/cmd/helm/show.go index 60ed0ab8e..fe5eaee26 100644 --- a/cmd/helm/show.go +++ b/cmd/helm/show.go @@ -152,7 +152,7 @@ func addShowFlags(subCmd *cobra.Command, client *action.Show) { f.BoolVar(&client.Devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored") if subCmd.Name() == "values" { - f.StringVar(&client.JSONPathTemplate, "jsonpath", "", "use jsonpath output format") + f.StringVar(&client.JSONPathTemplate, "jsonpath", "", "supply a JSONPath expression to filter the output") } addChartPathOptionsFlags(f, &client.ChartPathOptions) From 9777925a2ae1e98a3e7ec3923d0b56b7199c7806 Mon Sep 17 00:00:00 2001 From: Dong Gang Date: Thu, 16 Jul 2020 09:10:03 +0800 Subject: [PATCH 119/159] fix(create): update the hook name of test-connection pod Signed-off-by: Dong Gang --- pkg/chartutil/create.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index e74761b3f..c036ce37d 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -457,7 +457,7 @@ metadata: labels: {{- include ".labels" . | nindent 4 }} annotations: - "helm.sh/hook": test-success + "helm.sh/hook": test spec: containers: - name: wget From 844e575d2a7090903c26e658037e3298ecff9479 Mon Sep 17 00:00:00 2001 From: Simon Shine Date: Fri, 17 Jul 2020 06:33:27 +0200 Subject: [PATCH 120/159] Alter whitespace in "Update Complete" output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most places say "Happy Helming!". But pkg/downloader/manager.go also says "⎈Happy Helming!⎈" Signed-off-by: Simon Shine --- cmd/helm/repo_update.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/repo_update.go b/cmd/helm/repo_update.go index 5c1086e81..cbfc05b00 100644 --- a/cmd/helm/repo_update.go +++ b/cmd/helm/repo_update.go @@ -96,5 +96,5 @@ func updateCharts(repos []*repo.ChartRepository, out io.Writer) { }(re) } wg.Wait() - fmt.Fprintln(out, "Update Complete. ⎈ Happy Helming!⎈ ") + fmt.Fprintln(out, "Update Complete. ⎈Happy Helming!⎈") } From 9a13385022b0976a704c24c8d11e7b0f3561b931 Mon Sep 17 00:00:00 2001 From: Chris Wells Date: Sun, 19 Jul 2020 14:42:04 -0400 Subject: [PATCH 121/159] fix: Allow building in a path containing spaces Signed-off-by: Chris Wells --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index f8325480a..97f99fd86 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,7 @@ all: build build: $(BINDIR)/$(BINNAME) $(BINDIR)/$(BINNAME): $(SRC) - GO111MODULE=on go build $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o $(BINDIR)/$(BINNAME) ./cmd/helm + GO111MODULE=on go build $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o '$(BINDIR)'/$(BINNAME) ./cmd/helm # ------------------------------------------------------------------------------ # test @@ -97,7 +97,7 @@ test-acceptance: TARGETS = linux/amd64 test-acceptance: build build-cross @if [ -d "${ACCEPTANCE_DIR}" ]; then \ cd ${ACCEPTANCE_DIR} && \ - ROBOT_RUN_TESTS=$(ACCEPTANCE_RUN_TESTS) ROBOT_HELM_PATH=$(BINDIR) make acceptance; \ + ROBOT_RUN_TESTS=$(ACCEPTANCE_RUN_TESTS) ROBOT_HELM_PATH='$(BINDIR)' make acceptance; \ else \ echo "You must clone the acceptance_testing repo under $(ACCEPTANCE_DIR)"; \ echo "You can find the acceptance_testing repo at https://github.com/helm/acceptance-testing"; \ @@ -178,7 +178,7 @@ checksum: .PHONY: clean clean: - @rm -rf $(BINDIR) ./_dist + @rm -rf '$(BINDIR)' ./_dist .PHONY: release-notes release-notes: From ffc3d42f87f8334684f12372bbdda8147702a12d Mon Sep 17 00:00:00 2001 From: Holder Date: Wed, 22 Jul 2020 23:03:25 +0800 Subject: [PATCH 122/159] fix(sdk): Polish the downloader/manager package error return (#8491) * fix(sdk): Polish the downloader/manager package error return Close #8471 Signed-off-by: Dong Gang * Modify the repositories validation function `resloveRepoNames` and add a unit test. Signed-off-by: Dong Gang * Remove wrong commit Signed-off-by: Dong Gang --- cmd/helm/dependency_build.go | 7 ++++++- pkg/downloader/manager.go | 13 ++++++++++++- pkg/downloader/manager_test.go | 29 +++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/cmd/helm/dependency_build.go b/cmd/helm/dependency_build.go index 478b49479..4e87684ce 100644 --- a/cmd/helm/dependency_build.go +++ b/cmd/helm/dependency_build.go @@ -16,6 +16,7 @@ limitations under the License. package main import ( + "fmt" "io" "os" "path/filepath" @@ -65,7 +66,11 @@ func newDependencyBuildCmd(out io.Writer) *cobra.Command { if client.Verify { man.Verify = downloader.VerifyIfPossible } - return man.Build() + err := man.Build() + if e, ok := err.(downloader.ErrRepoNotFound); ok { + return fmt.Errorf("%s. Please add the missing repos via 'helm repo add'", e.Error()) + } + return err }, } diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 00198de0c..2d6918739 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -42,6 +42,17 @@ import ( "helm.sh/helm/v3/pkg/repo" ) +// ErrRepoNotFound indicates that chart repositories can't be found in local repo cache. +// The value of Repos is missing repos. +type ErrRepoNotFound struct { + Repos []string +} + +// Error implements the error interface. +func (e ErrRepoNotFound) Error() string { + return fmt.Sprintf("no repository definition for %s", strings.Join(e.Repos, ", ")) +} + // Manager handles the lifecycle of fetching, resolving, and storing dependencies. type Manager struct { // Out is used to print warnings and notifications. @@ -411,7 +422,7 @@ Loop: missing = append(missing, dd.Repository) } if len(missing) > 0 { - return errors.Errorf("no repository definition for %s. Please add the missing repos via 'helm repo add'", strings.Join(missing, ", ")) + return ErrRepoNotFound{missing} } return nil } diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index ea235c13f..dd3cbbd7b 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -360,3 +360,32 @@ func TestBuild_WithRepositoryAlias(t *testing.T) { Repository: "@test", }) } + +func TestErrRepoNotFound_Error(t *testing.T) { + type fields struct { + Repos []string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "OK", + fields: fields{ + Repos: []string{"https://charts1.example.com", "https://charts2.example.com"}, + }, + want: "no repository definition for https://charts1.example.com, https://charts2.example.com", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := ErrRepoNotFound{ + Repos: tt.fields.Repos, + } + if got := e.Error(); got != tt.want { + t.Errorf("Error() = %v, want %v", got, tt.want) + } + }) + } +} From f9d35242d0cc3774e4c4d937e6c00c49aa8c6c7f Mon Sep 17 00:00:00 2001 From: Andrew Melis Date: Wed, 22 Jul 2020 12:21:30 -0400 Subject: [PATCH 123/159] Enhance readability by extracting bitwise operation Fixes https://github.com/helm/helm/pull/8282#discussion_r458368780 Signed-off-by: Andrew Melis --- pkg/action/list.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/action/list.go b/pkg/action/list.go index 3d5e6d7a6..0f85de519 100644 --- a/pkg/action/list.go +++ b/pkg/action/list.go @@ -250,7 +250,8 @@ func (l *List) filterStateMask(releases []*release.Release) []*release.Release { for _, rls := range releases { currentStatus := l.StateMask.FromName(rls.Info.Status.String()) - if l.StateMask¤tStatus == 0 { + mask := l.StateMask & currentStatus + if mask == 0 { continue } desiredStateReleases = append(desiredStateReleases, rls) From ff147e9ed7463f6349ee416da723949ae2d33330 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Thu, 16 Jul 2020 11:03:08 -0400 Subject: [PATCH 124/159] Locking file URIs to a version in lockfile Previously, if a range was specified for a file:// url as a dependency the range would be put in the lockfile. Lockfiles are designed to pin to a specific version and not support ranges. This is for reproducibility. The change here pins to a the specific version of the chart specified using the file:// when update is run. Signed-off-by: Matt Farina --- internal/resolver/resolver.go | 13 +++++++++++-- internal/resolver/resolver_test.go | 11 +++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/internal/resolver/resolver.go b/internal/resolver/resolver.go index cec29c947..c72a39e82 100644 --- a/internal/resolver/resolver.go +++ b/internal/resolver/resolver.go @@ -27,6 +27,7 @@ import ( "github.com/pkg/errors" "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v3/pkg/provenance" "helm.sh/helm/v3/pkg/repo" @@ -68,14 +69,22 @@ func (r *Resolver) Resolve(reqs []*chart.Dependency, repoNames map[string]string } if strings.HasPrefix(d.Repository, "file://") { - if _, err := GetLocalPath(d.Repository, r.chartpath); err != nil { + chartpath, err := GetLocalPath(d.Repository, r.chartpath) + if err != nil { + return nil, err + } + + // The version of the chart locked will be the version of the chart + // currently listed in the file system within the chart. + ch, err := loader.LoadDir(chartpath) + if err != nil { return nil, err } locked[i] = &chart.Dependency{ Name: d.Name, Repository: d.Repository, - Version: d.Version, + Version: ch.Metadata.Version, } continue } diff --git a/internal/resolver/resolver_test.go b/internal/resolver/resolver_test.go index 0b0c3a6f8..f59188508 100644 --- a/internal/resolver/resolver_test.go +++ b/internal/resolver/resolver_test.go @@ -82,6 +82,17 @@ func TestResolve(t *testing.T) { }, }, }, + { + name: "repo from valid local path with range resolution", + req: []*chart.Dependency{ + {Name: "base", Repository: "file://base", Version: "^0.1.0"}, + }, + expect: &chart.Lock{ + Dependencies: []*chart.Dependency{ + {Name: "base", Repository: "file://base", Version: "0.1.0"}, + }, + }, + }, { name: "repo from invalid local path", req: []*chart.Dependency{ From 9cb90a8b234f98c16aef0918cba92d83061d7c97 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Fri, 17 Jul 2020 11:54:44 -0400 Subject: [PATCH 125/159] Make unmanaged repositories version resolvable If a repository was not know to helm (e.g. added using helm repo add) then Helm would use the range set in the depenencies as the version in the lock file. Lock files should not have ranges since they are locked to versions. Helm did this because the version information for repositories was not know to Helm. This change fixes that by making the repository and chart information known to Helm so it can resolve the versions. Closes #8449 Signed-off-by: Matt Farina --- pkg/downloader/manager.go | 132 ++++++++++++++++++++++++--------- pkg/downloader/manager_test.go | 30 ++++++++ 2 files changed, 126 insertions(+), 36 deletions(-) diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 2d6918739..9db5ed928 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -16,6 +16,8 @@ limitations under the License. package downloader import ( + "crypto" + "encoding/hex" "fmt" "io" "io/ioutil" @@ -106,7 +108,13 @@ func (m *Manager) Build() error { } } - if _, err := m.resolveRepoNames(req); err != nil { + repoNames, err := m.resolveRepoNames(req) + if err != nil { + return err + } + + _, err = m.ensureMissingRepos(repoNames, req) + if err != nil { return err } @@ -124,11 +132,6 @@ func (m *Manager) Build() error { } } - // Check that all of the repos we're dependent on actually exist. - if err := m.hasAllRepos(lock.Dependencies); err != nil { - return err - } - if !m.SkipUpdate { // For each repo in the file, update the cached copy of that repo if err := m.UpdateRepositories(); err != nil { @@ -158,14 +161,23 @@ func (m *Manager) Update() error { return nil } - // Check that all of the repos we're dependent on actually exist and - // the repo index names. + // Get the names of the repositories the dependencies need that Helm is + // configured to know about. repoNames, err := m.resolveRepoNames(req) if err != nil { return err } - // For each repo in the file, update the cached copy of that repo + // For the repositories Helm is not configured to know about, ensure Helm + // has some information about them and, when possible, the index files + // locally. + repoNames, err = m.ensureMissingRepos(repoNames, req) + if err != nil { + return err + } + + // For each of the repositories Helm is configured to know about, update + // the index information locally. if !m.SkipUpdate { if err := m.UpdateRepositories(); err != nil { return err @@ -393,38 +405,60 @@ func (m *Manager) safeDeleteDep(name, dir string) error { return nil } -// hasAllRepos ensures that all of the referenced deps are in the local repo cache. -func (m *Manager) hasAllRepos(deps []*chart.Dependency) error { - rf, err := loadRepoConfig(m.RepositoryConfig) - if err != nil { - return err - } - repos := rf.Repositories +// ensureMissingRepos attempts to ensure the repository information for repos +// not managed by Helm is present. This takes in the repoNames Helm is configured +// to work with along with the chart dependencies. It will find the deps not +// in a known repo and attempt to ensure the data is present for steps like +// version resolution. +func (m *Manager) ensureMissingRepos(repoNames map[string]string, deps []*chart.Dependency) (map[string]string, error) { + + var ru []*repo.Entry - // Verify that all repositories referenced in the deps are actually known - // by Helm. - missing := []string{} -Loop: for _, dd := range deps { - // If repo is from local path, continue - if strings.HasPrefix(dd.Repository, "file://") { + + // When the repoName for a dependency is known we can skip ensuring + if _, ok := repoNames[dd.Name]; ok { continue } - if dd.Repository == "" { - continue + // The generated repository name, which will result in an index being + // locally cached, has a name pattern of "helm-manager-" followed by a + // sha256 of the repo name. This assumes end users will never create + // repositories with these names pointing to other repositories. Using + // this method of naming allows the existing repository pulling and + // resolution code to do most of the work. + rn, err := key(dd.Repository) + if err != nil { + return repoNames, err } - for _, repo := range repos { - if urlutil.Equal(repo.URL, strings.TrimSuffix(dd.Repository, "/")) { - continue Loop - } + rn = "helm-manager-" + rn + + repoNames[dd.Name] = rn + + // Assuming the repository is generally available. For Helm managed + // access controls the repository needs to be added through the user + // managed system. This path will work for public charts, like those + // supplied by Bitnami, but not for protected charts, like corp ones + // behind a username and pass. + ri := &repo.Entry{ + Name: rn, + URL: dd.Repository, } - missing = append(missing, dd.Repository) + ru = append(ru, ri) } - if len(missing) > 0 { - return ErrRepoNotFound{missing} + + // Calls to UpdateRepositories (a public function) will only update + // repositories configured by the user. Here we update repos found in + // the dependencies that are not known to the user if update skipping + // is not configured. + if !m.SkipUpdate && len(ru) > 0 { + fmt.Fprintln(m.Out, "Getting updates for unmanaged Helm repositories...") + if err := m.parallelRepoUpdate(ru); err != nil { + return repoNames, err + } } - return nil + + return repoNames, nil } // resolveRepoNames returns the repo names of the referenced deps which can be used to fetch the cached index file @@ -517,16 +551,18 @@ func (m *Manager) UpdateRepositories() error { } repos := rf.Repositories if len(repos) > 0 { + fmt.Fprintln(m.Out, "Hang tight while we grab the latest from your chart repositories...") // This prints warnings straight to out. if err := m.parallelRepoUpdate(repos); err != nil { return err } + fmt.Fprintln(m.Out, "Update Complete. ⎈Happy Helming!⎈") } return nil } func (m *Manager) parallelRepoUpdate(repos []*repo.Entry) error { - fmt.Fprintln(m.Out, "Hang tight while we grab the latest from your chart repositories...") + var wg sync.WaitGroup for _, c := range repos { r, err := repo.NewChartRepository(c, m.Getters) @@ -536,15 +572,27 @@ func (m *Manager) parallelRepoUpdate(repos []*repo.Entry) error { wg.Add(1) go func(r *repo.ChartRepository) { if _, err := r.DownloadIndexFile(); err != nil { - fmt.Fprintf(m.Out, "...Unable to get an update from the %q chart repository (%s):\n\t%s\n", r.Config.Name, r.Config.URL, err) + // For those dependencies that are not known to helm and using a + // generated key name we display the repo url. + if strings.HasPrefix(r.Config.Name, "helm-manager-") { + fmt.Fprintf(m.Out, "...Unable to get an update from the %q chart repository:\n\t%s\n", r.Config.URL, err) + } else { + fmt.Fprintf(m.Out, "...Unable to get an update from the %q chart repository (%s):\n\t%s\n", r.Config.Name, r.Config.URL, err) + } } else { - fmt.Fprintf(m.Out, "...Successfully got an update from the %q chart repository\n", r.Config.Name) + // For those dependencies that are not known to helm and using a + // generated key name we display the repo url. + if strings.HasPrefix(r.Config.Name, "helm-manager-") { + fmt.Fprintf(m.Out, "...Successfully got an update from the %q chart repository\n", r.Config.URL) + } else { + fmt.Fprintf(m.Out, "...Successfully got an update from the %q chart repository\n", r.Config.Name) + } } wg.Done() }(r) } wg.Wait() - fmt.Fprintln(m.Out, "Update Complete. ⎈Happy Helming!⎈") + return nil } @@ -739,3 +787,15 @@ func move(tmpPath, destPath string) error { } return nil } + +// key is used to turn a name, such as a repository url, into a filesystem +// safe name that is unique for querying. To accomplish this a unique hash of +// the string is used. +func key(name string) (string, error) { + in := strings.NewReader(name) + hash := crypto.SHA256.New() + if _, err := io.Copy(hash, in); err != nil { + return "", nil + } + return hex.EncodeToString(hash.Sum(nil)), nil +} diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go index dd3cbbd7b..e60cf7624 100644 --- a/pkg/downloader/manager_test.go +++ b/pkg/downloader/manager_test.go @@ -389,3 +389,33 @@ func TestErrRepoNotFound_Error(t *testing.T) { }) } } + +func TestKey(t *testing.T) { + tests := []struct { + name string + expect string + }{ + { + name: "file:////tmp", + expect: "afeed3459e92a874f6373aca264ce1459bfa91f9c1d6612f10ae3dc2ee955df3", + }, + { + name: "https://example.com/charts", + expect: "7065c57c94b2411ad774638d76823c7ccb56415441f5ab2f5ece2f3845728e5d", + }, + { + name: "foo/bar/baz", + expect: "15c46a4f8a189ae22f36f201048881d6c090c93583bedcf71f5443fdef224c82", + }, + } + + for _, tt := range tests { + o, err := key(tt.name) + if err != nil { + t.Fatalf("unable to generate key for %q with error: %s", tt.name, err) + } + if o != tt.expect { + t.Errorf("wrong key name generated for %q, expected %q but got %q", tt.name, tt.expect, o) + } + } +} From 1458113696297a7d0426f275c9d0689d4d0ff47e Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Fri, 17 Jul 2020 15:44:50 -0400 Subject: [PATCH 126/159] Adding helm v4 todo Signed-off-by: Matt Farina --- pkg/downloader/manager.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 9db5ed928..6a4058c2c 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -171,6 +171,10 @@ func (m *Manager) Update() error { // For the repositories Helm is not configured to know about, ensure Helm // has some information about them and, when possible, the index files // locally. + // TODO(mattfarina): Repositories should be explicitly added by end users + // rather than automattic. In Helm v4 require users to add repositories. They + // should have to add them in order to make sure they are aware of the + // respoitories and opt-in to any locations. For security. repoNames, err = m.ensureMissingRepos(repoNames, req) if err != nil { return err From 25f67f74eeee861e132d1a0220144c87631dbe38 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Wed, 22 Jul 2020 15:51:27 -0400 Subject: [PATCH 127/159] Restoring Build behavior Two things changed in this commit... 1. The Build behavior was restored and the change only impacts Update. This is a more minimal functionality change thats a more secure behavior 2. Cleanup from Josh's feedback on the PR to create a const and comment changes Signed-off-by: Matt Farina --- pkg/downloader/manager.go | 58 +++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go index 6a4058c2c..bcd5dcec4 100644 --- a/pkg/downloader/manager.go +++ b/pkg/downloader/manager.go @@ -108,13 +108,7 @@ func (m *Manager) Build() error { } } - repoNames, err := m.resolveRepoNames(req) - if err != nil { - return err - } - - _, err = m.ensureMissingRepos(repoNames, req) - if err != nil { + if _, err := m.resolveRepoNames(req); err != nil { return err } @@ -132,6 +126,11 @@ func (m *Manager) Build() error { } } + // Check that all of the repos we're dependent on actually exist. + if err := m.hasAllRepos(lock.Dependencies); err != nil { + return err + } + if !m.SkipUpdate { // For each repo in the file, update the cached copy of that repo if err := m.UpdateRepositories(); err != nil { @@ -174,7 +173,7 @@ func (m *Manager) Update() error { // TODO(mattfarina): Repositories should be explicitly added by end users // rather than automattic. In Helm v4 require users to add repositories. They // should have to add them in order to make sure they are aware of the - // respoitories and opt-in to any locations. For security. + // respoitories and opt-in to any locations, for security. repoNames, err = m.ensureMissingRepos(repoNames, req) if err != nil { return err @@ -409,6 +408,40 @@ func (m *Manager) safeDeleteDep(name, dir string) error { return nil } +// hasAllRepos ensures that all of the referenced deps are in the local repo cache. +func (m *Manager) hasAllRepos(deps []*chart.Dependency) error { + rf, err := loadRepoConfig(m.RepositoryConfig) + if err != nil { + return err + } + repos := rf.Repositories + + // Verify that all repositories referenced in the deps are actually known + // by Helm. + missing := []string{} +Loop: + for _, dd := range deps { + // If repo is from local path, continue + if strings.HasPrefix(dd.Repository, "file://") { + continue + } + + if dd.Repository == "" { + continue + } + for _, repo := range repos { + if urlutil.Equal(repo.URL, strings.TrimSuffix(dd.Repository, "/")) { + continue Loop + } + } + missing = append(missing, dd.Repository) + } + if len(missing) > 0 { + return ErrRepoNotFound{missing} + } + return nil +} + // ensureMissingRepos attempts to ensure the repository information for repos // not managed by Helm is present. This takes in the repoNames Helm is configured // to work with along with the chart dependencies. It will find the deps not @@ -435,7 +468,7 @@ func (m *Manager) ensureMissingRepos(repoNames map[string]string, deps []*chart. if err != nil { return repoNames, err } - rn = "helm-manager-" + rn + rn = managerKeyPrefix + rn repoNames[dd.Name] = rn @@ -578,7 +611,7 @@ func (m *Manager) parallelRepoUpdate(repos []*repo.Entry) error { if _, err := r.DownloadIndexFile(); err != nil { // For those dependencies that are not known to helm and using a // generated key name we display the repo url. - if strings.HasPrefix(r.Config.Name, "helm-manager-") { + if strings.HasPrefix(r.Config.Name, managerKeyPrefix) { fmt.Fprintf(m.Out, "...Unable to get an update from the %q chart repository:\n\t%s\n", r.Config.URL, err) } else { fmt.Fprintf(m.Out, "...Unable to get an update from the %q chart repository (%s):\n\t%s\n", r.Config.Name, r.Config.URL, err) @@ -586,7 +619,7 @@ func (m *Manager) parallelRepoUpdate(repos []*repo.Entry) error { } else { // For those dependencies that are not known to helm and using a // generated key name we display the repo url. - if strings.HasPrefix(r.Config.Name, "helm-manager-") { + if strings.HasPrefix(r.Config.Name, managerKeyPrefix) { fmt.Fprintf(m.Out, "...Successfully got an update from the %q chart repository\n", r.Config.URL) } else { fmt.Fprintf(m.Out, "...Successfully got an update from the %q chart repository\n", r.Config.Name) @@ -792,6 +825,9 @@ func move(tmpPath, destPath string) error { return nil } +// The prefix to use for cache keys created by the manager for repo names +const managerKeyPrefix = "helm-manager-" + // key is used to turn a name, such as a repository url, into a filesystem // safe name that is unique for querying. To accomplish this a unique hash of // the string is used. From d141593d834f99822c08b9f3ca768258483afbf1 Mon Sep 17 00:00:00 2001 From: She Jiayu Date: Thu, 23 Jul 2020 12:28:43 +0800 Subject: [PATCH 128/159] Avoid hardcoded container port in default notes Signed-off-by: She Jiayu --- pkg/chartutil/create.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index c036ce37d..6e382b961 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -381,8 +381,9 @@ const defaultNotes = `1. Get the application URL by running these commands: echo http://$SERVICE_IP:{{ .Values.service.port }} {{- else if contains "ClusterIP" .Values.service.type }} export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include ".name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") echo "Visit http://127.0.0.1:8080 to use your application" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80 + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT {{- end }} ` From 4faeedd98b03e5af7733317a84e77ebff28c55f7 Mon Sep 17 00:00:00 2001 From: Rajat Jindal Date: Thu, 23 Jul 2020 11:51:17 +0530 Subject: [PATCH 129/159] fix watch error due to elb/proxy timeout Signed-off-by: Rajat Jindal --- pkg/kube/client.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 62e1b104b..decfc2e6e 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -35,6 +35,7 @@ import ( "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -478,7 +479,7 @@ func (c *Client) watchUntilReady(timeout time.Duration, info *resource.Info) err ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), timeout) defer cancel() - _, err = watchtools.ListWatchUntil(ctx, lw, func(e watch.Event) (bool, error) { + _, err = watchtools.UntilWithSync(ctx, lw, &unstructured.Unstructured{}, nil, func(e watch.Event) (bool, error) { // Make sure the incoming object is versioned as we use unstructured // objects when we build manifests obj := convertWithMapper(e.Object, info.Mapping) From b6bbf34097312fefec8120fe066780340f2d983f Mon Sep 17 00:00:00 2001 From: Haoming Zhang Date: Thu, 23 Jul 2020 21:04:18 -0700 Subject: [PATCH 130/159] Close gzip reader when done. Signed-off-by: Haoming Zhang --- pkg/storage/driver/util.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/storage/driver/util.go b/pkg/storage/driver/util.go index a87002ab4..e5b846163 100644 --- a/pkg/storage/driver/util.go +++ b/pkg/storage/driver/util.go @@ -68,6 +68,7 @@ func decodeRelease(data string) (*rspb.Release, error) { if err != nil { return nil, err } + defer r.Close() b2, err := ioutil.ReadAll(r) if err != nil { return nil, err From b13247c333339bcd8bf963e62df2e03f37383984 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Mon, 27 Jul 2020 08:57:57 -0700 Subject: [PATCH 131/159] introduce stale issue bot Signed-off-by: Matthew Fisher --- .github/workflows/stale-issue-bot.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/workflows/stale-issue-bot.yaml diff --git a/.github/workflows/stale-issue-bot.yaml b/.github/workflows/stale-issue-bot.yaml new file mode 100644 index 000000000..e21e6d5ca --- /dev/null +++ b/.github/workflows/stale-issue-bot.yaml @@ -0,0 +1,15 @@ +name: "Close stale issues" +on: + schedule: + - cron: "0 0 * * *" +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v3 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: 'This issue has been marked as stale because it has been open for 90 days with no activity. This thread will be automatically closed in 30 days if no further activity occurs.' + exempt-issue-labels: 'keep open' + days-before-stale: 90 + days-before-close: 30 From 44212f83dc9c893d962fe48648320e7b7b66950c Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Tue, 28 Jul 2020 09:52:39 -0400 Subject: [PATCH 132/159] Fix issue with install and upgrade running all hooks When #8156 was merged it had the side effect that all hooks were run all the time. All the hooks were put in the flow of the content rendered and sent to Kubernetes on every command. For example, if you ran the following 2 commands the test hooks would run: helm create foo helm install foo ./foo This should not run any hooks. But, the generated test hook is run. The change in this commit moves the writing of the hooks to output or disk back into the template command rather than in a private function within the actions. This is where it was for v3.2. One side effect is that post renderers will not work on hooks. This was the case in v3.2. Since this bug is blocking the release of v3.3.0 it is being rolled back. A refactor effort is underway for this section of code. post renderer for hooks should be added back as part of that work. Since post renderer hooks did not make it into a release it is ok to roll it back for now. There is code in the cmd/helm package that has been duplicated from pkg/action. This is a temporary measure to fix the immediate bug with plans to correct the situation as part of a refactor of renderResources. Signed-off-by: Matt Farina --- cmd/helm/template.go | 68 ++++++++++++++++++++++++++++++++++++++ pkg/action/action.go | 22 ++---------- pkg/action/install.go | 2 +- pkg/action/install_test.go | 6 ---- pkg/action/upgrade.go | 2 +- 5 files changed, 73 insertions(+), 27 deletions(-) diff --git a/cmd/helm/template.go b/cmd/helm/template.go index 5a8a25102..6123d29d4 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -20,6 +20,8 @@ import ( "bytes" "fmt" "io" + "os" + "path" "path/filepath" "regexp" "sort" @@ -79,6 +81,25 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { if rel != nil { var manifests bytes.Buffer fmt.Fprintln(&manifests, strings.TrimSpace(rel.Manifest)) + if !client.DisableHooks { + fileWritten := make(map[string]bool) + for _, m := range rel.Hooks { + if client.OutputDir == "" { + fmt.Fprintf(&manifests, "---\n# Source: %s\n%s\n", m.Path, m.Manifest) + } else { + newDir := client.OutputDir + if client.UseReleaseName { + newDir = filepath.Join(client.OutputDir, client.ReleaseName) + } + err = writeToFile(newDir, m.Path, m.Manifest, fileWritten[m.Path]) + if err != nil { + return err + } + fileWritten[m.Path] = true + } + + } + } // if we have a list of files to render, then check that each of the // provided files exists in the chart. @@ -149,3 +170,50 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { return cmd } + +// The following functions (writeToFile, createOrOpenFile, and ensureDirectoryForFile) +// are coppied from the actions package. This is part of a change to correct a +// bug introduced by #8156. As part of the todo to refactor renderResources +// this duplicate code should be removed. It is added here so that the API +// surface area is as minimally impacted as possible in fixing the issue. +func writeToFile(outputDir string, name string, data string, append bool) error { + outfileName := strings.Join([]string{outputDir, name}, string(filepath.Separator)) + + err := ensureDirectoryForFile(outfileName) + if err != nil { + return err + } + + f, err := createOrOpenFile(outfileName, append) + if err != nil { + return err + } + + defer f.Close() + + _, err = f.WriteString(fmt.Sprintf("---\n# Source: %s\n%s\n", name, data)) + + if err != nil { + return err + } + + fmt.Printf("wrote %s\n", outfileName) + return nil +} + +func createOrOpenFile(filename string, append bool) (*os.File, error) { + if append { + return os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0600) + } + return os.Create(filename) +} + +func ensureDirectoryForFile(file string) error { + baseDir := path.Dir(file) + _, err := os.Stat(baseDir) + if err != nil && !os.IsNotExist(err) { + return err + } + + return os.MkdirAll(baseDir, 0755) +} diff --git a/pkg/action/action.go b/pkg/action/action.go index fec86cd42..3c47cc6df 100644 --- a/pkg/action/action.go +++ b/pkg/action/action.go @@ -99,7 +99,9 @@ type Configuration struct { // renderResources renders the templates in a chart // // TODO: This function is badly in need of a refactor. -func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values, releaseName, outputDir string, subNotes, useReleaseName, includeCrds bool, disableHooks bool, pr postrender.PostRenderer, dryRun bool) ([]*release.Hook, *bytes.Buffer, string, error) { +// TODO: As part of the refactor the duplicate code in cmd/helm/template.go should be removed +// This code has to do with writing files to dick. +func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values, releaseName, outputDir string, subNotes, useReleaseName, includeCrds bool, pr postrender.PostRenderer, dryRun bool) ([]*release.Hook, *bytes.Buffer, string, error) { hs := []*release.Hook{} b := bytes.NewBuffer(nil) @@ -212,24 +214,6 @@ func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values } } - if !disableHooks && len(hs) > 0 { - for _, h := range hs { - if outputDir == "" { - fmt.Fprintf(b, "---\n# Source: %s\n%s\n", h.Path, h.Manifest) - } else { - newDir := outputDir - if useReleaseName { - newDir = filepath.Join(outputDir, releaseName) - } - err = writeToFile(newDir, h.Path, h.Manifest, fileWritten[h.Path]) - if err != nil { - return hs, b, "", err - } - fileWritten[h.Path] = true - } - } - } - if pr != nil { b, err = pr.Run(b) if err != nil { diff --git a/pkg/action/install.go b/pkg/action/install.go index 48a3aeeca..00fb208b0 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -236,7 +236,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. rel := i.createRelease(chrt, vals) var manifestDoc *bytes.Buffer - rel.Hooks, manifestDoc, rel.Info.Notes, err = i.cfg.renderResources(chrt, valuesToRender, i.ReleaseName, i.OutputDir, i.SubNotes, i.UseReleaseName, i.IncludeCRDs, i.DisableHooks, i.PostRenderer, i.DryRun) + rel.Hooks, manifestDoc, rel.Info.Notes, err = i.cfg.renderResources(chrt, valuesToRender, i.ReleaseName, i.OutputDir, i.SubNotes, i.UseReleaseName, i.IncludeCRDs, i.PostRenderer, i.DryRun) // Even for errors, attach this if available if manifestDoc != nil { rel.Manifest = manifestDoc.String() diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 4366889ce..6c4012cfd 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -499,9 +499,6 @@ func TestInstallReleaseOutputDir(t *testing.T) { _, err = os.Stat(filepath.Join(dir, "hello/templates/with-partials")) is.NoError(err) - _, err = os.Stat(filepath.Join(dir, "hello/templates/hooks")) - is.NoError(err) - _, err = os.Stat(filepath.Join(dir, "hello/templates/rbac")) is.NoError(err) @@ -542,9 +539,6 @@ func TestInstallOutputDirWithReleaseName(t *testing.T) { _, err = os.Stat(filepath.Join(newDir, "hello/templates/with-partials")) is.NoError(err) - _, err = os.Stat(filepath.Join(newDir, "hello/templates/hooks")) - is.NoError(err) - _, err = os.Stat(filepath.Join(newDir, "hello/templates/rbac")) is.NoError(err) diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index 949aebcae..e7c2aec25 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -222,7 +222,7 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chart.Chart, vals map[strin return nil, nil, err } - hooks, manifestDoc, notesTxt, err := u.cfg.renderResources(chart, valuesToRender, "", "", u.SubNotes, false, false, false, u.PostRenderer, u.DryRun) + hooks, manifestDoc, notesTxt, err := u.cfg.renderResources(chart, valuesToRender, "", "", u.SubNotes, false, false, u.PostRenderer, u.DryRun) if err != nil { return nil, nil, err } From 8bb0413552ca5b2de39d9cb2ec06089c6569908c Mon Sep 17 00:00:00 2001 From: Ma Xinjian Date: Fri, 31 Jul 2020 14:15:21 +0800 Subject: [PATCH 133/159] darwin-386 and windows-386 are not supported now $ curl https://get.helm.sh/helm-v3.2.4-windows-386.tar.gz BlobNotFoundThe specified does not exist. RequestId:6d53f961-d01e-0032-025f-5e4d79000000 $ curl https://get.helm.sh/helm-v2.16.9-darwin-386.tar.gz BlobNotFoundThe specified does not exist. RequestId:81020fad-c01e-0001-0e60-5e12d2000000 Signed-off-by: Ma Xinjian --- scripts/get | 2 +- scripts/get-helm-3 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/get b/scripts/get index 094892346..777a53bbc 100755 --- a/scripts/get +++ b/scripts/get @@ -62,7 +62,7 @@ runAsRoot() { # verifySupported checks that the os/arch combination is supported for # binary builds. verifySupported() { - local supported="darwin-386\ndarwin-amd64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-ppc64le\nwindows-386\nwindows-amd64" + local supported="darwin-amd64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-ppc64le\nwindows-amd64" if ! echo "${supported}" | grep -q "${OS}-${ARCH}"; then echo "No prebuilt binary for ${OS}-${ARCH}." echo "To build from source, go to https://github.com/helm/helm" diff --git a/scripts/get-helm-3 b/scripts/get-helm-3 index ce9411edc..f2495e444 100755 --- a/scripts/get-helm-3 +++ b/scripts/get-helm-3 @@ -60,7 +60,7 @@ runAsRoot() { # verifySupported checks that the os/arch combination is supported for # binary builds. verifySupported() { - local supported="darwin-386\ndarwin-amd64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-ppc64le\nlinux-s390x\nwindows-386\nwindows-amd64" + local supported="darwin-amd64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-ppc64le\nlinux-s390x\nwindows-amd64" if ! echo "${supported}" | grep -q "${OS}-${ARCH}"; then echo "No prebuilt binary for ${OS}-${ARCH}." echo "To build from source, go to https://github.com/helm/helm" From 4cc19d1d82c4f4ee4bb9af5739e1184f5800f588 Mon Sep 17 00:00:00 2001 From: Martin Hickey Date: Fri, 31 Jul 2020 07:57:17 +0000 Subject: [PATCH 134/159] Fix typo Signed-off-by: Martin Hickey --- pkg/action/action.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/action/action.go b/pkg/action/action.go index 3c47cc6df..071db709b 100644 --- a/pkg/action/action.go +++ b/pkg/action/action.go @@ -100,7 +100,7 @@ type Configuration struct { // // TODO: This function is badly in need of a refactor. // TODO: As part of the refactor the duplicate code in cmd/helm/template.go should be removed -// This code has to do with writing files to dick. +// This code has to do with writing files to disk. func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values, releaseName, outputDir string, subNotes, useReleaseName, includeCrds bool, pr postrender.PostRenderer, dryRun bool) ([]*release.Hook, *bytes.Buffer, string, error) { hs := []*release.Hook{} b := bytes.NewBuffer(nil) From fbc32aea3d43853f94768e4bc7bc4045fe9fb749 Mon Sep 17 00:00:00 2001 From: bellkeyang Date: Fri, 31 Jul 2020 20:39:38 +0800 Subject: [PATCH 135/159] bufix: fix validateNumColons docs Signed-off-by: bellkeyang --- internal/experimental/registry/reference.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/experimental/registry/reference.go b/internal/experimental/registry/reference.go index ebab29a7e..f0e91d4ba 100644 --- a/internal/experimental/registry/reference.go +++ b/internal/experimental/registry/reference.go @@ -105,7 +105,7 @@ func (ref *Reference) validateRepo() error { return err } -// validateNumColon ensures the ref only contains a single colon character (:) +// validateNumColons ensures the ref only contains a single colon character (:) // (or potentially two, there might be a port number specified i.e. :5000) func (ref *Reference) validateNumColons() error { if strings.Contains(ref.Tag, ":") { From 131510aa94faaa66ea4b3c3b7e4156206902ffc5 Mon Sep 17 00:00:00 2001 From: Matt Butcher Date: Fri, 31 Jul 2020 17:17:54 -0600 Subject: [PATCH 136/159] fix test that modifies the wrong cache data Signed-off-by: Matt Butcher --- cmd/helm/repo_add_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/helm/repo_add_test.go b/cmd/helm/repo_add_test.go index d1b9bc0fc..7cb669a1a 100644 --- a/cmd/helm/repo_add_test.go +++ b/cmd/helm/repo_add_test.go @@ -40,11 +40,12 @@ func TestRepoAddCmd(t *testing.T) { } defer srv.Stop() - repoFile := filepath.Join(ensure.TempDir(t), "repositories.yaml") + tmpdir := ensure.TempDir(t) + repoFile := filepath.Join(tmpdir, "repositories.yaml") tests := []cmdTestCase{{ name: "add a repository", - cmd: fmt.Sprintf("repo add test-name %s --repository-config %s", srv.URL(), repoFile), + cmd: fmt.Sprintf("repo add test-name %s --repository-config %s --repository-cache %s", srv.URL(), repoFile, tmpdir), golden: "output/repo-add.txt", }} From edc7d8ea320c4f32fa86a4278c175b96a8da9f2a Mon Sep 17 00:00:00 2001 From: Dmitry Chepurovskiy Date: Wed, 29 Jul 2020 20:30:11 +0300 Subject: [PATCH 137/159] Added selector option to list command Signed-off-by: Dmitry Chepurovskiy --- cmd/helm/list.go | 1 + pkg/action/list.go | 1 + 2 files changed, 2 insertions(+) diff --git a/cmd/helm/list.go b/cmd/helm/list.go index 18e5ffe45..dfa17d9bc 100644 --- a/cmd/helm/list.go +++ b/cmd/helm/list.go @@ -126,6 +126,7 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.IntVarP(&client.Limit, "max", "m", 256, "maximum number of releases to fetch") f.IntVar(&client.Offset, "offset", 0, "next release name in the list, used to offset from start value") f.StringVarP(&client.Filter, "filter", "f", "", "a regular expression (Perl compatible). Any releases that match the expression will be included in the results") + f.StringVarP(&client.Selector, "selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)") bindOutputFlag(cmd, &outfmt) return cmd diff --git a/pkg/action/list.go b/pkg/action/list.go index 0f85de519..854a8942b 100644 --- a/pkg/action/list.go +++ b/pkg/action/list.go @@ -126,6 +126,7 @@ type List struct { Deployed bool Failed bool Pending bool + Selector string } // NewList constructs a new *List From 99bd709530bbcbee4fc21822164ad44aa1770b24 Mon Sep 17 00:00:00 2001 From: Dmitry Chepurovskiy Date: Wed, 29 Jul 2020 22:24:07 +0300 Subject: [PATCH 138/159] Pass labels from secret/configmap to release object Signed-off-by: Dmitry Chepurovskiy --- pkg/release/release.go | 2 ++ pkg/storage/driver/cfgmaps.go | 1 + pkg/storage/driver/secrets.go | 1 + 3 files changed, 4 insertions(+) diff --git a/pkg/release/release.go b/pkg/release/release.go index 8582a86f3..1245d8129 100644 --- a/pkg/release/release.go +++ b/pkg/release/release.go @@ -37,6 +37,8 @@ type Release struct { Version int `json:"version,omitempty"` // Namespace is the kubernetes namespace of the release. Namespace string `json:"namespace,omitempty"` + // Labels of the release + Labels map[string]string `json:"labels,omitempty"` } // SetStatus is a helper for setting the status on a release. diff --git a/pkg/storage/driver/cfgmaps.go b/pkg/storage/driver/cfgmaps.go index 71e635975..05213bbdd 100644 --- a/pkg/storage/driver/cfgmaps.go +++ b/pkg/storage/driver/cfgmaps.go @@ -106,6 +106,7 @@ func (cfgmaps *ConfigMaps) List(filter func(*rspb.Release) bool) ([]*rspb.Releas continue } if filter(rls) { + rls.Labels = item.ObjectMeta.Labels results = append(results, rls) } } diff --git a/pkg/storage/driver/secrets.go b/pkg/storage/driver/secrets.go index 44280f70f..1503bc054 100644 --- a/pkg/storage/driver/secrets.go +++ b/pkg/storage/driver/secrets.go @@ -98,6 +98,7 @@ func (secrets *Secrets) List(filter func(*rspb.Release) bool) ([]*rspb.Release, continue } if filter(rls) { + rls.Labels = item.ObjectMeta.Labels results = append(results, rls) } } From 357a0785bcd09e068c240595f12f14ab29fae066 Mon Sep 17 00:00:00 2001 From: Dmitry Chepurovskiy Date: Wed, 29 Jul 2020 23:30:16 +0300 Subject: [PATCH 139/159] Added selector filtering Signed-off-by: Dmitry Chepurovskiy --- pkg/action/list.go | 13 +++++++++++++ pkg/storage/driver/cfgmaps.go | 4 +++- pkg/storage/driver/secrets.go | 4 +++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/pkg/action/list.go b/pkg/action/list.go index 854a8942b..9cf7ec138 100644 --- a/pkg/action/list.go +++ b/pkg/action/list.go @@ -20,6 +20,8 @@ import ( "path" "regexp" + "k8s.io/apimachinery/pkg/labels" + "helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/releaseutil" ) @@ -152,11 +154,22 @@ func (l *List) Run() ([]*release.Release, error) { } } + selectorObj, err := labels.Parse(l.Selector) + if err != nil { + return nil, err + } + results, err := l.cfg.Releases.List(func(rel *release.Release) bool { // Skip anything that doesn't match the filter. if filter != nil && !filter.MatchString(rel.Name) { return false } + + // Skip anything that doesn't match the selector + if ! selectorObj.Matches(labels.Set(rel.Labels)) { + return false + } + return true }) diff --git a/pkg/storage/driver/cfgmaps.go b/pkg/storage/driver/cfgmaps.go index 05213bbdd..94c278875 100644 --- a/pkg/storage/driver/cfgmaps.go +++ b/pkg/storage/driver/cfgmaps.go @@ -105,8 +105,10 @@ func (cfgmaps *ConfigMaps) List(filter func(*rspb.Release) bool) ([]*rspb.Releas cfgmaps.Log("list: failed to decode release: %v: %s", item, err) continue } + + rls.Labels = item.ObjectMeta.Labels + if filter(rls) { - rls.Labels = item.ObjectMeta.Labels results = append(results, rls) } } diff --git a/pkg/storage/driver/secrets.go b/pkg/storage/driver/secrets.go index 1503bc054..64dcf8216 100644 --- a/pkg/storage/driver/secrets.go +++ b/pkg/storage/driver/secrets.go @@ -97,8 +97,10 @@ func (secrets *Secrets) List(filter func(*rspb.Release) bool) ([]*rspb.Release, secrets.Log("list: failed to decode release: %v: %s", item, err) continue } + + rls.Labels = item.ObjectMeta.Labels + if filter(rls) { - rls.Labels = item.ObjectMeta.Labels results = append(results, rls) } } From 09172b468a7c8278c566880c26efd1078e43e5c8 Mon Sep 17 00:00:00 2001 From: Dmitry Chepurovskiy Date: Wed, 29 Jul 2020 23:42:43 +0300 Subject: [PATCH 140/159] Fix linting issues Signed-off-by: Dmitry Chepurovskiy --- pkg/action/list.go | 4 ++-- pkg/storage/driver/secrets.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/action/list.go b/pkg/action/list.go index 9cf7ec138..56008c6fa 100644 --- a/pkg/action/list.go +++ b/pkg/action/list.go @@ -166,10 +166,10 @@ func (l *List) Run() ([]*release.Release, error) { } // Skip anything that doesn't match the selector - if ! selectorObj.Matches(labels.Set(rel.Labels)) { + if !selectorObj.Matches(labels.Set(rel.Labels)) { return false } - + return true }) diff --git a/pkg/storage/driver/secrets.go b/pkg/storage/driver/secrets.go index 64dcf8216..2e8530d0c 100644 --- a/pkg/storage/driver/secrets.go +++ b/pkg/storage/driver/secrets.go @@ -97,7 +97,7 @@ func (secrets *Secrets) List(filter func(*rspb.Release) bool) ([]*rspb.Release, secrets.Log("list: failed to decode release: %v: %s", item, err) continue } - + rls.Labels = item.ObjectMeta.Labels if filter(rls) { From 6d60d26913ef81180eb6cfc13cdc2106e3ae24ef Mon Sep 17 00:00:00 2001 From: Dmitry Chepurovskiy Date: Thu, 30 Jul 2020 20:52:57 +0300 Subject: [PATCH 141/159] Added notice about supported backends Signed-off-by: Dmitry Chepurovskiy --- cmd/helm/list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/list.go b/cmd/helm/list.go index dfa17d9bc..2f40707b3 100644 --- a/cmd/helm/list.go +++ b/cmd/helm/list.go @@ -126,7 +126,7 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.IntVarP(&client.Limit, "max", "m", 256, "maximum number of releases to fetch") f.IntVar(&client.Offset, "offset", 0, "next release name in the list, used to offset from start value") f.StringVarP(&client.Filter, "filter", "f", "", "a regular expression (Perl compatible). Any releases that match the expression will be included in the results") - f.StringVarP(&client.Selector, "selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)") + f.StringVarP(&client.Selector, "selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2). Works only for secret(default) and configmap storage backends.") bindOutputFlag(cmd, &outfmt) return cmd From 2ea8f805b9348201f95d6eacd893cccfdaeb8624 Mon Sep 17 00:00:00 2001 From: Dmitry Chepurovskiy Date: Thu, 30 Jul 2020 22:40:46 +0300 Subject: [PATCH 142/159] Added testing for list action with selector Signed-off-by: Dmitry Chepurovskiy --- pkg/action/list_test.go | 46 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/pkg/action/list_test.go b/pkg/action/list_test.go index b8e2ece68..73009d523 100644 --- a/pkg/action/list_test.go +++ b/pkg/action/list_test.go @@ -320,3 +320,49 @@ func TestFilterLatestReleases(t *testing.T) { assert.ElementsMatch(t, expectedFilteredList, filteredList) }) } + +func TestSelectorList(t *testing.T) { + r1 := releaseStub() + r1.Name = "r1" + r1.Version = 1 + r1.Labels = map[string]string{"key": "value1"} + r2 := releaseStub() + r2.Name = "r2" + r2.Version = 1 + r2.Labels = map[string]string{"key": "value2"} + r3 := releaseStub() + r3.Name = "r3" + r3.Version = 1 + r3.Labels = map[string]string{} + + lister := newListFixture(t) + for _, rel := range []*release.Release{r1, r2, r3} { + if err := lister.cfg.Releases.Create(rel); err != nil { + t.Fatal(err) + } + } + + t.Run("should fail selector parsing", func(t *testing.T) { + is := assert.New(t) + lister.Selector = "a?=b" + + _, err := lister.Run() + is.Error(err) + }) + + t.Run("should select one release with matching label", func(t *testing.T) { + lister.Selector = "key==value1" + res, _ := lister.Run() + + expectedFilteredList := []*release.Release{r1} + assert.ElementsMatch(t, expectedFilteredList, res) + }) + + t.Run("should select two releases with non matching label", func(t *testing.T) { + lister.Selector = "key!=value1" + res, _ := lister.Run() + + expectedFilteredList := []*release.Release{r2, r3} + assert.ElementsMatch(t, expectedFilteredList, res) + }) +} From 266c74f390c6dcd08ffbbe942df99d5557632806 Mon Sep 17 00:00:00 2001 From: Dmitry Chepurovskiy Date: Tue, 4 Aug 2020 18:17:56 +0300 Subject: [PATCH 143/159] Move selector filtering after latest release version filtering Signed-off-by: Dmitry Chepurovskiy --- pkg/action/list.go | 29 +++++++++++++++++++---------- pkg/release/release.go | 5 +++-- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/pkg/action/list.go b/pkg/action/list.go index 56008c6fa..5ba0c4770 100644 --- a/pkg/action/list.go +++ b/pkg/action/list.go @@ -154,22 +154,12 @@ func (l *List) Run() ([]*release.Release, error) { } } - selectorObj, err := labels.Parse(l.Selector) - if err != nil { - return nil, err - } - results, err := l.cfg.Releases.List(func(rel *release.Release) bool { // Skip anything that doesn't match the filter. if filter != nil && !filter.MatchString(rel.Name) { return false } - // Skip anything that doesn't match the selector - if !selectorObj.Matches(labels.Set(rel.Labels)) { - return false - } - return true }) @@ -192,6 +182,13 @@ func (l *List) Run() ([]*release.Release, error) { // latest releases, otherwise outdated entries can be returned results = l.filterStateMask(results) + // Skip anything that doesn't match the selector + selectorObj, err := labels.Parse(l.Selector) + if err != nil { + return nil, err + } + results = l.filterSelector(results, selectorObj) + // Unfortunately, we have to sort before truncating, which can incur substantial overhead l.sort(results) @@ -274,6 +271,18 @@ func (l *List) filterStateMask(releases []*release.Release) []*release.Release { return desiredStateReleases } +func (l *List) filterSelector(releases []*release.Release, selector labels.Selector) []*release.Release { + desiredStateReleases := make([]*release.Release, 0) + + for _, rls := range releases { + if selector.Matches(labels.Set(rls.Labels)) { + desiredStateReleases = append(desiredStateReleases, rls) + } + } + + return desiredStateReleases +} + // SetStateMask calculates the state mask based on parameters. func (l *List) SetStateMask() { if l.All { diff --git a/pkg/release/release.go b/pkg/release/release.go index 1245d8129..b90612873 100644 --- a/pkg/release/release.go +++ b/pkg/release/release.go @@ -37,8 +37,9 @@ type Release struct { Version int `json:"version,omitempty"` // Namespace is the kubernetes namespace of the release. Namespace string `json:"namespace,omitempty"` - // Labels of the release - Labels map[string]string `json:"labels,omitempty"` + // Labels of the release. + // Disabled encoding into Json cause labels are stored in storage driver metadata field. + Labels map[string]string `json:"-"` } // SetStatus is a helper for setting the status on a release. From df4708a9de8a6f4c89dca7555a5b338c8298128d Mon Sep 17 00:00:00 2001 From: Dong Gang Date: Wed, 5 Aug 2020 10:37:00 +0800 Subject: [PATCH 144/159] polish the error handler Signed-off-by: Dong Gang --- pkg/action/show.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/action/show.go b/pkg/action/show.go index 73d989884..4eab2b4fd 100644 --- a/pkg/action/show.go +++ b/pkg/action/show.go @@ -20,6 +20,7 @@ import ( "fmt" "strings" + "github.com/pkg/errors" "k8s.io/cli-runtime/pkg/printers" "sigs.k8s.io/yaml" @@ -92,7 +93,7 @@ func (s *Show) Run(chartpath string) (string, error) { if s.JSONPathTemplate != "" { printer, err := printers.NewJSONPathPrinter(s.JSONPathTemplate) if err != nil { - return "", fmt.Errorf("error parsing jsonpath %s, %v", s.JSONPathTemplate, err) + return "", errors.Wrapf(err, "error parsing jsonpath %s", s.JSONPathTemplate) } printer.Execute(&out, s.chart.Values) } else { From 5421c7e99526af9683491fe5e069ed001fb5fd58 Mon Sep 17 00:00:00 2001 From: Tero <31454692+tero-dev@users.noreply.github.com> Date: Thu, 6 Aug 2020 17:00:14 +0300 Subject: [PATCH 145/159] Fix Quick Start Guide Link in README.md The previous link https://docs.helm.sh/using_helm/#quickstart-guide was redirecting into https://helm.sh/ja/docs/intro/ which is a Japanese version of the docs. I've fixed the link so it goes into the English version instead. Signed-off-by: Tero <31454692+tero-dev@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb6908fdb..9c39175bc 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ If you want to use a package manager: - [GoFish](https://gofi.sh/) users can use `gofish install helm`. - [Snapcraft](https://snapcraft.io/) users can use `snap install helm --classic` -To rapidly get Helm up and running, start with the [Quick Start Guide](https://docs.helm.sh/using_helm/#quickstart-guide). +To rapidly get Helm up and running, start with the [Quick Start Guide](https://helm.sh/docs/intro/quickstart/). See the [installation guide](https://helm.sh/docs/intro/install/) for more options, including installing pre-releases. From 4b1fa60d5883d53b4e4f09d3420b108e66bbd737 Mon Sep 17 00:00:00 2001 From: Thomas O'Donnell Date: Wed, 5 Aug 2020 19:02:42 +0200 Subject: [PATCH 146/159] Update Common Lables template in starter chart Have update the Common Labels template in the starter chart so that the value for the `app.kubernetes.io/version` is set to the same value as the image tag used in the deployment. Signed-off-by: Thomas O'Donnell --- pkg/chartutil/create.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index c036ce37d..cf10f0875 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -424,9 +424,7 @@ Common labels {{- define ".labels" -}} helm.sh/chart: {{ include ".chart" . }} {{ include ".selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} +app.kubernetes.io/version: {{ .Values.image.tag | default .Chart.AppVersion | quote }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end }} From 83a5e620d0acde77502b1f814f749268e8d8ef6e Mon Sep 17 00:00:00 2001 From: Morten Linderud Date: Wed, 12 Aug 2020 23:00:16 +0200 Subject: [PATCH 147/159] release/mock: Ensure conversion from int to string yields a string With the release of go 1.15, the test-suite doesn't pass as `go test` got a new warning for improper `string(x)` usage. https://golang.org/doc/go1.15#vet $ make test-unit # helm.sh/helm/v3/pkg/release pkg/release/mock.go:56:27: conversion from int to string yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?) [snip] make: *** [Makefile:82: test-unit] Error 2 This patch changes ensures we are utilizing `fmt.Sprint` instead as recommended. Signed-off-by: Morten Linderud --- pkg/release/mock.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/release/mock.go b/pkg/release/mock.go index 3abbd574b..a28e1dc16 100644 --- a/pkg/release/mock.go +++ b/pkg/release/mock.go @@ -17,6 +17,7 @@ limitations under the License. package release import ( + "fmt" "math/rand" "helm.sh/helm/v3/pkg/chart" @@ -53,7 +54,7 @@ func Mock(opts *MockReleaseOptions) *Release { name := opts.Name if name == "" { - name = "testrelease-" + string(rand.Intn(100)) + name = "testrelease-" + fmt.Sprint(rand.Intn(100)) } version := 1 From 065b7f6e257f7ee47ca0194f8c3b804e14173514 Mon Sep 17 00:00:00 2001 From: Maartje Eyskens Date: Fri, 14 Aug 2020 09:43:56 +0200 Subject: [PATCH 148/159] Bump Kubernetes to v0.18.8 + Bump jsonpatch jsonpatch now is the same version as used in Kubernetes v0.18.8 Signed-off-by: Maartje Eyskens --- go.mod | 14 +++++++------- go.sum | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 08eae92fa..66447ee3d 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/docker/distribution v2.7.1+incompatible github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce github.com/docker/go-units v0.4.0 - github.com/evanphx/json-patch v4.5.0+incompatible + github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b github.com/gobwas/glob v0.2.3 github.com/gofrs/flock v0.7.1 github.com/gosuri/uitable v0.0.4 @@ -34,13 +34,13 @@ require ( github.com/stretchr/testify v1.6.1 github.com/xeipuuv/gojsonschema v1.2.0 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 - k8s.io/api v0.18.4 - k8s.io/apiextensions-apiserver v0.18.4 - k8s.io/apimachinery v0.18.4 - k8s.io/cli-runtime v0.18.4 - k8s.io/client-go v0.18.4 + k8s.io/api v0.18.8 + k8s.io/apiextensions-apiserver v0.18.8 + k8s.io/apimachinery v0.18.8 + k8s.io/cli-runtime v0.18.8 + k8s.io/client-go v0.18.8 k8s.io/klog v1.0.0 - k8s.io/kubectl v0.18.4 + k8s.io/kubectl v0.18.8 sigs.k8s.io/yaml v1.2.0 ) diff --git a/go.sum b/go.sum index 0d0ef8c83..94f5fee82 100644 --- a/go.sum +++ b/go.sum @@ -195,6 +195,8 @@ github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b h1:vCplRbYcTTeBVLjIU0KvipEeVBSxl6sakUBRmeLBTkw= +github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b/go.mod h1:NAJj0yf/KaRKURN6nyi7A9IZydMivZEm9oQLWNjfKDc= github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= @@ -395,6 +397,7 @@ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -915,18 +918,32 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= k8s.io/api v0.18.4 h1:8x49nBRxuXGUlDlwlWd3RMY1SayZrzFfxea3UZSkFw4= k8s.io/api v0.18.4/go.mod h1:lOIQAKYgai1+vz9J7YcDZwC26Z0zQewYOGWdyIPUUQ4= +k8s.io/api v0.18.8 h1:aIKUzJPb96f3fKec2lxtY7acZC9gQNDLVhfSGpxBAC4= +k8s.io/api v0.18.8/go.mod h1:d/CXqwWv+Z2XEG1LgceeDmHQwpUJhROPx16SlxJgERY= k8s.io/apiextensions-apiserver v0.18.4 h1:Y3HGERmS8t9u12YNUFoOISqefaoGRuTc43AYCLzWmWE= k8s.io/apiextensions-apiserver v0.18.4/go.mod h1:NYeyeYq4SIpFlPxSAB6jHPIdvu3hL0pc36wuRChybio= +k8s.io/apiextensions-apiserver v0.18.8 h1:pkqYPKTHa0/3lYwH7201RpF9eFm0lmZDFBNzhN+k/sA= +k8s.io/apiextensions-apiserver v0.18.8/go.mod h1:7f4ySEkkvifIr4+BRrRWriKKIJjPyg9mb/p63dJKnlM= k8s.io/apimachinery v0.18.4 h1:ST2beySjhqwJoIFk6p7Hp5v5O0hYY6Gngq/gUYXTPIA= k8s.io/apimachinery v0.18.4/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= +k8s.io/apimachinery v0.18.8 h1:jimPrycCqgx2QPearX3to1JePz7wSbVLq+7PdBTTwQ0= +k8s.io/apimachinery v0.18.8/go.mod h1:6sQd+iHEqmOtALqOFjSWp2KZ9F0wlU/nWm0ZgsYWMig= k8s.io/apiserver v0.18.4/go.mod h1:q+zoFct5ABNnYkGIaGQ3bcbUNdmPyOCoEBcg51LChY8= +k8s.io/apiserver v0.18.8/go.mod h1:12u5FuGql8Cc497ORNj79rhPdiXQC4bf53X/skR/1YM= k8s.io/cli-runtime v0.18.4 h1:IUx7quIOb4gbQ4M+B1ksF/PTBovQuL5tXWzplX3t+FM= k8s.io/cli-runtime v0.18.4/go.mod h1:9/hS/Cuf7NVzWR5F/5tyS6xsnclxoPLVtwhnkJG1Y4g= +k8s.io/cli-runtime v0.18.8 h1:ycmbN3hs7CfkJIYxJAOB10iW7BVPmXGXkfEyiV9NJ+k= +k8s.io/cli-runtime v0.18.8/go.mod h1:7EzWiDbS9PFd0hamHHVoCY4GrokSTPSL32MA4rzIu0M= k8s.io/client-go v0.18.4 h1:un55V1Q/B3JO3A76eS0kUSywgGK/WR3BQ8fHQjNa6Zc= k8s.io/client-go v0.18.4/go.mod h1:f5sXwL4yAZRkAtzOxRWUhA/N8XzGCb+nPZI8PfobZ9g= +k8s.io/client-go v0.18.8 h1:SdbLpIxk5j5YbFr1b7fq8S7mDgDjYmUxSbszyoesoDM= +k8s.io/client-go v0.18.8/go.mod h1:HqFqMllQ5NnQJNwjro9k5zMyfhZlOwpuTLVrxjkYSxU= k8s.io/code-generator v0.18.4/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= +k8s.io/code-generator v0.18.8/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= k8s.io/component-base v0.18.4 h1:Kr53Fp1iCGNsl9Uv4VcRvLy7YyIqi9oaJOQ7SXtKI98= k8s.io/component-base v0.18.4/go.mod h1:7jr/Ef5PGmKwQhyAz/pjByxJbC58mhKAhiaDu0vXfPk= +k8s.io/component-base v0.18.8 h1:BW5CORobxb6q5mb+YvdwQlyXXS6NVH5fDXWbU7tf2L8= +k8s.io/component-base v0.18.8/go.mod h1:00frPRDas29rx58pPCxNkhUfPbwajlyyvu8ruNgSErU= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= @@ -937,8 +954,11 @@ k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOEC k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kubectl v0.18.4 h1:l9DUYPTEMs1+qNtoqPpTyaJOosvj7l7tQqphCO1K52s= k8s.io/kubectl v0.18.4/go.mod h1:EzB+nfeUWk6fm6giXQ8P4Fayw3dsN+M7Wjy23mTRtB0= +k8s.io/kubectl v0.18.8 h1:qTkHCz21YmK0+S0oE6TtjtxmjeDP42gJcZJyRKsIenA= +k8s.io/kubectl v0.18.8/go.mod h1:PlEgIAjOMua4hDFTEkVf+W5M0asHUKfE4y7VDZkpLHM= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/metrics v0.18.4/go.mod h1:luze4fyI9JG4eLDZy0kFdYEebqNfi0QrG4xNEbPkHOs= +k8s.io/metrics v0.18.8/go.mod h1:j7JzZdiyhLP2BsJm/Fzjs+j5Lb1Y7TySjhPWqBPwRXA= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= From d6708667da5c79ab4a093ea7473e96b93be5f1f7 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Sat, 8 Aug 2020 03:43:34 -0400 Subject: [PATCH 149/159] feat(comp): Disable file completion when not valid With Cobra 1.0, it is now possible to control when file completion should or should not be done. For example: helm list should not trigger file completion since 'helm list' does not accept any arguments. This commit disables file completion when appropriate and adds tests to verify that file completion is properly disabled. Signed-off-by: Marc Khouzam --- cmd/helm/completion.go | 16 ++++++--- cmd/helm/completion_test.go | 58 ++++++++++++++++++++++++++++++++ cmd/helm/create.go | 9 +++++ cmd/helm/create_test.go | 5 +++ cmd/helm/dependency.go | 11 +++--- cmd/helm/dependency_test.go | 4 +++ cmd/helm/docs.go | 11 +++--- cmd/helm/docs_test.go | 25 ++++++++++++++ cmd/helm/env.go | 9 ++--- cmd/helm/env_test.go | 25 ++++++++++++++ cmd/helm/get.go | 9 ++--- cmd/helm/get_all_test.go | 5 +++ cmd/helm/get_hooks_test.go | 5 +++ cmd/helm/get_manifest_test.go | 5 +++ cmd/helm/get_notes_test.go | 5 +++ cmd/helm/get_test.go | 25 ++++++++++++++ cmd/helm/get_values_test.go | 5 +++ cmd/helm/history_test.go | 5 +++ cmd/helm/install_test.go | 7 ++++ cmd/helm/lint_test.go | 5 +++ cmd/helm/list.go | 11 +++--- cmd/helm/list_test.go | 4 +++ cmd/helm/package_test.go | 5 +++ cmd/helm/plugin.go | 7 ++-- cmd/helm/plugin_install.go | 8 +++++ cmd/helm/plugin_list.go | 7 ++-- cmd/helm/plugin_test.go | 23 +++++++++++++ cmd/helm/pull_test.go | 5 +++ cmd/helm/release_testing_test.go | 26 ++++++++++++++ cmd/helm/repo.go | 9 ++--- cmd/helm/repo_add.go | 7 ++-- cmd/helm/repo_add_test.go | 6 ++++ cmd/helm/repo_index.go | 8 +++++ cmd/helm/repo_index_test.go | 5 +++ cmd/helm/repo_list.go | 9 ++--- cmd/helm/repo_list_test.go | 4 +++ cmd/helm/repo_remove_test.go | 5 +++ cmd/helm/repo_test.go | 25 ++++++++++++++ cmd/helm/repo_update.go | 11 +++--- cmd/helm/repo_update_test.go | 4 +++ cmd/helm/rollback_test.go | 6 ++++ cmd/helm/root.go | 3 ++ cmd/helm/root_test.go | 8 +++++ cmd/helm/search.go | 7 ++-- cmd/helm/search_hub_test.go | 4 +++ cmd/helm/search_repo.go | 5 +++ cmd/helm/search_repo_test.go | 4 +++ cmd/helm/search_test.go | 23 +++++++++++++ cmd/helm/show.go | 11 +++--- cmd/helm/show_test.go | 20 +++++++++++ cmd/helm/status_test.go | 5 +++ cmd/helm/template_test.go | 7 ++++ cmd/helm/uninstall_test.go | 5 +++ cmd/helm/upgrade_test.go | 6 ++++ cmd/helm/verify.go | 8 +++++ cmd/helm/verify_test.go | 5 +++ cmd/helm/version.go | 9 ++--- cmd/helm/version_test.go | 4 +++ 58 files changed, 517 insertions(+), 61 deletions(-) create mode 100644 cmd/helm/completion_test.go create mode 100644 cmd/helm/docs_test.go create mode 100644 cmd/helm/env_test.go create mode 100644 cmd/helm/get_test.go create mode 100644 cmd/helm/release_testing_test.go create mode 100644 cmd/helm/repo_test.go create mode 100644 cmd/helm/search_test.go diff --git a/cmd/helm/completion.go b/cmd/helm/completion.go index 696021363..c7e763c3d 100644 --- a/cmd/helm/completion.go +++ b/cmd/helm/completion.go @@ -54,10 +54,11 @@ $ helm completion zsh > "${fpath[1]}/_helm" func newCompletionCmd(out io.Writer) *cobra.Command { cmd := &cobra.Command{ - Use: "completion", - Short: "generate autocompletions script for the specified shell", - Long: completionDesc, - Args: require.NoArgs, + Use: "completion", + Short: "generate autocompletions script for the specified shell", + Long: completionDesc, + Args: require.NoArgs, + ValidArgsFunction: noCompletions, // Disable file completion } bash := &cobra.Command{ @@ -66,6 +67,7 @@ func newCompletionCmd(out io.Writer) *cobra.Command { Long: bashCompDesc, Args: require.NoArgs, DisableFlagsInUseLine: true, + ValidArgsFunction: noCompletions, RunE: func(cmd *cobra.Command, args []string) error { return runCompletionBash(out, cmd) }, @@ -77,6 +79,7 @@ func newCompletionCmd(out io.Writer) *cobra.Command { Long: zshCompDesc, Args: require.NoArgs, DisableFlagsInUseLine: true, + ValidArgsFunction: noCompletions, RunE: func(cmd *cobra.Command, args []string) error { return runCompletionZsh(out, cmd) }, @@ -253,3 +256,8 @@ __helm_bash_source <(__helm_convert_bash_to_zsh) out.Write([]byte(zshTail)) return nil } + +// Function to disable file completion +func noCompletions(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return nil, cobra.ShellCompDirectiveNoFileComp +} diff --git a/cmd/helm/completion_test.go b/cmd/helm/completion_test.go new file mode 100644 index 000000000..44c74f85a --- /dev/null +++ b/cmd/helm/completion_test.go @@ -0,0 +1,58 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "fmt" + "strings" + "testing" + + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/release" +) + +// Check if file completion should be performed according to parameter 'shouldBePerformed' +func checkFileCompletion(t *testing.T, cmdName string, shouldBePerformed bool) { + storage := storageFixture() + storage.Create(&release.Release{ + Name: "myrelease", + Info: &release.Info{Status: release.StatusDeployed}, + Chart: &chart.Chart{}, + Version: 1, + }) + + testcmd := fmt.Sprintf("__complete %s ''", cmdName) + _, out, err := executeActionCommandC(storage, testcmd) + if err != nil { + t.Errorf("unexpected error, %s", err) + } + if !strings.Contains(out, "ShellCompDirectiveNoFileComp") != shouldBePerformed { + if shouldBePerformed { + t.Error(fmt.Sprintf("Unexpected directive ShellCompDirectiveNoFileComp when completing '%s'", cmdName)) + } else { + + t.Error(fmt.Sprintf("Did not receive directive ShellCompDirectiveNoFileComp when completing '%s'", cmdName)) + } + t.Log(out) + } +} + +func TestCompletionFileCompletion(t *testing.T) { + checkFileCompletion(t, "completion", false) + checkFileCompletion(t, "completion bash", false) + checkFileCompletion(t, "completion zsh", false) +} diff --git a/cmd/helm/create.go b/cmd/helm/create.go index 5bdda05cb..21a7e026c 100644 --- a/cmd/helm/create.go +++ b/cmd/helm/create.go @@ -64,6 +64,15 @@ func newCreateCmd(out io.Writer) *cobra.Command { Short: "create a new chart with the given name", Long: createDesc, Args: require.ExactArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) == 0 { + // Allow file completion when completing the argument for the name + // which could be a path + return nil, cobra.ShellCompDirectiveDefault + } + // No more completions, so disable file completion + return nil, cobra.ShellCompDirectiveNoFileComp + }, RunE: func(cmd *cobra.Command, args []string) error { o.name = args[0] o.starterDir = helmpath.DataPath("starters") diff --git a/cmd/helm/create_test.go b/cmd/helm/create_test.go index bbb8d394a..1db6bed52 100644 --- a/cmd/helm/create_test.go +++ b/cmd/helm/create_test.go @@ -192,3 +192,8 @@ func TestCreateStarterAbsoluteCmd(t *testing.T) { t.Error("Did not find foo.tpl") } } + +func TestCreateFileCompletion(t *testing.T) { + checkFileCompletion(t, "create", true) + checkFileCompletion(t, "create myname", false) +} diff --git a/cmd/helm/dependency.go b/cmd/helm/dependency.go index 2cc4c5045..39dfd98ce 100644 --- a/cmd/helm/dependency.go +++ b/cmd/helm/dependency.go @@ -84,11 +84,12 @@ This will produce an error if the chart cannot be loaded. func newDependencyCmd(out io.Writer) *cobra.Command { cmd := &cobra.Command{ - Use: "dependency update|build|list", - Aliases: []string{"dep", "dependencies"}, - Short: "manage a chart's dependencies", - Long: dependencyDesc, - Args: require.NoArgs, + Use: "dependency update|build|list", + Aliases: []string{"dep", "dependencies"}, + Short: "manage a chart's dependencies", + Long: dependencyDesc, + Args: require.NoArgs, + ValidArgsFunction: noCompletions, // Disable file completion } cmd.AddCommand(newDependencyListCmd(out)) diff --git a/cmd/helm/dependency_test.go b/cmd/helm/dependency_test.go index 80b357a77..34c6a25e1 100644 --- a/cmd/helm/dependency_test.go +++ b/cmd/helm/dependency_test.go @@ -51,3 +51,7 @@ func TestDependencyListCmd(t *testing.T) { }} runTestCmd(t, tests) } + +func TestDependencyFileCompletion(t *testing.T) { + checkFileCompletion(t, "dependency", false) +} diff --git a/cmd/helm/docs.go b/cmd/helm/docs.go index c974d4014..621b17ca1 100644 --- a/cmd/helm/docs.go +++ b/cmd/helm/docs.go @@ -47,11 +47,12 @@ func newDocsCmd(out io.Writer) *cobra.Command { o := &docsOptions{} cmd := &cobra.Command{ - Use: "docs", - Short: "generate documentation as markdown or man pages", - Long: docsDesc, - Hidden: true, - Args: require.NoArgs, + Use: "docs", + Short: "generate documentation as markdown or man pages", + Long: docsDesc, + Hidden: true, + Args: require.NoArgs, + ValidArgsFunction: noCompletions, RunE: func(cmd *cobra.Command, args []string) error { o.topCmd = cmd.Root() return o.run(out) diff --git a/cmd/helm/docs_test.go b/cmd/helm/docs_test.go new file mode 100644 index 000000000..cda299b0a --- /dev/null +++ b/cmd/helm/docs_test.go @@ -0,0 +1,25 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "testing" +) + +func TestDocsFileCompletion(t *testing.T) { + checkFileCompletion(t, "docs", false) +} diff --git a/cmd/helm/env.go b/cmd/helm/env.go index 0fbfb9da4..4db3d80de 100644 --- a/cmd/helm/env.go +++ b/cmd/helm/env.go @@ -32,10 +32,11 @@ Env prints out all the environment information in use by Helm. func newEnvCmd(out io.Writer) *cobra.Command { cmd := &cobra.Command{ - Use: "env", - Short: "helm client environment information", - Long: envHelp, - Args: require.NoArgs, + Use: "env", + Short: "helm client environment information", + Long: envHelp, + Args: require.NoArgs, + ValidArgsFunction: noCompletions, Run: func(cmd *cobra.Command, args []string) { envVars := settings.EnvVars() diff --git a/cmd/helm/env_test.go b/cmd/helm/env_test.go new file mode 100644 index 000000000..a7170a8cc --- /dev/null +++ b/cmd/helm/env_test.go @@ -0,0 +1,25 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "testing" +) + +func TestEnvFileCompletion(t *testing.T) { + checkFileCompletion(t, "env", false) +} diff --git a/cmd/helm/get.go b/cmd/helm/get.go index 7c4854b59..e94871c7b 100644 --- a/cmd/helm/get.go +++ b/cmd/helm/get.go @@ -37,10 +37,11 @@ get extended information about the release, including: func newGetCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { cmd := &cobra.Command{ - Use: "get", - Short: "download extended information of a named release", - Long: getHelp, - Args: require.NoArgs, + Use: "get", + Short: "download extended information of a named release", + Long: getHelp, + Args: require.NoArgs, + ValidArgsFunction: noCompletions, // Disable file completion } cmd.AddCommand(newGetAllCmd(cfg, out)) diff --git a/cmd/helm/get_all_test.go b/cmd/helm/get_all_test.go index a213ac583..0c140faf8 100644 --- a/cmd/helm/get_all_test.go +++ b/cmd/helm/get_all_test.go @@ -45,3 +45,8 @@ func TestGetCmd(t *testing.T) { func TestGetAllRevisionCompletion(t *testing.T) { revisionFlagCompletionTest(t, "get all") } + +func TestGetAllFileCompletion(t *testing.T) { + checkFileCompletion(t, "get all", false) + checkFileCompletion(t, "get all myrelease", false) +} diff --git a/cmd/helm/get_hooks_test.go b/cmd/helm/get_hooks_test.go index 7b9142d12..6c010d1bd 100644 --- a/cmd/helm/get_hooks_test.go +++ b/cmd/helm/get_hooks_test.go @@ -40,3 +40,8 @@ func TestGetHooks(t *testing.T) { func TestGetHooksRevisionCompletion(t *testing.T) { revisionFlagCompletionTest(t, "get hooks") } + +func TestGetHooksFileCompletion(t *testing.T) { + checkFileCompletion(t, "get hooks", false) + checkFileCompletion(t, "get hooks myrelease", false) +} diff --git a/cmd/helm/get_manifest_test.go b/cmd/helm/get_manifest_test.go index bd0ffc5d6..f3f572e80 100644 --- a/cmd/helm/get_manifest_test.go +++ b/cmd/helm/get_manifest_test.go @@ -40,3 +40,8 @@ func TestGetManifest(t *testing.T) { func TestGetManifestRevisionCompletion(t *testing.T) { revisionFlagCompletionTest(t, "get manifest") } + +func TestGetManifestFileCompletion(t *testing.T) { + checkFileCompletion(t, "get manifest", false) + checkFileCompletion(t, "get manifest myrelease", false) +} diff --git a/cmd/helm/get_notes_test.go b/cmd/helm/get_notes_test.go index a59120b77..7d43c87e7 100644 --- a/cmd/helm/get_notes_test.go +++ b/cmd/helm/get_notes_test.go @@ -40,3 +40,8 @@ func TestGetNotesCmd(t *testing.T) { func TestGetNotesRevisionCompletion(t *testing.T) { revisionFlagCompletionTest(t, "get notes") } + +func TestGetNotesFileCompletion(t *testing.T) { + checkFileCompletion(t, "get notes", false) + checkFileCompletion(t, "get notes myrelease", false) +} diff --git a/cmd/helm/get_test.go b/cmd/helm/get_test.go new file mode 100644 index 000000000..79f914bea --- /dev/null +++ b/cmd/helm/get_test.go @@ -0,0 +1,25 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "testing" +) + +func TestGetFileCompletion(t *testing.T) { + checkFileCompletion(t, "get", false) +} diff --git a/cmd/helm/get_values_test.go b/cmd/helm/get_values_test.go index ecd92d354..2a71b1e4d 100644 --- a/cmd/helm/get_values_test.go +++ b/cmd/helm/get_values_test.go @@ -60,3 +60,8 @@ func TestGetValuesRevisionCompletion(t *testing.T) { func TestGetValuesOutputCompletion(t *testing.T) { outputFlagCompletionTest(t, "get values") } + +func TestGetValuesFileCompletion(t *testing.T) { + checkFileCompletion(t, "get values", false) + checkFileCompletion(t, "get values myrelease", false) +} diff --git a/cmd/helm/history_test.go b/cmd/helm/history_test.go index c9bfb648e..fffd983da 100644 --- a/cmd/helm/history_test.go +++ b/cmd/helm/history_test.go @@ -108,3 +108,8 @@ func revisionFlagCompletionTest(t *testing.T, cmdName string) { }} runTestCmd(t, tests) } + +func TestHistoryFileCompletion(t *testing.T) { + checkFileCompletion(t, "history", false) + checkFileCompletion(t, "history myrelease", false) +} diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go index 36de648f9..6892fcd86 100644 --- a/cmd/helm/install_test.go +++ b/cmd/helm/install_test.go @@ -239,3 +239,10 @@ func TestInstallVersionCompletion(t *testing.T) { }} runTestCmd(t, tests) } + +func TestInstallFileCompletion(t *testing.T) { + checkFileCompletion(t, "install", false) + checkFileCompletion(t, "install --generate-name", true) + checkFileCompletion(t, "install myname", true) + checkFileCompletion(t, "install myname mychart", false) +} diff --git a/cmd/helm/lint_test.go b/cmd/helm/lint_test.go index 9079935d4..3501ccf87 100644 --- a/cmd/helm/lint_test.go +++ b/cmd/helm/lint_test.go @@ -36,3 +36,8 @@ func TestLintCmdWithSubchartsFlag(t *testing.T) { }} runTestCmd(t, tests) } + +func TestLintFileCompletion(t *testing.T) { + checkFileCompletion(t, "lint", true) + checkFileCompletion(t, "lint mypath", true) // Multiple paths can be given +} diff --git a/cmd/helm/list.go b/cmd/helm/list.go index 2f40707b3..08a26be04 100644 --- a/cmd/helm/list.go +++ b/cmd/helm/list.go @@ -63,11 +63,12 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { var outfmt output.Format cmd := &cobra.Command{ - Use: "list", - Short: "list releases", - Long: listHelp, - Aliases: []string{"ls"}, - Args: require.NoArgs, + Use: "list", + Short: "list releases", + Long: listHelp, + Aliases: []string{"ls"}, + Args: require.NoArgs, + ValidArgsFunction: noCompletions, RunE: func(cmd *cobra.Command, args []string) error { if client.AllNamespaces { if err := cfg.Init(settings.RESTClientGetter(), "", os.Getenv("HELM_DRIVER"), debug); err != nil { diff --git a/cmd/helm/list_test.go b/cmd/helm/list_test.go index dadb57b94..b3b29356e 100644 --- a/cmd/helm/list_test.go +++ b/cmd/helm/list_test.go @@ -235,3 +235,7 @@ func TestListCmd(t *testing.T) { func TestListOutputCompletion(t *testing.T) { outputFlagCompletionTest(t, "list") } + +func TestListFileCompletion(t *testing.T) { + checkFileCompletion(t, "list", false) +} diff --git a/cmd/helm/package_test.go b/cmd/helm/package_test.go index e0a5fabd6..ecb3ee36c 100644 --- a/cmd/helm/package_test.go +++ b/cmd/helm/package_test.go @@ -202,3 +202,8 @@ func setFlags(cmd *cobra.Command, flags map[string]string) { dest.Set(f, v) } } + +func TestPackageFileCompletion(t *testing.T) { + checkFileCompletion(t, "package", true) + checkFileCompletion(t, "package mypath", true) // Multiple paths can be given +} diff --git a/cmd/helm/plugin.go b/cmd/helm/plugin.go index 8e1044f54..a118a03eb 100644 --- a/cmd/helm/plugin.go +++ b/cmd/helm/plugin.go @@ -32,9 +32,10 @@ Manage client-side Helm plugins. func newPluginCmd(out io.Writer) *cobra.Command { cmd := &cobra.Command{ - Use: "plugin", - Short: "install, list, or uninstall Helm plugins", - Long: pluginHelp, + Use: "plugin", + Short: "install, list, or uninstall Helm plugins", + Long: pluginHelp, + ValidArgsFunction: noCompletions, // Disable file completion } cmd.AddCommand( newPluginInstallCmd(out), diff --git a/cmd/helm/plugin_install.go b/cmd/helm/plugin_install.go index 8deb1f4f9..183d3dc57 100644 --- a/cmd/helm/plugin_install.go +++ b/cmd/helm/plugin_install.go @@ -43,6 +43,14 @@ func newPluginInstallCmd(out io.Writer) *cobra.Command { Long: pluginInstallDesc, Aliases: []string{"add"}, Args: require.ExactArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) == 0 { + // We do file completion, in case the plugin is local + return nil, cobra.ShellCompDirectiveDefault + } + // No more completion once the plugin path has been specified + return nil, cobra.ShellCompDirectiveNoFileComp + }, PreRunE: func(cmd *cobra.Command, args []string) error { return o.complete(args) }, diff --git a/cmd/helm/plugin_list.go b/cmd/helm/plugin_list.go index 49a454963..6503161e8 100644 --- a/cmd/helm/plugin_list.go +++ b/cmd/helm/plugin_list.go @@ -28,9 +28,10 @@ import ( func newPluginListCmd(out io.Writer) *cobra.Command { cmd := &cobra.Command{ - Use: "list", - Aliases: []string{"ls"}, - Short: "list installed Helm plugins", + Use: "list", + Aliases: []string{"ls"}, + Short: "list installed Helm plugins", + ValidArgsFunction: noCompletions, RunE: func(cmd *cobra.Command, args []string) error { debug("pluginDirs: %s", settings.PluginsDirectory) plugins, err := plugin.FindPlugins(settings.PluginsDirectory) diff --git a/cmd/helm/plugin_test.go b/cmd/helm/plugin_test.go index e43f277a5..cf21d8460 100644 --- a/cmd/helm/plugin_test.go +++ b/cmd/helm/plugin_test.go @@ -298,3 +298,26 @@ func TestLoadPlugins_HelmNoPlugins(t *testing.T) { t.Fatalf("Expected 0 plugins, got %d", len(plugins)) } } + +func TestPluginFileCompletion(t *testing.T) { + checkFileCompletion(t, "plugin", false) +} + +func TestPluginInstallFileCompletion(t *testing.T) { + checkFileCompletion(t, "plugin install", true) + checkFileCompletion(t, "plugin install mypath", false) +} + +func TestPluginListFileCompletion(t *testing.T) { + checkFileCompletion(t, "plugin list", false) +} + +func TestPluginUninstallFileCompletion(t *testing.T) { + checkFileCompletion(t, "plugin uninstall", false) + checkFileCompletion(t, "plugin uninstall myplugin", false) +} + +func TestPluginUpdateFileCompletion(t *testing.T) { + checkFileCompletion(t, "plugin update", false) + checkFileCompletion(t, "plugin update myplugin", false) +} diff --git a/cmd/helm/pull_test.go b/cmd/helm/pull_test.go index 435df51f1..3f769a1bc 100644 --- a/cmd/helm/pull_test.go +++ b/cmd/helm/pull_test.go @@ -221,3 +221,8 @@ func TestPullVersionCompletion(t *testing.T) { }} runTestCmd(t, tests) } + +func TestPullFileCompletion(t *testing.T) { + checkFileCompletion(t, "pull", false) + checkFileCompletion(t, "pull repo/chart", false) +} diff --git a/cmd/helm/release_testing_test.go b/cmd/helm/release_testing_test.go new file mode 100644 index 000000000..257e95721 --- /dev/null +++ b/cmd/helm/release_testing_test.go @@ -0,0 +1,26 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "testing" +) + +func TestReleaseTestingFileCompletion(t *testing.T) { + checkFileCompletion(t, "test", false) + checkFileCompletion(t, "test myrelease", false) +} diff --git a/cmd/helm/repo.go b/cmd/helm/repo.go index ad6ceaa8f..5aac38819 100644 --- a/cmd/helm/repo.go +++ b/cmd/helm/repo.go @@ -34,10 +34,11 @@ It can be used to add, remove, list, and index chart repositories. func newRepoCmd(out io.Writer) *cobra.Command { cmd := &cobra.Command{ - Use: "repo add|remove|list|index|update [ARGS]", - Short: "add, list, remove, update, and index chart repositories", - Long: repoHelm, - Args: require.NoArgs, + Use: "repo add|remove|list|index|update [ARGS]", + Short: "add, list, remove, update, and index chart repositories", + Long: repoHelm, + Args: require.NoArgs, + ValidArgsFunction: noCompletions, // Disable file completion } cmd.AddCommand(newRepoAddCmd(out)) diff --git a/cmd/helm/repo_add.go b/cmd/helm/repo_add.go index 418a549c6..3eeb342f5 100644 --- a/cmd/helm/repo_add.go +++ b/cmd/helm/repo_add.go @@ -57,9 +57,10 @@ func newRepoAddCmd(out io.Writer) *cobra.Command { o := &repoAddOptions{} cmd := &cobra.Command{ - Use: "add [NAME] [URL]", - Short: "add a chart repository", - Args: require.ExactArgs(2), + Use: "add [NAME] [URL]", + Short: "add a chart repository", + Args: require.ExactArgs(2), + ValidArgsFunction: noCompletions, RunE: func(cmd *cobra.Command, args []string) error { o.name = args[0] o.url = args[1] diff --git a/cmd/helm/repo_add_test.go b/cmd/helm/repo_add_test.go index 7cb669a1a..9ef64390b 100644 --- a/cmd/helm/repo_add_test.go +++ b/cmd/helm/repo_add_test.go @@ -160,3 +160,9 @@ func repoAddConcurrent(t *testing.T, testName, repoFile string) { } } } + +func TestRepoAddFileCompletion(t *testing.T) { + checkFileCompletion(t, "repo add", false) + checkFileCompletion(t, "repo add reponame", false) + checkFileCompletion(t, "repo add reponame https://example.com", false) +} diff --git a/cmd/helm/repo_index.go b/cmd/helm/repo_index.go index 63afaf37b..917acd442 100644 --- a/cmd/helm/repo_index.go +++ b/cmd/helm/repo_index.go @@ -53,6 +53,14 @@ func newRepoIndexCmd(out io.Writer) *cobra.Command { Short: "generate an index file given a directory containing packaged charts", Long: repoIndexDesc, Args: require.ExactArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) == 0 { + // Allow file completion when completing the argument for the directory + return nil, cobra.ShellCompDirectiveDefault + } + // No more completions, so disable file completion + return nil, cobra.ShellCompDirectiveNoFileComp + }, RunE: func(cmd *cobra.Command, args []string) error { o.dir = args[0] return o.run(out) diff --git a/cmd/helm/repo_index_test.go b/cmd/helm/repo_index_test.go index e04ae1b59..ae3390154 100644 --- a/cmd/helm/repo_index_test.go +++ b/cmd/helm/repo_index_test.go @@ -165,3 +165,8 @@ func copyFile(dst, src string) error { return err } + +func TestRepoIndexFileCompletion(t *testing.T) { + checkFileCompletion(t, "repo index", true) + checkFileCompletion(t, "repo index mydir", false) +} diff --git a/cmd/helm/repo_list.go b/cmd/helm/repo_list.go index ed1c9573c..fc53ba75a 100644 --- a/cmd/helm/repo_list.go +++ b/cmd/helm/repo_list.go @@ -32,10 +32,11 @@ import ( func newRepoListCmd(out io.Writer) *cobra.Command { var outfmt output.Format cmd := &cobra.Command{ - Use: "list", - Aliases: []string{"ls"}, - Short: "list chart repositories", - Args: require.NoArgs, + Use: "list", + Aliases: []string{"ls"}, + Short: "list chart repositories", + Args: require.NoArgs, + ValidArgsFunction: noCompletions, RunE: func(cmd *cobra.Command, args []string) error { f, err := repo.LoadFile(settings.RepositoryConfig) if isNotExist(err) || (len(f.Repositories) == 0 && !(outfmt == output.JSON || outfmt == output.YAML)) { diff --git a/cmd/helm/repo_list_test.go b/cmd/helm/repo_list_test.go index f371452f2..90149ebda 100644 --- a/cmd/helm/repo_list_test.go +++ b/cmd/helm/repo_list_test.go @@ -23,3 +23,7 @@ import ( func TestRepoListOutputCompletion(t *testing.T) { outputFlagCompletionTest(t, "repo list") } + +func TestRepoListFileCompletion(t *testing.T) { + checkFileCompletion(t, "repo list", false) +} diff --git a/cmd/helm/repo_remove_test.go b/cmd/helm/repo_remove_test.go index f7d50140e..0ea1d63d2 100644 --- a/cmd/helm/repo_remove_test.go +++ b/cmd/helm/repo_remove_test.go @@ -160,3 +160,8 @@ func testCacheFiles(t *testing.T, cacheIndexFile string, cacheChartsFile string, t.Errorf("Error cache chart file was not removed for repository %s", repoName) } } + +func TestRepoRemoveFileCompletion(t *testing.T) { + checkFileCompletion(t, "repo remove", false) + checkFileCompletion(t, "repo remove repo1", false) +} diff --git a/cmd/helm/repo_test.go b/cmd/helm/repo_test.go new file mode 100644 index 000000000..2b0df7c4c --- /dev/null +++ b/cmd/helm/repo_test.go @@ -0,0 +1,25 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "testing" +) + +func TestRepoFileCompletion(t *testing.T) { + checkFileCompletion(t, "repo", false) +} diff --git a/cmd/helm/repo_update.go b/cmd/helm/repo_update.go index cbfc05b00..e845751c1 100644 --- a/cmd/helm/repo_update.go +++ b/cmd/helm/repo_update.go @@ -46,11 +46,12 @@ func newRepoUpdateCmd(out io.Writer) *cobra.Command { o := &repoUpdateOptions{update: updateCharts} cmd := &cobra.Command{ - Use: "update", - Aliases: []string{"up"}, - Short: "update information of available charts locally from chart repositories", - Long: updateDesc, - Args: require.NoArgs, + Use: "update", + Aliases: []string{"up"}, + Short: "update information of available charts locally from chart repositories", + Long: updateDesc, + Args: require.NoArgs, + ValidArgsFunction: noCompletions, RunE: func(cmd *cobra.Command, args []string) error { o.repoFile = settings.RepositoryConfig o.repoCache = settings.RepositoryCache diff --git a/cmd/helm/repo_update_test.go b/cmd/helm/repo_update_test.go index 981f0bba3..e5e4eb337 100644 --- a/cmd/helm/repo_update_test.go +++ b/cmd/helm/repo_update_test.go @@ -100,3 +100,7 @@ func TestUpdateCharts(t *testing.T) { t.Error("Update was not successful") } } + +func TestRepoUpdateFileCompletion(t *testing.T) { + checkFileCompletion(t, "repo update", false) +} diff --git a/cmd/helm/rollback_test.go b/cmd/helm/rollback_test.go index c11a7fca6..b39378f92 100644 --- a/cmd/helm/rollback_test.go +++ b/cmd/helm/rollback_test.go @@ -104,3 +104,9 @@ func TestRollbackRevisionCompletion(t *testing.T) { }} runTestCmd(t, tests) } + +func TestRollbackFileCompletion(t *testing.T) { + checkFileCompletion(t, "rollback", false) + checkFileCompletion(t, "rollback myrelease", false) + checkFileCompletion(t, "rollback myrelease 1", false) +} diff --git a/cmd/helm/root.go b/cmd/helm/root.go index 449009cb5..904f11a21 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -75,6 +75,9 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string Short: "The Helm package manager for Kubernetes.", Long: globalUsage, SilenceUsage: true, + // This breaks completion for 'helm help ' + // The Cobra release following 1.0 will fix this + //ValidArgsFunction: noCompletions, // Disable file completion } flags := cmd.PersistentFlags() diff --git a/cmd/helm/root_test.go b/cmd/helm/root_test.go index 891bb698e..075544971 100644 --- a/cmd/helm/root_test.go +++ b/cmd/helm/root_test.go @@ -121,3 +121,11 @@ func TestUnknownSubCmd(t *testing.T) { t.Errorf("Expect unknown command error, got %q", err) } } + +// Need the release of Cobra following 1.0 to be able to disable +// file completion on the root command. Until then, we cannot +// because it would break 'helm help ' +// +// func TestRootFileCompletion(t *testing.T) { +// checkFileCompletion(t, "", false) +// } diff --git a/cmd/helm/search.go b/cmd/helm/search.go index 240d5e7c7..44c8d64e3 100644 --- a/cmd/helm/search.go +++ b/cmd/helm/search.go @@ -31,9 +31,10 @@ search subcommands to search different locations for charts. func newSearchCmd(out io.Writer) *cobra.Command { cmd := &cobra.Command{ - Use: "search [keyword]", - Short: "search for a keyword in charts", - Long: searchDesc, + Use: "search [keyword]", + Short: "search for a keyword in charts", + Long: searchDesc, + ValidArgsFunction: noCompletions, // Disable file completion } cmd.AddCommand(newSearchHubCmd(out)) diff --git a/cmd/helm/search_hub_test.go b/cmd/helm/search_hub_test.go index 7b0f3a389..4f62eed74 100644 --- a/cmd/helm/search_hub_test.go +++ b/cmd/helm/search_hub_test.go @@ -54,3 +54,7 @@ func TestSearchHubCmd(t *testing.T) { func TestSearchHubOutputCompletion(t *testing.T) { outputFlagCompletionTest(t, "search hub") } + +func TestSearchHubFileCompletion(t *testing.T) { + checkFileCompletion(t, "search hub", true) // File completion may be useful when inputing a keyword +} diff --git a/cmd/helm/search_repo.go b/cmd/helm/search_repo.go index dd530379b..a7f27f179 100644 --- a/cmd/helm/search_repo.go +++ b/cmd/helm/search_repo.go @@ -365,6 +365,11 @@ func compListCharts(toComplete string, includeFiles bool) ([]string, cobra.Shell // We handle it ourselves instead. completions = compEnforceNoSpace(completions) } + if !includeFiles { + // If we should not include files in the completions, + // we should disable file completion + directive = directive | cobra.ShellCompDirectiveNoFileComp + } return completions, directive } diff --git a/cmd/helm/search_repo_test.go b/cmd/helm/search_repo_test.go index 402ef2970..39c9c53f5 100644 --- a/cmd/helm/search_repo_test.go +++ b/cmd/helm/search_repo_test.go @@ -87,3 +87,7 @@ func TestSearchRepositoriesCmd(t *testing.T) { func TestSearchRepoOutputCompletion(t *testing.T) { outputFlagCompletionTest(t, "search repo") } + +func TestSearchRepoFileCompletion(t *testing.T) { + checkFileCompletion(t, "search repo", true) // File completion may be useful when inputing a keyword +} diff --git a/cmd/helm/search_test.go b/cmd/helm/search_test.go new file mode 100644 index 000000000..6cf845b06 --- /dev/null +++ b/cmd/helm/search_test.go @@ -0,0 +1,23 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import "testing" + +func TestSearchFileCompletion(t *testing.T) { + checkFileCompletion(t, "search", false) +} diff --git a/cmd/helm/show.go b/cmd/helm/show.go index fe5eaee26..888d2d3f3 100644 --- a/cmd/helm/show.go +++ b/cmd/helm/show.go @@ -55,11 +55,12 @@ func newShowCmd(out io.Writer) *cobra.Command { client := action.NewShow(action.ShowAll) showCommand := &cobra.Command{ - Use: "show", - Short: "show information of a chart", - Aliases: []string{"inspect"}, - Long: showDesc, - Args: require.NoArgs, + Use: "show", + Short: "show information of a chart", + Aliases: []string{"inspect"}, + Long: showDesc, + Args: require.NoArgs, + ValidArgsFunction: noCompletions, // Disable file completion } // Function providing dynamic auto-completion diff --git a/cmd/helm/show_test.go b/cmd/helm/show_test.go index 6c550282f..2734faf5e 100644 --- a/cmd/helm/show_test.go +++ b/cmd/helm/show_test.go @@ -118,3 +118,23 @@ func TestShowVersionCompletion(t *testing.T) { }} runTestCmd(t, tests) } + +func TestShowFileCompletion(t *testing.T) { + checkFileCompletion(t, "show", false) +} + +func TestShowAllFileCompletion(t *testing.T) { + checkFileCompletion(t, "show all", true) +} + +func TestShowChartFileCompletion(t *testing.T) { + checkFileCompletion(t, "show chart", true) +} + +func TestShowReadmeFileCompletion(t *testing.T) { + checkFileCompletion(t, "show readme", true) +} + +func TestShowValuesFileCompletion(t *testing.T) { + checkFileCompletion(t, "show values", true) +} diff --git a/cmd/helm/status_test.go b/cmd/helm/status_test.go index 0d2500e65..18731e465 100644 --- a/cmd/helm/status_test.go +++ b/cmd/helm/status_test.go @@ -171,3 +171,8 @@ func TestStatusRevisionCompletion(t *testing.T) { func TestStatusOutputCompletion(t *testing.T) { outputFlagCompletionTest(t, "status") } + +func TestStatusFileCompletion(t *testing.T) { + checkFileCompletion(t, "status", false) + checkFileCompletion(t, "status myrelease", false) +} diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go index f8cd31347..6f7ca939d 100644 --- a/cmd/helm/template_test.go +++ b/cmd/helm/template_test.go @@ -154,3 +154,10 @@ func TestTemplateVersionCompletion(t *testing.T) { }} runTestCmd(t, tests) } + +func TestTemplateFileCompletion(t *testing.T) { + checkFileCompletion(t, "template", false) + checkFileCompletion(t, "template --generate-name", true) + checkFileCompletion(t, "template myname", true) + checkFileCompletion(t, "template myname mychart", false) +} diff --git a/cmd/helm/uninstall_test.go b/cmd/helm/uninstall_test.go index a34934077..ad78361c1 100644 --- a/cmd/helm/uninstall_test.go +++ b/cmd/helm/uninstall_test.go @@ -66,3 +66,8 @@ func TestUninstall(t *testing.T) { } runTestCmd(t, tests) } + +func TestUninstallFileCompletion(t *testing.T) { + checkFileCompletion(t, "uninstall", false) + checkFileCompletion(t, "uninstall myrelease", false) +} diff --git a/cmd/helm/upgrade_test.go b/cmd/helm/upgrade_test.go index 64daf2934..6fe79ebce 100644 --- a/cmd/helm/upgrade_test.go +++ b/cmd/helm/upgrade_test.go @@ -407,3 +407,9 @@ func TestUpgradeVersionCompletion(t *testing.T) { }} runTestCmd(t, tests) } + +func TestUpgradeFileCompletion(t *testing.T) { + checkFileCompletion(t, "upgrade", false) + checkFileCompletion(t, "upgrade myrelease", true) + checkFileCompletion(t, "upgrade myrelease repo/chart", false) +} diff --git a/cmd/helm/verify.go b/cmd/helm/verify.go index f26fb377f..d126c9ef3 100644 --- a/cmd/helm/verify.go +++ b/cmd/helm/verify.go @@ -44,6 +44,14 @@ func newVerifyCmd(out io.Writer) *cobra.Command { Short: "verify that a chart at the given path has been signed and is valid", Long: verifyDesc, Args: require.ExactArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) == 0 { + // Allow file completion when completing the argument for the path + return nil, cobra.ShellCompDirectiveDefault + } + // No more completions, so disable file completion + return nil, cobra.ShellCompDirectiveNoFileComp + }, RunE: func(cmd *cobra.Command, args []string) error { err := client.Run(args[0]) if err != nil { diff --git a/cmd/helm/verify_test.go b/cmd/helm/verify_test.go index ccbcb3cf2..23b793557 100644 --- a/cmd/helm/verify_test.go +++ b/cmd/helm/verify_test.go @@ -90,3 +90,8 @@ func TestVerifyCmd(t *testing.T) { }) } } + +func TestVerifyFileCompletion(t *testing.T) { + checkFileCompletion(t, "verify", true) + checkFileCompletion(t, "verify mypath", false) +} diff --git a/cmd/helm/version.go b/cmd/helm/version.go index 2f50c876c..72f93e545 100644 --- a/cmd/helm/version.go +++ b/cmd/helm/version.go @@ -59,10 +59,11 @@ func newVersionCmd(out io.Writer) *cobra.Command { o := &versionOptions{} cmd := &cobra.Command{ - Use: "version", - Short: "print the client version information", - Long: versionDesc, - Args: require.NoArgs, + Use: "version", + Short: "print the client version information", + Long: versionDesc, + Args: require.NoArgs, + ValidArgsFunction: noCompletions, RunE: func(cmd *cobra.Command, args []string) error { return o.run(out) }, diff --git a/cmd/helm/version_test.go b/cmd/helm/version_test.go index 134401948..aa3cbfb7d 100644 --- a/cmd/helm/version_test.go +++ b/cmd/helm/version_test.go @@ -43,3 +43,7 @@ func TestVersion(t *testing.T) { }} runTestCmd(t, tests) } + +func TestVersionFileCompletion(t *testing.T) { + checkFileCompletion(t, "version", false) +} From b07b2589fb157f017079c0f7285f98bc56a33ae2 Mon Sep 17 00:00:00 2001 From: Tariq Ibrahim Date: Tue, 18 Aug 2020 21:58:21 -0700 Subject: [PATCH 150/159] optimise if condition in service ready logic Signed-off-by: Tariq Ibrahim --- pkg/kube/wait.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/kube/wait.go b/pkg/kube/wait.go index 90a9f8b38..c3beb232d 100644 --- a/pkg/kube/wait.go +++ b/pkg/kube/wait.go @@ -188,8 +188,8 @@ func (w *waiter) serviceReady(s *corev1.Service) bool { return true } - // Make sure the service is not explicitly set to "None" before checking the IP - if s.Spec.ClusterIP != corev1.ClusterIPNone && s.Spec.ClusterIP == "" { + // Ensure that the service cluster IP is not empty + if s.Spec.ClusterIP == "" { w.log("Service does not have cluster IP address: %s/%s", s.GetNamespace(), s.GetName()) return false } From 9664bb2a0a528e1b9262501dfaee587e0e459c39 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Wed, 19 Aug 2020 13:20:54 -0700 Subject: [PATCH 151/159] add v4 to list of exempt labels Signed-off-by: Matthew Fisher --- .github/workflows/stale-issue-bot.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale-issue-bot.yaml b/.github/workflows/stale-issue-bot.yaml index e21e6d5ca..946e7f09b 100644 --- a/.github/workflows/stale-issue-bot.yaml +++ b/.github/workflows/stale-issue-bot.yaml @@ -10,6 +10,6 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue has been marked as stale because it has been open for 90 days with no activity. This thread will be automatically closed in 30 days if no further activity occurs.' - exempt-issue-labels: 'keep open' + exempt-issue-labels: 'keep open,v4.x' days-before-stale: 90 days-before-close: 30 From d13c43d3e8d54c09d82d2aff68b06255538649c8 Mon Sep 17 00:00:00 2001 From: Matthew Fisher Date: Wed, 19 Aug 2020 13:33:12 -0700 Subject: [PATCH 152/159] use URL escape codes Signed-off-by: Matthew Fisher --- .github/workflows/stale-issue-bot.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale-issue-bot.yaml b/.github/workflows/stale-issue-bot.yaml index 946e7f09b..32ea22418 100644 --- a/.github/workflows/stale-issue-bot.yaml +++ b/.github/workflows/stale-issue-bot.yaml @@ -10,6 +10,6 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue has been marked as stale because it has been open for 90 days with no activity. This thread will be automatically closed in 30 days if no further activity occurs.' - exempt-issue-labels: 'keep open,v4.x' + exempt-issue-labels: 'keep+open,v4.x' days-before-stale: 90 days-before-close: 30 From 11f658e2234f5d3c02212e30ba38cd579d134aaa Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Thu, 20 Aug 2020 13:08:48 -0400 Subject: [PATCH 153/159] Fixing linting of templates on Windows When the engine stored templates in the map the keys were generated based on path and not filepath. filepath was being used in the linter when retrieving content from the keys. On Windows the keys ended up being different. This change is to use path joins to create the lookup key. Since the name path was used in the code it needed to be changed in order to import the package. Tests already exist and were failing on windows. This got in because CI is not run on Windows. Closes #6418 Signed-off-by: Matt Farina --- pkg/lint/rules/template.go | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/pkg/lint/rules/template.go b/pkg/lint/rules/template.go index 3da5b63fa..9a3a2a1ba 100644 --- a/pkg/lint/rules/template.go +++ b/pkg/lint/rules/template.go @@ -19,6 +19,7 @@ package rules import ( "fmt" "os" + "path" "path/filepath" "regexp" "strings" @@ -47,10 +48,10 @@ var validName = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([- // Templates lints the templates in the Linter. func Templates(linter *support.Linter, values map[string]interface{}, namespace string, strict bool) { - path := "templates/" - templatesPath := filepath.Join(linter.ChartDir, path) + fpath := "templates/" + templatesPath := filepath.Join(linter.ChartDir, fpath) - templatesDirExist := linter.RunLinterRule(support.WarningSev, path, validateTemplatesDir(templatesPath)) + templatesDirExist := linter.RunLinterRule(support.WarningSev, fpath, validateTemplatesDir(templatesPath)) // Templates directory is optional for now if !templatesDirExist { @@ -60,7 +61,7 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace // Load chart and parse templates chart, err := loader.Load(linter.ChartDir) - chartLoaded := linter.RunLinterRule(support.ErrorSev, path, err) + chartLoaded := linter.RunLinterRule(support.ErrorSev, fpath, err) if !chartLoaded { return @@ -77,14 +78,14 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace } valuesToRender, err := chartutil.ToRenderValues(chart, cvals, options, nil) if err != nil { - linter.RunLinterRule(support.ErrorSev, path, err) + linter.RunLinterRule(support.ErrorSev, fpath, err) return } var e engine.Engine e.LintMode = true renderedContentMap, err := e.Render(chart, valuesToRender) - renderOk := linter.RunLinterRule(support.ErrorSev, path, err) + renderOk := linter.RunLinterRule(support.ErrorSev, fpath, err) if !renderOk { return @@ -99,13 +100,13 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace */ for _, template := range chart.Templates { fileName, data := template.Name, template.Data - path = fileName + fpath = fileName - linter.RunLinterRule(support.ErrorSev, path, validateAllowedExtension(fileName)) + linter.RunLinterRule(support.ErrorSev, fpath, validateAllowedExtension(fileName)) // These are v3 specific checks to make sure and warn people if their // chart is not compatible with v3 - linter.RunLinterRule(support.WarningSev, path, validateNoCRDHooks(data)) - linter.RunLinterRule(support.ErrorSev, path, validateNoReleaseTime(data)) + linter.RunLinterRule(support.WarningSev, fpath, validateNoCRDHooks(data)) + linter.RunLinterRule(support.ErrorSev, fpath, validateNoReleaseTime(data)) // We only apply the following lint rules to yaml files if filepath.Ext(fileName) != ".yaml" || filepath.Ext(fileName) == ".yml" { @@ -114,12 +115,12 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace // NOTE: disabled for now, Refs https://github.com/helm/helm/issues/1463 // Check that all the templates have a matching value - //linter.RunLinterRule(support.WarningSev, path, validateNoMissingValues(templatesPath, valuesToRender, preExecutedTemplate)) + //linter.RunLinterRule(support.WarningSev, fpath, validateNoMissingValues(templatesPath, valuesToRender, preExecutedTemplate)) // NOTE: disabled for now, Refs https://github.com/helm/helm/issues/1037 - // linter.RunLinterRule(support.WarningSev, path, validateQuotes(string(preExecutedTemplate))) + // linter.RunLinterRule(support.WarningSev, fpath, validateQuotes(string(preExecutedTemplate))) - renderedContent := renderedContentMap[filepath.Join(chart.Name(), fileName)] + renderedContent := renderedContentMap[path.Join(chart.Name(), fileName)] if strings.TrimSpace(renderedContent) != "" { var yamlStruct K8sYamlStruct // Even though K8sYamlStruct only defines a few fields, an error in any other @@ -128,10 +129,10 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace // If YAML linting fails, we sill progress. So we don't capture the returned state // on this linter run. - linter.RunLinterRule(support.ErrorSev, path, validateYamlContent(err)) - linter.RunLinterRule(support.ErrorSev, path, validateMetadataName(&yamlStruct)) - linter.RunLinterRule(support.ErrorSev, path, validateNoDeprecations(&yamlStruct)) - linter.RunLinterRule(support.ErrorSev, path, validateMatchSelector(&yamlStruct, renderedContent)) + linter.RunLinterRule(support.ErrorSev, fpath, validateYamlContent(err)) + linter.RunLinterRule(support.ErrorSev, fpath, validateMetadataName(&yamlStruct)) + linter.RunLinterRule(support.ErrorSev, fpath, validateNoDeprecations(&yamlStruct)) + linter.RunLinterRule(support.ErrorSev, fpath, validateMatchSelector(&yamlStruct, renderedContent)) } } } From 8a545d6ca7e40ae412c53f5dc683ecc8a8ecdb96 Mon Sep 17 00:00:00 2001 From: Ma Xinjian Date: Fri, 21 Aug 2020 14:47:29 +0800 Subject: [PATCH 154/159] Correct checksum file links Signed-off-by: Ma Xinjian --- scripts/release-notes.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/release-notes.sh b/scripts/release-notes.sh index dd48d4a17..3625aaa9a 100755 --- a/scripts/release-notes.sh +++ b/scripts/release-notes.sh @@ -39,8 +39,8 @@ done ## Check for hints that checksum files were downloaded ## from `make fetch-dist` -if [[ ! -e "./_dist/helm-${RELEASE}-darwin-amd64.tar.gz.sha256" ]]; then - echo "checksum file ./_dist/helm-${RELEASE}-darwin-amd64.tar.gz.sha256 not found in ./_dist/" +if [[ ! -e "./_dist/helm-${RELEASE}-darwin-amd64.tar.gz.sha256sum" ]]; then + echo "checksum file ./_dist/helm-${RELEASE}-darwin-amd64.tar.gz.sha256sum not found in ./_dist/" echo "Did you forget to run \`make fetch-dist\` first ?" exit 1 fi From 4abcdc40efb9ad455ed99bc73c8ee716fe89123d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Fri, 21 Aug 2020 11:21:43 +0200 Subject: [PATCH 155/159] pkg/*: Small linting fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Manuel Rüger --- pkg/action/package.go | 2 +- pkg/repo/chartrepo_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/action/package.go b/pkg/action/package.go index 19d845cf3..5059eee07 100644 --- a/pkg/action/package.go +++ b/pkg/action/package.go @@ -135,7 +135,7 @@ func (p *Package) Clearsign(filename string) error { // promptUser implements provenance.PassphraseFetcher func promptUser(name string) ([]byte, error) { fmt.Printf("Password for key %q > ", name) - pw, err := terminal.ReadPassword(int(syscall.Stdin)) + pw, err := terminal.ReadPassword(syscall.Stdin) fmt.Println() return pw, err } diff --git a/pkg/repo/chartrepo_test.go b/pkg/repo/chartrepo_test.go index f50d6a2b6..eceb3009e 100644 --- a/pkg/repo/chartrepo_test.go +++ b/pkg/repo/chartrepo_test.go @@ -172,7 +172,7 @@ func TestIndexCustomSchemeDownload(t *testing.T) { func verifyIndex(t *testing.T, actual *IndexFile) { var empty time.Time - if actual.Generated == empty { + if actual.Generated.Equal(empty) { t.Errorf("Generated should be greater than 0: %s", actual.Generated) } @@ -242,7 +242,7 @@ func verifyIndex(t *testing.T, actual *IndexFile) { if len(g.Maintainers) != 2 { t.Error("Expected 2 maintainers.") } - if g.Created == empty { + if g.Created.Equal(empty) { t.Error("Expected created to be non-empty") } if g.Description == "" { From 3fc88f24929b3cac6e5284bbb5701ff94b3f11e0 Mon Sep 17 00:00:00 2001 From: Matt Farina Date: Fri, 21 Aug 2020 11:51:58 -0400 Subject: [PATCH 156/159] Fixing failing CI for windows A fix introduced in #8631 caused a bug in Windows builds due to a type difference between POSIX and Windows environments. This change corrects that problem and provides a code comment to warn others. Signed-off-by: Matt Farina --- pkg/action/package.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/action/package.go b/pkg/action/package.go index 5059eee07..0a927cd41 100644 --- a/pkg/action/package.go +++ b/pkg/action/package.go @@ -135,7 +135,9 @@ func (p *Package) Clearsign(filename string) error { // promptUser implements provenance.PassphraseFetcher func promptUser(name string) ([]byte, error) { fmt.Printf("Password for key %q > ", name) - pw, err := terminal.ReadPassword(syscall.Stdin) + // syscall.Stdin is not an int in all environments and needs to be coerced + // into one there (e.g., Windows) + pw, err := terminal.ReadPassword(int(syscall.Stdin)) fmt.Println() return pw, err } From 10d4d2ed999a403e2464f673e0e19b95ee4e1ac6 Mon Sep 17 00:00:00 2001 From: rudeigerc Date: Sat, 22 Aug 2020 02:30:22 +0800 Subject: [PATCH 157/159] feat(env): add support of accepting a specific variable for helm env Signed-off-by: Yuchen Cheng --- cmd/helm/env.go | 48 +++++++++++++++++++-------- cmd/helm/env_test.go | 9 +++++ cmd/helm/testdata/output/env-comp.txt | 16 +++++++++ 3 files changed, 59 insertions(+), 14 deletions(-) create mode 100644 cmd/helm/testdata/output/env-comp.txt diff --git a/cmd/helm/env.go b/cmd/helm/env.go index 4db3d80de..3754b748d 100644 --- a/cmd/helm/env.go +++ b/cmd/helm/env.go @@ -32,25 +32,45 @@ Env prints out all the environment information in use by Helm. func newEnvCmd(out io.Writer) *cobra.Command { cmd := &cobra.Command{ - Use: "env", - Short: "helm client environment information", - Long: envHelp, - Args: require.NoArgs, - ValidArgsFunction: noCompletions, + Use: "env", + Short: "helm client environment information", + Long: envHelp, + Args: require.MaximumNArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) == 0 { + keys := getSortedEnvVarKeys() + return keys, cobra.ShellCompDirectiveNoFileComp + } + + return nil, cobra.ShellCompDirectiveNoFileComp + }, Run: func(cmd *cobra.Command, args []string) { envVars := settings.EnvVars() - // Sort the variables by alphabetical order. - // This allows for a constant output across calls to 'helm env'. - var keys []string - for k := range envVars { - keys = append(keys, k) - } - sort.Strings(keys) - for _, k := range keys { - fmt.Fprintf(out, "%s=\"%s\"\n", k, envVars[k]) + if len(args) == 0 { + // Sort the variables by alphabetical order. + // This allows for a constant output across calls to 'helm env'. + keys := getSortedEnvVarKeys() + + for _, k := range keys { + fmt.Fprintf(out, "%s=\"%s\"\n", k, envVars[k]) + } + } else { + fmt.Fprintf(out, "%s\n", envVars[args[0]]) } }, } return cmd } + +func getSortedEnvVarKeys() []string { + envVars := settings.EnvVars() + + var keys []string + for k := range envVars { + keys = append(keys, k) + } + sort.Strings(keys) + + return keys +} diff --git a/cmd/helm/env_test.go b/cmd/helm/env_test.go index a7170a8cc..abdc9c94e 100644 --- a/cmd/helm/env_test.go +++ b/cmd/helm/env_test.go @@ -20,6 +20,15 @@ import ( "testing" ) +func TestEnv(t *testing.T) { + tests := []cmdTestCase{{ + name: "completion for env", + cmd: "__complete env ''", + golden: "output/env-comp.txt", + }} + runTestCmd(t, tests) +} + func TestEnvFileCompletion(t *testing.T) { checkFileCompletion(t, "env", false) } diff --git a/cmd/helm/testdata/output/env-comp.txt b/cmd/helm/testdata/output/env-comp.txt new file mode 100644 index 000000000..c4b46ae6b --- /dev/null +++ b/cmd/helm/testdata/output/env-comp.txt @@ -0,0 +1,16 @@ +HELM_BIN +HELM_CACHE_HOME +HELM_CONFIG_HOME +HELM_DATA_HOME +HELM_DEBUG +HELM_KUBEAPISERVER +HELM_KUBECONTEXT +HELM_KUBETOKEN +HELM_MAX_HISTORY +HELM_NAMESPACE +HELM_PLUGINS +HELM_REGISTRY_CONFIG +HELM_REPOSITORY_CACHE +HELM_REPOSITORY_CONFIG +:4 +Completion ended with directive: ShellCompDirectiveNoFileComp From 195d7a650712d8eee2db887bf8e1a4e2c363328b Mon Sep 17 00:00:00 2001 From: Yuchen Cheng Date: Sat, 22 Aug 2020 22:04:09 +0800 Subject: [PATCH 158/159] add checkFileCompletion for env HELM_BIN Signed-off-by: Yuchen Cheng --- cmd/helm/env_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/helm/env_test.go b/cmd/helm/env_test.go index abdc9c94e..01ef25933 100644 --- a/cmd/helm/env_test.go +++ b/cmd/helm/env_test.go @@ -31,4 +31,5 @@ func TestEnv(t *testing.T) { func TestEnvFileCompletion(t *testing.T) { checkFileCompletion(t, "env", false) + checkFileCompletion(t, "env HELM_BIN", false) } From 45b084b25504a1e19592684f964f43b57792875a Mon Sep 17 00:00:00 2001 From: knrt10 Date: Fri, 28 Aug 2020 18:23:33 +0530 Subject: [PATCH 159/159] Fix spelling in completion.go Signed-off-by: knrt10 --- cmd/helm/completion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/completion.go b/cmd/helm/completion.go index c7e763c3d..db50b375a 100644 --- a/cmd/helm/completion.go +++ b/cmd/helm/completion.go @@ -151,7 +151,7 @@ __helm_compgen() { fi for w in "${completions[@]}"; do if [[ "${w}" = "$1"* ]]; then - # Use printf instead of echo beause it is possible that + # Use printf instead of echo because it is possible that # the value to print is -n, which would be interpreted # as a flag to echo printf "%s\n" "${w}"