Repository: helm/helm (go)

Issue:
"helm install --description" flag not available
Output of `helm version`:
`version.BuildInfo{Version:"v3.0.0", GitCommit:"e29ce2a54e96cd02ccfce88bee4f58bb6e2a28b6", GitTreeState:"clean", GoVersion:"go1.13.4"}`

Output of `kubectl version`:
```
Client Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.1", GitCommit:"d647ddbd755faf07169599a625faf302ffc34458", GitTreeState:"clean", BuildDate:"2019-10-02T17:01:15Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"13+", GitVersion:"v1.13.11-eks-5876d6", GitCommit:"5876d6b7429820450950ade17fe7b4bf5ccada7f", GitTreeState:"clean", BuildDate:"2019-09-24T20:54:25Z", GoVersion:"go1.11.13", Compiler:"gc", Platform:"linux/amd64"}
```

Cloud Provider/Platform (AKS, GKE, Minikube etc.): 
any of them

**Steps to reproduce the issue**
Just run:

`helm install ... --description "your description" ...`

**Actual behavior**
I get this error:
`Error: unknown flag: --description`

**Expected behavior**
As for Helm2 I need to add a description to my release.

**Additional**

I don't know if there is an equivalent flag on Helm 3. I couldn't find anything on the internet.

If there is a command to add description please let me know. If there is not, isn't it a desirable feature?

Thanks.


Pull request:
fix(helm): add --description flag to helm
fix(helm): add --description flag to 'helm install', 'helm upgrade', and 'helm uninstall'

Since this feature was present on helm 2, and some existing pipelines rely heavily on it, I believe is better adding it here instead of modifying a lot of existing scripts.

When added, this flag allows us to add a custom description to the release. E.g.: 
`--description "my custom description"`

Closes #7033

Signed-off-by: Juan Matias Kungfu de la Camara Beovide <juanmatias@gmail.com>

Patch:
diff --git a/Makefile b/Makefile
index e48a20fd5..611222e28 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,8 @@
-BINDIR     := $(CURDIR)/bin
-DIST_DIRS  := find * -type d -exec
-TARGETS    := darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le windows/amd64
-BINNAME    ?= helm
+BINDIR      := $(CURDIR)/bin
+DIST_DIRS   := find * -type d -exec
+TARGETS     := darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le windows/amd64
+TARGET_OBJS ?= darwin-amd64.tar.gz darwin-amd64.tar.gz.sha256 linux-amd64.tar.gz linux-amd64.tar.gz.sha256 linux-386.tar.gz linux-386.tar.gz.sha256 linux-arm.tar.gz linux-arm.tar.gz.sha256 linux-arm64.tar.gz linux-arm64.tar.gz.sha256 linux-ppc64le.tar.gz linux-ppc64le.tar.gz.sha256 windows-amd64.zip windows-amd64.zip.sha256
+BINNAME     ?= helm
 
 GOPATH        = $(shell go env GOPATH)
 DEP           = $(GOPATH)/bin/dep
@@ -138,6 +139,20 @@ dist:
 		$(DIST_DIRS) zip -r helm-${VERSION}-{}.zip {} \; \
 	)
 
+.PHONY: fetch-dist
+fetch-dist:
+	mkdir -p _dist
+	cd _dist && \
+	for obj in ${TARGET_OBJS} ; do \
+		curl -sSL -o helm-${VERSION}-$${obj} https://get.helm.sh/helm-${VERSION}-$${obj} ; \
+	done
+
+.PHONY: sign
+sign:
+	for f in _dist/*.{gz,zip,sha256} ; do \
+		gpg --armor --detach-sign $${f} ; \
+	done
+
 .PHONY: checksum
 checksum:
 	for f in _dist/*.{gz,zip} ; do \
diff --git a/README.md b/README.md
index bb1e40ca6..73fd189d7 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 [![CircleCI](https://circleci.com/gh/helm/helm.svg?style=shield)](https://circleci.com/gh/helm/helm)
 [![Go Report Card](https://goreportcard.com/badge/github.com/helm/helm)](https://goreportcard.com/report/github.com/helm/helm)
-[![GoDoc](https://godoc.org/helm.sh/helm?status.svg)](https://godoc.org/helm.sh/helm)
+[![GoDoc](https://img.shields.io/static/v1?label=godoc&message=reference&color=blue)](https://pkg.go.dev/helm.sh/helm/v3)
 [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3131/badge)](https://bestpractices.coreinfrastructure.org/projects/3131)
 
 Helm is a tool for managing Charts. Charts are packages of pre-configured Kubernetes resources.
diff --git a/cmd/helm/install.go b/cmd/helm/install.go
index 40935db17..176250f84 100644
--- a/cmd/helm/install.go
+++ b/cmd/helm/install.go
@@ -130,11 +130,12 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 func addInstallFlags(f *pflag.FlagSet, client *action.Install, valueOpts *values.Options) {
 	f.BoolVar(&client.DryRun, "dry-run", false, "simulate an install")
 	f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during install")
-	f.BoolVar(&client.Replace, "replace", false, "re-use the given name, even if that name is already used. This is unsafe in production")
+	f.BoolVar(&client.Replace, "replace", false, "re-use the given name, only if that name is a deleted release which remains in the history. This is unsafe in production")
 	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.BoolVarP(&client.GenerateName, "generate-name", "g", false, "generate the name (and omit the NAME parameter)")
 	f.StringVar(&client.NameTemplate, "name-template", "", "specify template used to name the release")
+	f.StringVar(&client.Description, "description", "", "add a custom description")
 	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.DependencyUpdate, "dependency-update", false, "run helm dependency update before installing the chart")
 	f.BoolVar(&client.Atomic, "atomic", false, "if set, installation process purges chart on fail. The --wait flag will be set automatically if --atomic is used")
diff --git a/cmd/helm/list.go b/cmd/helm/list.go
index 83edfe156..0da0c21d3 100644
--- a/cmd/helm/list.go
+++ b/cmd/helm/list.go
@@ -97,7 +97,7 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 	f.BoolVarP(&client.ByDate, "date", "d", false, "sort by release date")
 	f.BoolVarP(&client.SortReverse, "reverse", "r", false, "reverse the sort order")
 	f.BoolVarP(&client.All, "all", "a", false, "show all releases, not just the ones marked deployed or failed")
-	f.BoolVar(&client.Uninstalled, "uninstalled", false, "show uninstalled releases")
+	f.BoolVar(&client.Uninstalled, "uninstalled", false, "show uninstalled releases (if 'helm uninstall --keep-history' was used)")
 	f.BoolVar(&client.Superseded, "superseded", false, "show superseded releases")
 	f.BoolVar(&client.Uninstalling, "uninstalling", false, "show releases that are currently being uninstalled")
 	f.BoolVar(&client.Deployed, "deployed", false, "show deployed releases. If no other is specified, this will be automatically enabled")
diff --git a/cmd/helm/load_plugins.go b/cmd/helm/load_plugins.go
index ed99a5164..f2fb5c01d 100644
--- a/cmd/helm/load_plugins.go
+++ b/cmd/helm/load_plugins.go
@@ -151,8 +151,11 @@ func manuallyProcessArgs(args []string) ([]string, []string) {
 		case "--debug":
 			known = append(known, a)
 		case isKnown(a):
-			known = append(known, a, args[i+1])
+			known = append(known, a)
 			i++
+			if i < len(args) {
+				known = append(known, args[i])
+			}
 		default:
 			if knownArg(a) {
 				known = append(known, a)
diff --git a/cmd/helm/package.go b/cmd/helm/package.go
index dd4bb2d17..9f7961f95 100644
--- a/cmd/helm/package.go
+++ b/cmd/helm/package.go
@@ -36,10 +36,15 @@ This command packages a chart into a versioned chart archive file. If a path
 is given, this will look at that path for a chart (which must contain a
 Chart.yaml file) and then package that directory.
 
-If no path is given, this will look in the present working directory for a
-Chart.yaml file, and (if found) build the current directory into a chart.
-
 Versioned chart archives are used by Helm package repositories.
+
+To sign a chart, use the '--sign' flag. In most cases, you should also
+provide '--keyring path/to/secret/keys' and '--key keyname'.
+
+  $ helm package --sign ./mychart --key mykey --keyring ~/.gnupg/secring.gpg
+
+If '--keyring' is not specified, Helm usually defaults to the public keyring
+unless your environment is otherwise configured.
 `
 
 func newPackageCmd(out io.Writer) *cobra.Command {
diff --git a/cmd/helm/repo_add.go b/cmd/helm/repo_add.go
index 1c84ad8d6..e6afce3d5 100644
--- a/cmd/helm/repo_add.go
+++ b/cmd/helm/repo_add.go
@@ -29,7 +29,7 @@ import (
 	"github.com/gofrs/flock"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
-	"gopkg.in/yaml.v2"
+	"sigs.k8s.io/yaml"
 
 	"helm.sh/helm/v3/cmd/helm/require"
 	"helm.sh/helm/v3/pkg/getter"
diff --git a/cmd/helm/template.go b/cmd/helm/template.go
index 5312d798f..a47631c0d 100644
--- a/cmd/helm/template.go
+++ b/cmd/helm/template.go
@@ -44,6 +44,7 @@ faked locally. Additionally, none of the server-side testing of chart validity
 
 func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 	var validate bool
+	var includeCrds bool
 	client := action.NewInstall(cfg)
 	valueOpts := &values.Options{}
 	var extraAPIs []string
@@ -67,7 +68,14 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 
 			var manifests bytes.Buffer
 
+			if includeCrds {
+				for _, f := range rel.Chart.CRDs() {
+					fmt.Fprintf(&manifests, "---\n# Source: %s\n%s\n", f.Name, f.Data)
+				}
+			}
+
 			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)
@@ -120,6 +128,8 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 	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")
+	f.BoolVar(&includeCrds, "include-crds", false, "include CRDs in the templated output")
+	f.BoolVar(&client.IsUpgrade, "is-upgrade", false, "set .Release.IsUpgrade instead of .Release.IsInstall")
 	f.StringArrayVarP(&extraAPIs, "api-versions", "a", []string{}, "Kubernetes api versions used for Capabilities.APIVersions")
 
 	return cmd
diff --git a/cmd/helm/uninstall.go b/cmd/helm/uninstall.go
index 27b5a8426..7096d7873 100644
--- a/cmd/helm/uninstall.go
+++ b/cmd/helm/uninstall.go
@@ -69,6 +69,7 @@ func newUninstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 	f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during uninstallation")
 	f.BoolVar(&client.KeepHistory, "keep-history", false, "remove all associated resources and mark the release as deleted, but retain the release history")
 	f.DurationVar(&client.Timeout, "timeout", 300*time.Second, "time to wait for any individual Kubernetes operation (like Jobs for hooks)")
+	f.StringVar(&client.Description, "description", "", "add a custom description")
 
 	return cmd
 }
diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go
index eadc3b63d..dce8ad74f 100644
--- a/cmd/helm/upgrade.go
+++ b/cmd/helm/upgrade.go
@@ -156,6 +156,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 	f.IntVar(&client.MaxHistory, "history-max", 10, "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")
 	addChartPathOptionsFlags(f, &client.ChartPathOptions)
 	addValueOptionsFlags(f, valueOpts)
 	bindOutputFlag(cmd, &outfmt)
diff --git a/code-of-conduct.md b/code-of-conduct.md
index 0d15c00cf..91ccaf035 100644
--- a/code-of-conduct.md
+++ b/code-of-conduct.md
@@ -1,3 +1,3 @@
-# Kubernetes Community Code of Conduct
+# Community Code of Conduct
 
-Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)
+Helm follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
diff --git a/internal/version/version.go b/internal/version/version.go
index 131a2b130..22439d11b 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -33,7 +33,7 @@ var (
 	version = "v3.0"
 
 	// metadata is extra build time data
-	metadata = "unreleased"
+	metadata = ""
 	// gitCommit is the git sha1
 	gitCommit = ""
 	// gitTreeState is the state of the git tree
diff --git a/pkg/action/get_values.go b/pkg/action/get_values.go
index 5bc3a7005..9c32db213 100644
--- a/pkg/action/get_values.go
+++ b/pkg/action/get_values.go
@@ -39,6 +39,10 @@ func NewGetValues(cfg *Configuration) *GetValues {
 
 // Run executes 'helm get values' against the given release.
 func (g *GetValues) Run(name string) (map[string]interface{}, error) {
+	if err := g.cfg.KubeClient.IsReachable(); err != nil {
+		return nil, err
+	}
+
 	rel, err := g.cfg.releaseContent(name, g.Version)
 	if err != nil {
 		return nil, err
diff --git a/pkg/action/install.go b/pkg/action/install.go
index 8cd270693..89a343a6f 100644
--- a/pkg/action/install.go
+++ b/pkg/action/install.go
@@ -79,6 +79,7 @@ type Install struct {
 	ReleaseName      string
 	GenerateName     bool
 	NameTemplate     string
+	Description      string
 	OutputDir        string
 	Atomic           bool
 	SkipCRDs         bool
@@ -86,6 +87,8 @@ type Install struct {
 	// APIVersions allows a manual set of supported API Versions to be passed
 	// (for things like templating). These are ignored if ClientOnly is false
 	APIVersions chartutil.VersionSet
+	// Used by helm template to render charts with .Relase.IsUpgrade. Ignored if Dry-Run is false
+	IsUpgrade bool
 }
 
 // ChartPathOptions captures common options used for controlling chart paths
@@ -197,11 +200,14 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
 		return nil, err
 	}
 
+	//special case for helm template --is-upgrade
+	isUpgrade := i.IsUpgrade && i.DryRun
 	options := chartutil.ReleaseOptions{
 		Name:      i.ReleaseName,
 		Namespace: i.Namespace,
 		Revision:  1,
-		IsInstall: true,
+		IsInstall: !isUpgrade,
+		IsUpgrade: isUpgrade,
 	}
 	valuesToRender, err := chartutil.ToRenderValues(chrt, vals, options, caps)
 	if err != nil {
@@ -237,7 +243,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 {
+	if !i.ClientOnly && !isUpgrade {
 		if err := existingResourceConflict(resources); err != nil {
 			return nil, errors.Wrap(err, "rendered manifests contain a resource that already exists. Unable to continue with install")
 		}
@@ -292,7 +298,11 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
 		}
 	}
 
-	rel.SetStatus(release.StatusDeployed, "Install complete")
+	if len(i.Description) > 0 {
+		rel.SetStatus(release.StatusDeployed, i.Description)
+	} else {
+		rel.SetStatus(release.StatusDeployed, "Install complete")
+	}
 
 	// This is a tricky case. The release has been created, but the result
 	// cannot be recorded. The truest thing to tell the user is that the
diff --git a/pkg/action/pull.go b/pkg/action/pull.go
index aaf63861e..b0a3d2598 100644
--- a/pkg/action/pull.go
+++ b/pkg/action/pull.go
@@ -63,6 +63,7 @@ func (p *Pull) Run(chartRef string) (string, error) {
 		Getters: getter.All(p.Settings),
 		Options: []getter.Option{
 			getter.WithBasicAuth(p.Username, p.Password),
+			getter.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile),
 		},
 		RepositoryConfig: p.Settings.RepositoryConfig,
 		RepositoryCache:  p.Settings.RepositoryCache,
diff --git a/pkg/action/uninstall.go b/pkg/action/uninstall.go
index fb72a845b..dfaa98472 100644
--- a/pkg/action/uninstall.go
+++ b/pkg/action/uninstall.go
@@ -37,6 +37,7 @@ type Uninstall struct {
 	DryRun       bool
 	KeepHistory  bool
 	Timeout      time.Duration
+	Description  string
 }
 
 // NewUninstall creates a new Uninstall object with the given configuration.
@@ -118,7 +119,11 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error)
 	}
 
 	rel.Info.Status = release.StatusUninstalled
-	rel.Info.Description = "Uninstallation complete"
+	if len(u.Description) > 0 {
+		rel.Info.Description = u.Description
+	} else {
+		rel.Info.Description = "Uninstallation complete"
+	}
 
 	if !u.KeepHistory {
 		u.cfg.Log("purge requested for %s", name)
diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go
index d0495a864..cdc40eaaa 100644
--- a/pkg/action/upgrade.go
+++ b/pkg/action/upgrade.go
@@ -58,6 +58,7 @@ type Upgrade struct {
 	Atomic        bool
 	CleanupOnFail bool
 	SubNotes      bool
+	Description   string
 }
 
 // NewUpgrade creates a new Upgrade object with the given configuration.
@@ -218,7 +219,11 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea
 
 	if u.DryRun {
 		u.cfg.Log("dry run for %s", upgradedRelease.Name)
-		upgradedRelease.Info.Description = "Dry run complete"
+		if len(u.Description) > 0 {
+			upgradedRelease.Info.Description = u.Description
+		} else {
+			upgradedRelease.Info.Description = "Dry run complete"
+		}
 		return upgradedRelease, nil
 	}
 
@@ -270,7 +275,11 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea
 	u.cfg.recordRelease(originalRelease)
 
 	upgradedRelease.Info.Status = release.StatusDeployed
-	upgradedRelease.Info.Description = "Upgrade complete"
+	if len(u.Description) > 0 {
+		upgradedRelease.Info.Description = u.Description
+	} else {
+		upgradedRelease.Info.Description = "Upgrade complete"
+	}
 
 	return upgradedRelease, nil
 }
diff --git a/pkg/chart/loader/archive.go b/pkg/chart/loader/archive.go
index 3c50fe379..7e187a170 100644
--- a/pkg/chart/loader/archive.go
+++ b/pkg/chart/loader/archive.go
@@ -126,6 +126,12 @@ func LoadArchiveFiles(in io.Reader) ([]*BufferedFile, error) {
 			continue
 		}
 
+		switch hd.Typeflag {
+		// We don't want to process these extension header files.
+		case tar.TypeXGlobalHeader, tar.TypeXHeader:
+			continue
+		}
+
 		// Archive could contain \ if generated on Windows
 		delimiter := "/"
 		if strings.ContainsRune(hd.Name, '\\') {
diff --git a/pkg/downloader/chart_downloader.go b/pkg/downloader/chart_downloader.go
index 8e251bc89..f3d4321c5 100644
--- a/pkg/downloader/chart_downloader.go
+++ b/pkg/downloader/chart_downloader.go
@@ -214,6 +214,10 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er
 		c.Options = append(c.Options, getter.WithBasicAuth(r.Config.Username, r.Config.Password))
 	}
 
+	if r.Config.CertFile != "" || r.Config.KeyFile != "" || r.Config.CAFile != "" {
+		c.Options = append(c.Options, getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile))
+	}
+
 	// Next, we need to load the index, and actually look up the chart.
 	idxFile := filepath.Join(c.RepositoryCache, helmpath.CacheIndexFile(r.Config.Name))
 	i, err := repo.LoadIndexFile(idxFile)
diff --git a/pkg/downloader/manager.go b/pkg/downloader/manager.go
index 4e9d691d8..81dd53614 100644
--- a/pkg/downloader/manager.go
+++ b/pkg/downloader/manager.go
@@ -149,6 +149,13 @@ func (m *Manager) Update() error {
 		return err
 	}
 
+	// downloadAll might overwrite dependency version, recalculate lock digest
+	newDigest, err := resolver.HashReq(req, lock.Dependencies)
+	if err != nil {
+		return err
+	}
+	lock.Digest = newDigest
+
 	// If the lock file hasn't changed, don't write a new one.
 	oldLock := c.Lock
 	if oldLock != nil && oldLock.Digest == lock.Digest {
diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go
index dae0b6be7..5a7d54993 100644
--- a/pkg/engine/engine.go
+++ b/pkg/engine/engine.go
@@ -93,11 +93,19 @@ func warnWrap(warn string) string {
 // initFunMap creates the Engine's FuncMap and adds context-specific functions.
 func (e Engine) initFunMap(t *template.Template, referenceTpls map[string]renderable) {
 	funcMap := funcMap()
+	includedNames := make([]string, 0)
 
 	// Add the 'include' function here so we can close over t.
 	funcMap["include"] = func(name string, data interface{}) (string, error) {
 		var buf strings.Builder
+		for _, n := range includedNames {
+			if n == name {
+				return "", errors.Wrapf(fmt.Errorf("unable to excute template"), "rendering template has a nested reference name: %s", name)
+			}
+		}
+		includedNames = append(includedNames, name)
 		err := t.ExecuteTemplate(&buf, name, data)
+		includedNames = includedNames[:len(includedNames)-1]
 		return buf.String(), err
 	}
 
diff --git a/pkg/lint/rules/chartfile.go b/pkg/lint/rules/chartfile.go
index 35bb81571..70cb83bc5 100644
--- a/pkg/lint/rules/chartfile.go
+++ b/pkg/lint/rules/chartfile.go
@@ -46,7 +46,6 @@ func Chartfile(linter *support.Linter) {
 	}
 
 	linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartName(chartFile))
-	linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartNameDirMatch(linter.ChartDir, chartFile))
 
 	// Chart metadata
 	linter.RunLinterRule(support.ErrorSev, chartFileName, validateChartAPIVersion(chartFile))
@@ -82,13 +81,6 @@ func validateChartName(cf *chart.Metadata) error {
 	return nil
 }
 
-func validateChartNameDirMatch(chartDir string, cf *chart.Metadata) error {
-	if cf.Name != filepath.Base(chartDir) {
-		return errors.Errorf("directory name (%s) and chart name (%s) must be the same", filepath.Base(chartDir), cf.Name)
-	}
-	return nil
-}
-
 func validateChartAPIVersion(cf *chart.Metadata) error {
 	if cf.APIVersion == "" {
 		return errors.New("apiVersion is required. The value must be either \"v1\" or \"v2\"")
diff --git a/pkg/provenance/sign.go b/pkg/provenance/sign.go
index 6032eb063..5d16779f1 100644
--- a/pkg/provenance/sign.go
+++ b/pkg/provenance/sign.go
@@ -169,7 +169,7 @@ func (s *Signatory) DecryptKey(fn PassphraseFetcher) error {
 	if s.Entity == nil {
 		return errors.New("private key not found")
 	} else if s.Entity.PrivateKey == nil {
-		return errors.New("provided key is not a private key")
+		return errors.New("provided key is not a private key. Try providing a keyring with secret keys")
 	}
 
 	// Nothing else to do if key is not encrypted.
@@ -203,7 +203,7 @@ func (s *Signatory) ClearSign(chartpath string) (string, error) {
 	if s.Entity == nil {
 		return "", errors.New("private key not found")
 	} else if s.Entity.PrivateKey == nil {
-		return "", errors.New("provided key is not a private key")
+		return "", errors.New("provided key is not a private key. Try providing a keyring with secret keys")
 	}
 
 	if fi, err := os.Stat(chartpath); err != nil {
diff --git a/scripts/validate-license.sh b/scripts/validate-license.sh
index 00bd38ea2..dc247436f 100755
--- a/scripts/validate-license.sh
+++ b/scripts/validate-license.sh
@@ -27,14 +27,16 @@ find_files() {
   \( -name '*.go' -o -name '*.sh' \)
 }
 
-mapfile -t failed_license_header < <(find_files | xargs grep -L 'Licensed under the Apache License, Version 2.0 (the "License")')
+# Use "|| :" to ignore the error code when grep returns empty
+failed_license_header=($(find_files | xargs grep -L 'Licensed under the Apache License, Version 2.0 (the "License")' || :))
 if (( ${#failed_license_header[@]} > 0 )); then
   echo "Some source files are missing license headers."
   printf '%s\n' "${failed_license_header[@]}"
   exit 1
 fi
 
-mapfile -t failed_copyright_header < <(find_files | xargs grep -L 'Copyright The Helm Authors.')
+# Use "|| :" to ignore the error code when grep returns empty
+failed_copyright_header=($(find_files | xargs grep -L 'Copyright The Helm Authors.' || :))
 if (( ${#failed_copyright_header[@]} > 0 )); then
   echo "Some source files are missing the copyright header."
   printf '%s\n' "${failed_copyright_header[@]}"


Test patch:
diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go
index 8aa2f6c06..735829432 100644
--- a/cmd/helm/template_test.go
+++ b/cmd/helm/template_test.go
@@ -79,6 +79,11 @@ func TestTemplateCmd(t *testing.T) {
 			cmd:    fmt.Sprintf("template --api-versions helm.k8s.io/test '%s'", chartPath),
 			golden: "output/template-with-api-version.txt",
 		},
+		{
+			name:   "template with CRDs",
+			cmd:    fmt.Sprintf("template '%s' --include-crds", chartPath),
+			golden: "output/template-with-crds.txt",
+		},
 	}
 	runTestCmd(t, tests)
 }
diff --git a/cmd/helm/testdata/output/template-with-crds.txt b/cmd/helm/testdata/output/template-with-crds.txt
new file mode 100644
index 000000000..9fa1c7e6d
--- /dev/null
+++ b/cmd/helm/testdata/output/template-with-crds.txt
@@ -0,0 +1,72 @@
+---
+# Source: crds/crdA.yaml
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: testCRDs
+spec:
+  group: testCRDGroups
+  names:
+    kind: TestCRD
+    listKind: TestCRDList
+    plural: TestCRDs
+    shortNames:
+      - tc
+    singular: authconfig
+
+---
+# Source: subchart1/charts/subcharta/templates/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: subcharta
+  labels:
+    helm.sh/chart: "subcharta-0.1.0"
+spec:
+  type: ClusterIP
+  ports:
+  - port: 80
+    targetPort: 80
+    protocol: TCP
+    name: apache
+  selector:
+    app.kubernetes.io/name: subcharta
+---
+# Source: subchart1/charts/subchartb/templates/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: subchartb
+  labels:
+    helm.sh/chart: "subchartb-0.1.0"
+spec:
+  type: ClusterIP
+  ports:
+  - port: 80
+    targetPort: 80
+    protocol: TCP
+    name: nginx
+  selector:
+    app.kubernetes.io/name: subchartb
+---
+# Source: subchart1/templates/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: subchart1
+  labels:
+    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-api-version/test: v1
+spec:
+  type: ClusterIP
+  ports:
+  - port: 80
+    targetPort: 80
+    protocol: TCP
+    name: nginx
+  selector:
+    app.kubernetes.io/name: subchart1
diff --git a/cmd/helm/testdata/output/version-short.txt b/cmd/helm/testdata/output/version-short.txt
index 5e7749489..d9fb9c736 100644
--- a/cmd/helm/testdata/output/version-short.txt
+++ b/cmd/helm/testdata/output/version-short.txt
@@ -1,1 +1,1 @@
-v3.0+unreleased
+v3.0
diff --git a/cmd/helm/testdata/output/version-template.txt b/cmd/helm/testdata/output/version-template.txt
index c12e29c2d..776c1919b 100644
--- a/cmd/helm/testdata/output/version-template.txt
+++ b/cmd/helm/testdata/output/version-template.txt
@@ -1,1 +1,1 @@
-Version: v3.0+unreleased
\ No newline at end of file
+Version: v3.0
\ No newline at end of file
diff --git a/cmd/helm/testdata/output/version.txt b/cmd/helm/testdata/output/version.txt
index 0d9b536e6..4b493d31c 100644
--- a/cmd/helm/testdata/output/version.txt
+++ b/cmd/helm/testdata/output/version.txt
@@ -1,1 +1,1 @@
-version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"", GitTreeState:"", GoVersion:""}
+version.BuildInfo{Version:"v3.0", GitCommit:"", GitTreeState:"", GoVersion:""}
diff --git a/pkg/chart/loader/archive_test.go b/pkg/chart/loader/archive_test.go
new file mode 100644
index 000000000..7d8c8b51e
--- /dev/null
+++ b/pkg/chart/loader/archive_test.go
@@ -0,0 +1,110 @@
+/*
+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 loader
+
+import (
+	"archive/tar"
+	"bytes"
+	"compress/gzip"
+	"testing"
+)
+
+func TestLoadArchiveFiles(t *testing.T) {
+	tcs := []struct {
+		name     string
+		generate func(w *tar.Writer)
+		check    func(t *testing.T, files []*BufferedFile, err error)
+	}{
+		{
+			name:     "empty input should return no files",
+			generate: func(w *tar.Writer) {},
+			check: func(t *testing.T, files []*BufferedFile, err error) {
+				if err.Error() != "no files in chart archive" {
+					t.Fatalf(`expected "no files in chart archive", got [%#v]`, err)
+				}
+			},
+		},
+		{
+			name: "should ignore files with XGlobalHeader type",
+			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{
+					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)
+				}
+
+				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{
+					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_header content`, err)
+				}
+
+				if len(files) != 1 {
+					t.Fatalf(`expected to get one file but got [%v]`, files)
+				}
+			},
+		},
+	}
+
+	for _, tc := range tcs {
+		t.Run(tc.name, func(t *testing.T) {
+			buf := &bytes.Buffer{}
+			gzw := gzip.NewWriter(buf)
+			tw := tar.NewWriter(gzw)
+
+			tc.generate(tw)
+
+			_ = tw.Close()
+			_ = gzw.Close()
+
+			files, err := LoadArchiveFiles(buf)
+			tc.check(t, files, err)
+		})
+	}
+}
diff --git a/pkg/chartutil/testdata/subpop/charts/subchart1/crds/crdA.yaml b/pkg/chartutil/testdata/subpop/charts/subchart1/crds/crdA.yaml
new file mode 100644
index 000000000..fca77fd4b
--- /dev/null
+++ b/pkg/chartutil/testdata/subpop/charts/subchart1/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/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go
index 80249e240..e0692c8c8 100644
--- a/pkg/downloader/chart_downloader_test.go
+++ b/pkg/downloader/chart_downloader_test.go
@@ -80,6 +80,67 @@ func TestResolveChartRef(t *testing.T) {
 	}
 }
 
+func TestResolveChartOpts(t *testing.T) {
+	tests := []struct {
+		name, ref, version string
+		expect             []getter.Option
+	}{
+		{
+			name: "repo with CA-file",
+			ref:  "testing-ca-file/foo",
+			expect: []getter.Option{
+				getter.WithURL("https://example.com/foo-1.2.3.tgz"),
+				getter.WithTLSClientConfig("cert", "key", "ca"),
+			},
+		},
+	}
+
+	c := ChartDownloader{
+		Out:              os.Stderr,
+		RepositoryConfig: repoConfig,
+		RepositoryCache:  repoCache,
+		Getters: getter.All(&cli.EnvSettings{
+			RepositoryConfig: repoConfig,
+			RepositoryCache:  repoCache,
+		}),
+	}
+
+	// snapshot options
+	snapshotOpts := c.Options
+
+	for _, tt := range tests {
+		// reset chart downloader options for each test case
+		c.Options = snapshotOpts
+
+		expect, err := getter.NewHTTPGetter(tt.expect...)
+		if err != nil {
+			t.Errorf("%s: failed to setup http client: %s", tt.name, err)
+			continue
+		}
+
+		u, err := c.ResolveChartVersion(tt.ref, tt.version)
+		if err != nil {
+			t.Errorf("%s: failed with error %s", tt.name, err)
+			continue
+		}
+
+		got, err := getter.NewHTTPGetter(
+			append(
+				c.Options,
+				getter.WithURL(u.String()),
+			)...,
+		)
+		if err != nil {
+			t.Errorf("%s: failed to create http client: %s", tt.name, err)
+			continue
+		}
+
+		if *(got.(*getter.HTTPGetter)) != *(expect.(*getter.HTTPGetter)) {
+			t.Errorf("%s: expected %s, got %s", tt.name, expect, got)
+		}
+	}
+}
+
 func TestVerifyChart(t *testing.T) {
 	v, err := VerifyChart("testdata/signtest-0.1.0.tgz", "testdata/helm-test-key.pub")
 	if err != nil {
diff --git a/pkg/downloader/manager_test.go b/pkg/downloader/manager_test.go
index 6e32b3e85..dd83c3dc2 100644
--- a/pkg/downloader/manager_test.go
+++ b/pkg/downloader/manager_test.go
@@ -181,6 +181,74 @@ func TestGetRepoNames(t *testing.T) {
 	}
 }
 
+func TestUpdateBeforeBuild(t *testing.T) {
+	// Set up a fake repo
+	srv, err := repotest.NewTempServer("testdata/*.tgz*")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer srv.Stop()
+	if err := srv.LinkIndices(); err != nil {
+		t.Fatal(err)
+	}
+	dir := func(p ...string) string {
+		return filepath.Join(append([]string{srv.Root()}, p...)...)
+	}
+
+	// Save dep
+	d := &chart.Chart{
+		Metadata: &chart.Metadata{
+			Name:       "dep-chart",
+			Version:    "0.1.0",
+			APIVersion: "v1",
+		},
+	}
+	if err := chartutil.SaveDir(d, dir()); err != nil {
+		t.Fatal(err)
+	}
+	// Save a chart
+	c := &chart.Chart{
+		Metadata: &chart.Metadata{
+			Name:       "with-dependency",
+			Version:    "0.1.0",
+			APIVersion: "v1",
+			Dependencies: []*chart.Dependency{{
+				Name:       d.Metadata.Name,
+				Version:    ">=0.1.0",
+				Repository: "file://../dep-chart",
+			}},
+		},
+	}
+	if err := chartutil.SaveDir(c, dir()); err != nil {
+		t.Fatal(err)
+	}
+
+	// Set-up a manager
+	b := bytes.NewBuffer(nil)
+	g := getter.Providers{getter.Provider{
+		Schemes: []string{"http", "https"},
+		New:     getter.NewHTTPGetter,
+	}}
+	m := &Manager{
+		ChartPath:        dir(c.Metadata.Name),
+		Out:              b,
+		Getters:          g,
+		RepositoryConfig: dir("repositories.yaml"),
+		RepositoryCache:  dir(),
+	}
+
+	// Update before Build. see issue: https://github.com/helm/helm/issues/7101
+	err = m.Update()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = m.Build()
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
 // This function is the skeleton test code of failing tests for #6416 and #6871 and bugs due to #5874.
 //
 // This function is used by below tests that ensures success of build operation
diff --git a/pkg/downloader/testdata/repositories.yaml b/pkg/downloader/testdata/repositories.yaml
index 374d95c8a..430865269 100644
--- a/pkg/downloader/testdata/repositories.yaml
+++ b/pkg/downloader/testdata/repositories.yaml
@@ -15,4 +15,9 @@ repositories:
   - name: testing-relative
     url: "http://example.com/helm"
   - name: testing-relative-trailing-slash
-    url: "http://example.com/helm/"
\ No newline at end of file
+    url: "http://example.com/helm/"
+  - name: testing-ca-file
+    url: "https://example.com"
+    certFile: "cert"
+    keyFile: "key"
+    caFile: "ca"
diff --git a/pkg/downloader/testdata/repository/testing-ca-file-index.yaml b/pkg/downloader/testdata/repository/testing-ca-file-index.yaml
new file mode 100644
index 000000000..17cdde1c6
--- /dev/null
+++ b/pkg/downloader/testdata/repository/testing-ca-file-index.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1
+entries:
+  foo:
+    - name: foo
+      description: Foo Chart
+      home: https://helm.sh/helm
+      keywords: []
+      maintainers: []
+      sources:
+        - https://github.com/helm/charts
+      urls:
+        - https://example.com/foo-1.2.3.tgz
+      version: 1.2.3
+      checksum: 0e6661f193211d7a5206918d42f5c2a9470b737d
diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go
index 031527dd0..f3609fcbd 100644
--- a/pkg/engine/engine_test.go
+++ b/pkg/engine/engine_test.go
@@ -460,6 +460,15 @@ func TestAlterFuncMap_include(t *testing.T) {
 		},
 	}
 
+	// Check nested reference in include FuncMap
+	d := &chart.Chart{
+		Metadata: &chart.Metadata{Name: "nested"},
+		Templates: []*chart.File{
+			{Name: "templates/quote", Data: []byte(`{{include "nested/templates/quote" . | indent 2}} dead.`)},
+			{Name: "templates/_partial", Data: []byte(`{{.Release.Name}} - he`)},
+		},
+	}
+
 	v := chartutil.Values{
 		"Values": "",
 		"Chart":  c.Metadata,
@@ -477,6 +486,12 @@ func TestAlterFuncMap_include(t *testing.T) {
 	if got := out["conrad/templates/quote"]; got != expect {
 		t.Errorf("Expected %q, got %q (%v)", expect, got, out)
 	}
+
+	_, err = Render(d, v)
+	expectErrName := "nested/templates/quote"
+	if err == nil {
+		t.Errorf("Expected err of nested reference name: %v", expectErrName)
+	}
 }
 
 func TestAlterFuncMap_require(t *testing.T) {
diff --git a/pkg/lint/lint_test.go b/pkg/lint/lint_test.go
index b770704c6..2a982d088 100644
--- a/pkg/lint/lint_test.go
+++ b/pkg/lint/lint_test.go
@@ -35,12 +35,12 @@ const goodChartDir = "rules/testdata/goodone"
 
 func TestBadChart(t *testing.T) {
 	m := All(badChartDir, values, namespace, strict).Messages
-	if len(m) != 8 {
+	if len(m) != 7 {
 		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, e6 bool
+	var i, w, e, e2, e3, e4, e5 bool
 	for _, msg := range m {
 		if msg.Severity == support.InfoSev {
 			if strings.Contains(msg.Err.Error(), "icon is recommended") {
@@ -59,24 +59,21 @@ func TestBadChart(t *testing.T) {
 			if strings.Contains(msg.Err.Error(), "name is required") {
 				e2 = true
 			}
-			if strings.Contains(msg.Err.Error(), "directory name (badchartfile) and chart name () must be the same") {
-				e3 = true
-			}
 
 			if strings.Contains(msg.Err.Error(), "apiVersion is required. The value must be either \"v1\" or \"v2\"") {
-				e4 = true
+				e3 = true
 			}
 
 			if strings.Contains(msg.Err.Error(), "chart type is not valid in apiVersion") {
-				e5 = true
+				e4 = true
 			}
 
 			if strings.Contains(msg.Err.Error(), "dependencies are not valid in the Chart file with apiVersion") {
-				e6 = true
+				e5 = true
 			}
 		}
 	}
-	if !e || !e2 || !e3 || !e4 || !e5 || !e6 || !w || !i {
+	if !e || !e2 || !e3 || !e4 || !e5 || !w || !i {
 		t.Errorf("Didn't find all the expected errors, got %#v", m)
 	}
 }
diff --git a/pkg/lint/rules/chartfile_test.go b/pkg/lint/rules/chartfile_test.go
index ff2a63583..d032dd12f 100644
--- a/pkg/lint/rules/chartfile_test.go
+++ b/pkg/lint/rules/chartfile_test.go
@@ -30,18 +30,15 @@ import (
 )
 
 const (
-	badChartDir  = "testdata/badchartfile"
-	goodChartDir = "testdata/goodone"
+	badChartDir = "testdata/badchartfile"
 )
 
 var (
 	badChartFilePath         = filepath.Join(badChartDir, "Chart.yaml")
-	goodChartFilePath        = filepath.Join(goodChartDir, "Chart.yaml")
 	nonExistingChartFilePath = filepath.Join(os.TempDir(), "Chart.yaml")
 )
 
 var badChart, _ = chartutil.LoadChartfile(badChartFilePath)
-var goodChart, _ = chartutil.LoadChartfile(goodChartFilePath)
 
 // Validation functions Test
 func TestValidateChartYamlNotDirectory(t *testing.T) {
@@ -73,24 +70,6 @@ func TestValidateChartName(t *testing.T) {
 	}
 }
 
-func TestValidateChartNameDirMatch(t *testing.T) {
-	err := validateChartNameDirMatch(goodChartDir, goodChart)
-	if err != nil {
-		t.Errorf("validateChartNameDirMatch to return no error, gor a linter error")
-	}
-	// It has not name
-	err = validateChartNameDirMatch(badChartDir, badChart)
-	if err == nil {
-		t.Errorf("validatechartnamedirmatch to return a linter error, got no error")
-	}
-
-	// Wrong path
-	err = validateChartNameDirMatch(badChartDir, goodChart)
-	if err == nil {
-		t.Errorf("validatechartnamedirmatch to return a linter error, got no error")
-	}
-}
-
 func TestValidateChartVersion(t *testing.T) {
 	var failTest = []struct {
 		Version  string
@@ -209,36 +188,32 @@ func TestChartfile(t *testing.T) {
 	Chartfile(&linter)
 	msgs := linter.Messages
 
-	if len(msgs) != 7 {
-		t.Errorf("Expected 7 errors, got %d", len(msgs))
+	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[1].Err.Error(), "directory name (badchartfile) and chart name () must be the same") {
+	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(), "apiVersion is required. The value must be either \"v1\" or \"v2\"") {
+	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(), "version '0.0.0.0' is not a valid SemVer") {
+	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(), "icon is recommended") {
+	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(), "chart type is not valid in apiVersion") {
+	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[6].Err.Error(), "dependencies are not valid in the Chart file with apiVersion") {
-		t.Errorf("Unexpected message 6: %s", msgs[6].Err)
-	}
-
 }