Repository: helm/helm
Pull request #7208 (2019-12-11 16:06:04)

add Marc Khouzam as a core maintainer
Signed-off-by: Matthew Fisher <matt.fisher@microsoft.com>


Patch:
diff --git a/.golangci.yml b/.golangci.yml
index 2c3b6234d..601d98661 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -1,5 +1,5 @@
 run:
-  timeout: 2m
+  deadline: 2m
 
 linters:
   disable-all: true
diff --git a/Makefile b/Makefile
index 611222e28..e48a20fd5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,7 @@
-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
+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
 
 GOPATH        = $(shell go env GOPATH)
 DEP           = $(GOPATH)/bin/dep
@@ -139,20 +138,6 @@ 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/OWNERS b/OWNERS
index 715c8993d..d7dac5514 100644
--- a/OWNERS
+++ b/OWNERS
@@ -4,6 +4,7 @@ maintainers:
   - fibonacci1729
   - hickeyma
   - jdolitsky
+  - marckhouzam
   - mattfarina
   - michelleN
   - prydonius
diff --git a/README.md b/README.md
index 73fd189d7..9af358e10 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://img.shields.io/static/v1?label=godoc&message=reference&color=blue)](https://pkg.go.dev/helm.sh/helm/v3)
+[![GoDoc](https://godoc.org/helm.sh/helm?status.svg)](https://godoc.org/helm.sh/helm)
 [![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.
@@ -37,19 +37,19 @@ Unpack the `helm` binary and add it to your PATH and you are good to go!
 
 If you want to use a package manager:
 
-- [Homebrew](https://brew.sh/) users can use `brew install helm`.
+- [Homebrew](https://brew.sh/) users can use `brew install kubernetes-helm`.
 - [Chocolatey](https://chocolatey.org/) users can use `choco install kubernetes-helm`.
 - [Scoop](https://scoop.sh/) users can use `scoop install helm`.
 - [GoFish](https://gofi.sh/) users can use `gofish install helm`.
 
 To rapidly get Helm up and running, start with the [Quick Start Guide](https://docs.helm.sh/using_helm/#quickstart-guide).
 
-See the [installation guide](https://helm.sh/docs/intro/install/) for more options,
+See the [installation guide](https://docs.helm.sh/using_helm/#installing-helm) for more options,
 including installing pre-releases.
 
 ## Docs
 
-Get started with the [Quick Start guide](https://helm.sh/docs/intro/quickstart/) or plunge into the [complete documentation](https://helm.sh/docs)
+Get started with the [Quick Start guide](https://docs.helm.sh/using_helm/#quickstart-guide) or plunge into the [complete documentation](https://docs.helm.sh)
 
 ## Roadmap
 
diff --git a/cmd/helm/env.go b/cmd/helm/env.go
index 2687272ba..1b9cb4012 100644
--- a/cmd/helm/env.go
+++ b/cmd/helm/env.go
@@ -19,7 +19,6 @@ package main
 import (
 	"fmt"
 	"io"
-	"sort"
 
 	"helm.sh/helm/v3/pkg/cli"
 
@@ -56,18 +55,8 @@ type envOptions struct {
 }
 
 func (o *envOptions) run(out io.Writer) error {
-	envVars := o.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.Printf("%s=\"%s\"\n", k, envVars[k])
+	for k, v := range o.settings.EnvVars() {
+		fmt.Printf("%s=\"%s\"\n", k, v)
 	}
 	return nil
 }
diff --git a/cmd/helm/install.go b/cmd/helm/install.go
index 176250f84..40935db17 100644
--- a/cmd/helm/install.go
+++ b/cmd/helm/install.go
@@ -130,12 +130,11 @@ 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, only if that name is a deleted release which remains in the history. This is unsafe in production")
+	f.BoolVar(&client.Replace, "replace", false, "re-use the given name, even if that name is already used. 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 0da0c21d3..32501530d 100644
--- a/cmd/helm/list.go
+++ b/cmd/helm/list.go
@@ -77,15 +77,12 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 			client.SetStateMask()
 
 			results, err := client.Run()
-			if err != nil {
-				return err
-			}
 
 			if client.Short {
 				for _, res := range results {
 					fmt.Fprintln(out, res.Name)
 				}
-				return nil
+				return err
 			}
 
 			return outfmt.Write(out, newReleaseListWriter(results))
@@ -97,7 +94,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 (if 'helm uninstall --keep-history' was used)")
+	f.BoolVar(&client.Uninstalled, "uninstalled", false, "show uninstalled releases")
 	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 f2fb5c01d..53e082e96 100644
--- a/cmd/helm/load_plugins.go
+++ b/cmd/helm/load_plugins.go
@@ -127,7 +127,7 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) {
 func manuallyProcessArgs(args []string) ([]string, []string) {
 	known := []string{}
 	unknown := []string{}
-	kvargs := []string{"--kube-context", "--namespace", "-n", "--kubeconfig", "--registry-config", "--repository-cache", "--repository-config"}
+	kvargs := []string{"--kube-context", "--namespace", "--kubeconfig", "--registry-config", "--repository-cache", "--repository-config"}
 	knownArg := func(a string) bool {
 		for _, pre := range kvargs {
 			if strings.HasPrefix(a, pre+"=") {
@@ -136,26 +136,13 @@ func manuallyProcessArgs(args []string) ([]string, []string) {
 		}
 		return false
 	}
-
-	isKnown := func(v string) string {
-		for _, i := range kvargs {
-			if i == v {
-				return v
-			}
-		}
-		return ""
-	}
-
 	for i := 0; i < len(args); i++ {
 		switch a := args[i]; a {
 		case "--debug":
 			known = append(known, a)
-		case isKnown(a):
-			known = append(known, a)
+		case "--kube-context", "--namespace", "-n", "--kubeconfig", "--registry-config", "--repository-cache", "--repository-config":
+			known = append(known, a, args[i+1])
 			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 9f7961f95..dd4bb2d17 100644
--- a/cmd/helm/package.go
+++ b/cmd/helm/package.go
@@ -36,15 +36,10 @@ 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.
 
-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'.
+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.
 
-  $ 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.
+Versioned chart archives are used by Helm package repositories.
 `
 
 func newPackageCmd(out io.Writer) *cobra.Command {
diff --git a/cmd/helm/repo_add.go b/cmd/helm/repo_add.go
index e6afce3d5..1c84ad8d6 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"
-	"sigs.k8s.io/yaml"
+	"gopkg.in/yaml.v2"
 
 	"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 a47631c0d..5312d798f 100644
--- a/cmd/helm/template.go
+++ b/cmd/helm/template.go
@@ -44,7 +44,6 @@ 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
@@ -68,14 +67,7 @@ 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)
@@ -128,8 +120,6 @@ 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 7096d7873..27b5a8426 100644
--- a/cmd/helm/uninstall.go
+++ b/cmd/helm/uninstall.go
@@ -69,7 +69,6 @@ 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 dce8ad74f..eadc3b63d 100644
--- a/cmd/helm/upgrade.go
+++ b/cmd/helm/upgrade.go
@@ -156,7 +156,6 @@ 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 91ccaf035..0d15c00cf 100644
--- a/code-of-conduct.md
+++ b/code-of-conduct.md
@@ -1,3 +1,3 @@
-# Community Code of Conduct
+# Kubernetes Community Code of Conduct
 
-Helm follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
+Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)
diff --git a/internal/tlsutil/cfg.go b/internal/tlsutil/cfg.go
index 8b9d4329f..f40258739 100644
--- a/internal/tlsutil/cfg.go
+++ b/internal/tlsutil/cfg.go
@@ -27,14 +27,18 @@ import (
 // Options represents configurable options used to create client and server TLS configurations.
 type Options struct {
 	CaCertFile string
-	// If either the KeyFile or CertFile is empty, ClientConfig() will not load them.
+	// If either the KeyFile or CertFile is empty, ClientConfig() will not load them,
+	// preventing Helm from authenticating to Tiller. They are required to be non-empty
+	// when calling ServerConfig, otherwise an error is returned.
 	KeyFile  string
 	CertFile string
 	// Client-only options
 	InsecureSkipVerify bool
+	// Server-only options
+	ClientAuth tls.ClientAuthType
 }
 
-// ClientConfig returns a TLS configuration for use by a Helm client.
+// ClientConfig retusn a TLS configuration for use by a Helm client.
 func ClientConfig(opts Options) (cfg *tls.Config, err error) {
 	var cert *tls.Certificate
 	var pool *x509.CertPool
@@ -56,3 +60,24 @@ func ClientConfig(opts Options) (cfg *tls.Config, err error) {
 	cfg = &tls.Config{InsecureSkipVerify: opts.InsecureSkipVerify, Certificates: []tls.Certificate{*cert}, RootCAs: pool}
 	return cfg, nil
 }
+
+// ServerConfig returns a TLS configuration for use by the Tiller server.
+func ServerConfig(opts Options) (cfg *tls.Config, err error) {
+	var cert *tls.Certificate
+	var pool *x509.CertPool
+
+	if cert, err = CertFromFilePair(opts.CertFile, opts.KeyFile); err != nil {
+		if os.IsNotExist(err) {
+			return nil, errors.Wrapf(err, "could not load x509 key pair (cert: %q, key: %q)", opts.CertFile, opts.KeyFile)
+		}
+		return nil, errors.Wrapf(err, "could not read x509 key pair (cert: %q, key: %q)", opts.CertFile, opts.KeyFile)
+	}
+	if opts.ClientAuth >= tls.VerifyClientCertIfGiven && opts.CaCertFile != "" {
+		if pool, err = CertPoolFromFile(opts.CaCertFile); err != nil {
+			return nil, err
+		}
+	}
+
+	cfg = &tls.Config{MinVersion: tls.VersionTLS12, ClientAuth: opts.ClientAuth, Certificates: []tls.Certificate{*cert}, ClientCAs: pool}
+	return cfg, nil
+}
diff --git a/internal/version/version.go b/internal/version/version.go
index 22439d11b..131a2b130 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 = ""
+	metadata = "unreleased"
 	// 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 9c32db213..5bc3a7005 100644
--- a/pkg/action/get_values.go
+++ b/pkg/action/get_values.go
@@ -39,10 +39,6 @@ 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 89a343a6f..8f1b5528b 100644
--- a/pkg/action/install.go
+++ b/pkg/action/install.go
@@ -79,7 +79,6 @@ type Install struct {
 	ReleaseName      string
 	GenerateName     bool
 	NameTemplate     string
-	Description      string
 	OutputDir        string
 	Atomic           bool
 	SkipCRDs         bool
@@ -87,8 +86,6 @@ 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
@@ -129,7 +126,7 @@ func (i *Install) installCRDs(crds []*chart.File) error {
 				i.cfg.Log("CRD %s is already present. Skipping.", crdName)
 				continue
 			}
-			return errors.Wrapf(err, "failed to install CRD %s", obj.Name)
+			return errors.Wrapf(err, "failed to instal CRD %s", obj.Name)
 		}
 		totalItems = append(totalItems, res...)
 	}
@@ -200,14 +197,11 @@ 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: !isUpgrade,
-		IsUpgrade: isUpgrade,
+		IsInstall: true,
 	}
 	valuesToRender, err := chartutil.ToRenderValues(chrt, vals, options, caps)
 	if err != nil {
@@ -243,7 +237,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 {
 		if err := existingResourceConflict(resources); err != nil {
 			return nil, errors.Wrap(err, "rendered manifests contain a resource that already exists. Unable to continue with install")
 		}
@@ -298,11 +292,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
 		}
 	}
 
-	if len(i.Description) > 0 {
-		rel.SetStatus(release.StatusDeployed, i.Description)
-	} else {
-		rel.SetStatus(release.StatusDeployed, "Install complete")
-	}
+	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
@@ -311,9 +301,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
 	//
 	// One possible strategy would be to do a timed retry to see if we can get
 	// this stored in the future.
-	if err := i.recordRelease(rel); err != nil {
-		i.cfg.Log("failed to record the release: %s", err)
-	}
+	i.recordRelease(rel)
 
 	return rel, nil
 }
@@ -432,7 +420,7 @@ func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values
 
 	if ch.Metadata.KubeVersion != "" {
 		if !chartutil.IsCompatibleRange(ch.Metadata.KubeVersion, caps.KubeVersion.String()) {
-			return hs, b, "", errors.Errorf("chart requires kubeVersion: %s which is incompatible with Kubernetes %s", ch.Metadata.KubeVersion, caps.KubeVersion.String())
+			return hs, b, "", errors.Errorf("chart requires kubernetesVersion: %s which is incompatible with Kubernetes %s", ch.Metadata.KubeVersion, caps.KubeVersion.String())
 		}
 	}
 
diff --git a/pkg/action/pull.go b/pkg/action/pull.go
index b0a3d2598..aaf63861e 100644
--- a/pkg/action/pull.go
+++ b/pkg/action/pull.go
@@ -63,7 +63,6 @@ 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 dfaa98472..fb72a845b 100644
--- a/pkg/action/uninstall.go
+++ b/pkg/action/uninstall.go
@@ -37,7 +37,6 @@ type Uninstall struct {
 	DryRun       bool
 	KeepHistory  bool
 	Timeout      time.Duration
-	Description  string
 }
 
 // NewUninstall creates a new Uninstall object with the given configuration.
@@ -119,11 +118,7 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error)
 	}
 
 	rel.Info.Status = release.StatusUninstalled
-	if len(u.Description) > 0 {
-		rel.Info.Description = u.Description
-	} else {
-		rel.Info.Description = "Uninstallation complete"
-	}
+	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 cdc40eaaa..d0495a864 100644
--- a/pkg/action/upgrade.go
+++ b/pkg/action/upgrade.go
@@ -58,7 +58,6 @@ type Upgrade struct {
 	Atomic        bool
 	CleanupOnFail bool
 	SubNotes      bool
-	Description   string
 }
 
 // NewUpgrade creates a new Upgrade object with the given configuration.
@@ -219,11 +218,7 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea
 
 	if u.DryRun {
 		u.cfg.Log("dry run for %s", upgradedRelease.Name)
-		if len(u.Description) > 0 {
-			upgradedRelease.Info.Description = u.Description
-		} else {
-			upgradedRelease.Info.Description = "Dry run complete"
-		}
+		upgradedRelease.Info.Description = "Dry run complete"
 		return upgradedRelease, nil
 	}
 
@@ -275,11 +270,7 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea
 	u.cfg.recordRelease(originalRelease)
 
 	upgradedRelease.Info.Status = release.StatusDeployed
-	if len(u.Description) > 0 {
-		upgradedRelease.Info.Description = u.Description
-	} else {
-		upgradedRelease.Info.Description = "Upgrade complete"
-	}
+	upgradedRelease.Info.Description = "Upgrade complete"
 
 	return upgradedRelease, nil
 }
diff --git a/pkg/chart/loader/archive.go b/pkg/chart/loader/archive.go
index 7e187a170..3c50fe379 100644
--- a/pkg/chart/loader/archive.go
+++ b/pkg/chart/loader/archive.go
@@ -126,12 +126,6 @@ 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 f3d4321c5..8e251bc89 100644
--- a/pkg/downloader/chart_downloader.go
+++ b/pkg/downloader/chart_downloader.go
@@ -214,10 +214,6 @@ 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 81dd53614..407e7ffe4 100644
--- a/pkg/downloader/manager.go
+++ b/pkg/downloader/manager.go
@@ -79,12 +79,7 @@ func (m *Manager) Build() error {
 		return m.Update()
 	}
 
-	// Check that all of the repos we're dependent on actually exist.
 	req := c.Metadata.Dependencies
-	if _, err := m.resolveRepoNames(req); err != nil {
-		return err
-	}
-
 	if sum, err := resolver.HashReq(req, lock.Dependencies); err != nil || sum != lock.Digest {
 		return errors.New("Chart.lock is out of sync with Chart.yaml")
 	}
@@ -125,7 +120,7 @@ func (m *Manager) Update() error {
 
 	// Check that all of the repos we're dependent on actually exist and
 	// the repo index names.
-	repoNames, err := m.resolveRepoNames(req)
+	repoNames, err := m.getRepoNames(req)
 	if err != nil {
 		return err
 	}
@@ -149,13 +144,6 @@ 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 {
@@ -384,9 +372,8 @@ Loop:
 	return nil
 }
 
-// resolveRepoNames returns the repo names of the referenced deps which can be used to fetch the cached index file
-// and replaces aliased repository URLs into resolved URLs in dependencies.
-func (m *Manager) resolveRepoNames(deps []*chart.Dependency) (map[string]string, error) {
+// getRepoNames returns the repo names of the referenced deps which can be used to fetch the cahced index file.
+func (m *Manager) getRepoNames(deps []*chart.Dependency) (map[string]string, error) {
 	rf, err := loadRepoConfig(m.RepositoryConfig)
 	if err != nil {
 		if os.IsNotExist(err) {
diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go
index 5a7d54993..dae0b6be7 100644
--- a/pkg/engine/engine.go
+++ b/pkg/engine/engine.go
@@ -93,19 +93,11 @@ 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/kube/wait.go b/pkg/kube/wait.go
index f0005a61e..7198917c4 100644
--- a/pkg/kube/wait.go
+++ b/pkg/kube/wait.go
@@ -27,7 +27,6 @@ import (
 	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 	extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
-	apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
@@ -115,17 +114,6 @@ func (w *waiter) waitForResources(created ResourceList) error {
 				if err := scheme.Scheme.Convert(v.Object, crd, nil); err != nil {
 					return false, err
 				}
-				if !w.crdBetaReady(*crd) {
-					return false, nil
-				}
-			case *apiextv1.CustomResourceDefinition:
-				if err := v.Get(); err != nil {
-					return false, err
-				}
-				crd := &apiextv1.CustomResourceDefinition{}
-				if err := scheme.Scheme.Convert(v.Object, crd, nil); err != nil {
-					return false, err
-				}
 				if !w.crdReady(*crd) {
 					return false, nil
 				}
@@ -241,10 +229,7 @@ func (w *waiter) daemonSetReady(ds *appsv1.DaemonSet) bool {
 	return true
 }
 
-// Because the v1 extensions API is not available on all supported k8s versions
-// yet and because Go doesn't support generics, we need to have a duplicate
-// function to support the v1beta1 types
-func (w *waiter) crdBetaReady(crd apiextv1beta1.CustomResourceDefinition) bool {
+func (w *waiter) crdReady(crd apiextv1beta1.CustomResourceDefinition) bool {
 	for _, cond := range crd.Status.Conditions {
 		switch cond.Type {
 		case apiextv1beta1.Established:
@@ -264,26 +249,6 @@ func (w *waiter) crdBetaReady(crd apiextv1beta1.CustomResourceDefinition) bool {
 	return false
 }
 
-func (w *waiter) crdReady(crd apiextv1.CustomResourceDefinition) bool {
-	for _, cond := range crd.Status.Conditions {
-		switch cond.Type {
-		case apiextv1.Established:
-			if cond.Status == apiextv1.ConditionTrue {
-				return true
-			}
-		case apiextv1.NamesAccepted:
-			if cond.Status == apiextv1.ConditionFalse {
-				// This indicates a naming conflict, but it's probably not the
-				// job of this function to fail because of that. Instead,
-				// we treat it as a success, since the process should be able to
-				// continue.
-				return true
-			}
-		}
-	}
-	return false
-}
-
 func (w *waiter) statefulSetReady(sts *appsv1.StatefulSet) bool {
 	// If the update strategy is not a rolling update, there will be nothing to wait for
 	if sts.Spec.UpdateStrategy.Type != appsv1.RollingUpdateStatefulSetStrategyType {
diff --git a/pkg/lint/rules/chartfile.go b/pkg/lint/rules/chartfile.go
index 70cb83bc5..35bb81571 100644
--- a/pkg/lint/rules/chartfile.go
+++ b/pkg/lint/rules/chartfile.go
@@ -46,6 +46,7 @@ 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))
@@ -81,6 +82,13 @@ 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 5d16779f1..6032eb063 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. Try providing a keyring with secret keys")
+		return errors.New("provided key is not a private key")
 	}
 
 	// 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. Try providing a keyring with secret keys")
+		return "", errors.New("provided key is not a private key")
 	}
 
 	if fi, err := os.Stat(chartpath); err != nil {
diff --git a/scripts/get b/scripts/get
index 711635ee3..3f645f807 100755
--- a/scripts/get
+++ b/scripts/get
@@ -78,16 +78,13 @@ verifySupported() {
 # checkDesiredVersion checks if the desired version is available.
 checkDesiredVersion() {
   if [ "x$DESIRED_VERSION" == "x" ]; then
-    # FIXME(bacongobbler): hard code the desired version for the time being.
-    # A better fix would be to filter for Helm 2 release pages.
-    TAG="v2.16.1"
     # Get tag from release URL
-    # local latest_release_url="https://github.com/helm/helm/releases/latest"
-    # if type "curl" > /dev/null; then
-    #   TAG=$(curl -Ls -o /dev/null -w %{url_effective} $latest_release_url | grep -oE "[^/]+$" )
-    # elif type "wget" > /dev/null; then
-    #   TAG=$(wget $latest_release_url --server-response -O /dev/null 2>&1 | awk '/^  Location: /{DEST=$2} END{ print DEST}' | grep -oE "[^/]+$")
-    # fi
+    local latest_release_url="https://github.com/helm/helm/releases/latest"
+    if type "curl" > /dev/null; then
+      TAG=$(curl -Ls -o /dev/null -w %{url_effective} $latest_release_url | grep -oE "[^/]+$" )
+    elif type "wget" > /dev/null; then
+      TAG=$(wget $latest_release_url --server-response -O /dev/null 2>&1 | awk '/^  Location: /{DEST=$2} END{ print DEST}' | grep -oE "[^/]+$")
+    fi
   else
     TAG=$DESIRED_VERSION
   fi
@@ -190,7 +187,7 @@ testVersion() {
 help () {
   echo "Accepted cli arguments are:"
   echo -e "\t[--help|-h ] ->> prints this help"
-  echo -e "\t[--version|-v <desired_version>]"
+  echo -e "\t[--version|-v <desired_version>] . When not defined it defaults to latest"
   echo -e "\te.g. --version v2.4.0  or -v latest"
   echo -e "\t[--no-sudo]  ->> install without sudo"
 }
diff --git a/scripts/get-helm-3 b/scripts/get-helm-3
deleted file mode 100755
index c1655a68e..000000000
--- a/scripts/get-helm-3
+++ /dev/null
@@ -1,236 +0,0 @@
-#!/usr/bin/env bash
-
-# 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.
-
-# The install script is based off of the MIT-licensed script from glide,
-# the package manager for Go: https://github.com/Masterminds/glide.sh/blob/master/get
-
-PROJECT_NAME="helm"
-
-: ${USE_SUDO:="true"}
-: ${HELM_INSTALL_DIR:="/usr/local/bin"}
-
-# initArch discovers the architecture for this system.
-initArch() {
-  ARCH=$(uname -m)
-  case $ARCH in
-    armv5*) ARCH="armv5";;
-    armv6*) ARCH="armv6";;
-    armv7*) ARCH="arm";;
-    aarch64) ARCH="arm64";;
-    x86) ARCH="386";;
-    x86_64) ARCH="amd64";;
-    i686) ARCH="386";;
-    i386) ARCH="386";;
-  esac
-}
-
-# initOS discovers the operating system for this system.
-initOS() {
-  OS=$(echo `uname`|tr '[:upper:]' '[:lower:]')
-
-  case "$OS" in
-    # Minimalist GNU for Windows
-    mingw*) OS='windows';;
-  esac
-}
-
-# runs the given command as root (detects if we are root already)
-runAsRoot() {
-  local CMD="$*"
-
-  if [ $EUID -ne 0 -a $USE_SUDO = "true" ]; then
-    CMD="sudo $CMD"
-  fi
-
-  $CMD
-}
-
-# 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"
-  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"
-    exit 1
-  fi
-
-  if ! type "curl" > /dev/null && ! type "wget" > /dev/null; then
-    echo "Either curl or wget is required"
-    exit 1
-  fi
-}
-
-# checkDesiredVersion checks if the desired version is available.
-checkDesiredVersion() {
-  if [ "x$DESIRED_VERSION" == "x" ]; then
-    # Get tag from release URL
-    local latest_release_url="https://github.com/helm/helm/releases/latest"
-    if type "curl" > /dev/null; then
-      TAG=$(curl -Ls -o /dev/null -w %{url_effective} $latest_release_url | grep -oE "[^/]+$" )
-    elif type "wget" > /dev/null; then
-      TAG=$(wget $latest_release_url --server-response -O /dev/null 2>&1 | awk '/^  Location: /{DEST=$2} END{ print DEST}' | grep -oE "[^/]+$")
-    fi
-  else
-    TAG=$DESIRED_VERSION
-  fi
-}
-
-# checkHelmInstalledVersion checks which version of helm is installed and
-# if it needs to be changed.
-checkHelmInstalledVersion() {
-  if [[ -f "${HELM_INSTALL_DIR}/${PROJECT_NAME}" ]]; then
-    local version=$("${HELM_INSTALL_DIR}/${PROJECT_NAME}" version --template="{{ .Version }}")
-    if [[ "$version" == "$TAG" ]]; then
-      echo "Helm ${version} is already ${DESIRED_VERSION:-latest}"
-      return 0
-    else
-      echo "Helm ${TAG} is available. Changing from version ${version}."
-      return 1
-    fi
-  else
-    return 1
-  fi
-}
-
-# downloadFile downloads the latest binary package and also the checksum
-# for that binary.
-downloadFile() {
-  HELM_DIST="helm-$TAG-$OS-$ARCH.tar.gz"
-  DOWNLOAD_URL="https://get.helm.sh/$HELM_DIST"
-  CHECKSUM_URL="$DOWNLOAD_URL.sha256"
-  HELM_TMP_ROOT="$(mktemp -dt helm-installer-XXXXXX)"
-  HELM_TMP_FILE="$HELM_TMP_ROOT/$HELM_DIST"
-  HELM_SUM_FILE="$HELM_TMP_ROOT/$HELM_DIST.sha256"
-  echo "Downloading $DOWNLOAD_URL"
-  if type "curl" > /dev/null; then
-    curl -SsL "$CHECKSUM_URL" -o "$HELM_SUM_FILE"
-  elif type "wget" > /dev/null; then
-    wget -q -O "$HELM_SUM_FILE" "$CHECKSUM_URL"
-  fi
-  if type "curl" > /dev/null; then
-    curl -SsL "$DOWNLOAD_URL" -o "$HELM_TMP_FILE"
-  elif type "wget" > /dev/null; then
-    wget -q -O "$HELM_TMP_FILE" "$DOWNLOAD_URL"
-  fi
-}
-
-# installFile verifies the SHA256 for the file, then unpacks and
-# installs it.
-installFile() {
-  HELM_TMP="$HELM_TMP_ROOT/$PROJECT_NAME"
-  local sum=$(openssl sha1 -sha256 ${HELM_TMP_FILE} | awk '{print $2}')
-  local expected_sum=$(cat ${HELM_SUM_FILE})
-  if [ "$sum" != "$expected_sum" ]; then
-    echo "SHA sum of ${HELM_TMP_FILE} does not match. Aborting."
-    exit 1
-  fi
-
-  mkdir -p "$HELM_TMP"
-  tar xf "$HELM_TMP_FILE" -C "$HELM_TMP"
-  HELM_TMP_BIN="$HELM_TMP/$OS-$ARCH/$PROJECT_NAME"
-  echo "Preparing to install $PROJECT_NAME into ${HELM_INSTALL_DIR}"
-  runAsRoot cp "$HELM_TMP_BIN" "$HELM_INSTALL_DIR"
-  echo "$PROJECT_NAME installed into $HELM_INSTALL_DIR/$PROJECT_NAME"
-}
-
-# fail_trap is executed if an error occurs.
-fail_trap() {
-  result=$?
-  if [ "$result" != "0" ]; then
-    if [[ -n "$INPUT_ARGUMENTS" ]]; then
-      echo "Failed to install $PROJECT_NAME with the arguments provided: $INPUT_ARGUMENTS"
-      help
-    else
-      echo "Failed to install $PROJECT_NAME"
-    fi
-    echo -e "\tFor support, go to https://github.com/helm/helm."
-  fi
-  cleanup
-  exit $result
-}
-
-# testVersion tests the installed client to make sure it is working.
-testVersion() {
-  set +e
-  HELM="$(which $PROJECT_NAME)"
-  if [ "$?" = "1" ]; then
-    echo "$PROJECT_NAME not found. Is $HELM_INSTALL_DIR on your "'$PATH?'
-    exit 1
-  fi
-  set -e
-}
-
-# help provides possible cli installation arguments
-help () {
-  echo "Accepted cli arguments are:"
-  echo -e "\t[--help|-h ] ->> prints this help"
-  echo -e "\t[--version|-v <desired_version>] . When not defined it fetches the latest release from GitHub"
-  echo -e "\te.g. --version v3.0.0 or -v canary"
-  echo -e "\t[--no-sudo]  ->> install without sudo"
-}
-
-# cleanup temporary files to avoid https://github.com/helm/helm/issues/2977
-cleanup() {
-  if [[ -d "${HELM_TMP_ROOT:-}" ]]; then
-    rm -rf "$HELM_TMP_ROOT"
-  fi
-}
-
-# Execution
-
-#Stop execution on any error
-trap "fail_trap" EXIT
-set -e
-
-# Parsing input arguments (if any)
-export INPUT_ARGUMENTS="${@}"
-set -u
-while [[ $# -gt 0 ]]; do
-  case $1 in
-    '--version'|-v)
-       shift
-       if [[ $# -ne 0 ]]; then
-           export DESIRED_VERSION="${1}"
-       else
-           echo -e "Please provide the desired version. e.g. --version v3.0.0 or -v canary"
-           exit 0
-       fi
-       ;;
-    '--no-sudo')
-       USE_SUDO="false"
-       ;;
-    '--help'|-h)
-       help
-       exit 0
-       ;;
-    *) exit 1
-       ;;
-  esac
-  shift
-done
-set +u
-
-initArch
-initOS
-verifySupported
-checkDesiredVersion
-if ! checkHelmInstalledVersion; then
-  downloadFile
-  installFile
-fi
-testVersion
-cleanup
diff --git a/scripts/validate-license.sh b/scripts/validate-license.sh
index dc247436f..00bd38ea2 100755
--- a/scripts/validate-license.sh
+++ b/scripts/validate-license.sh
@@ -27,16 +27,14 @@ find_files() {
   \( -name '*.go' -o -name '*.sh' \)
 }
 
-# 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")' || :))
+mapfile -t 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
 
-# Use "|| :" to ignore the error code when grep returns empty
-failed_copyright_header=($(find_files | xargs grep -L 'Copyright The Helm Authors.' || :))
+mapfile -t 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/plugin_test.go b/cmd/helm/plugin_test.go
index 3fd3a4197..7bc8fe70c 100644
--- a/cmd/helm/plugin_test.go
+++ b/cmd/helm/plugin_test.go
@@ -30,27 +30,14 @@ func TestManuallyProcessArgs(t *testing.T) {
 		"--debug",
 		"--foo", "bar",
 		"--kubeconfig=/home/foo",
-		"--kubeconfig", "/home/foo",
-		"--kube-context=test1",
 		"--kube-context", "test1",
-		"-n=test2",
 		"-n", "test2",
-		"--namespace=test2",
-		"--namespace", "test2",
 		"--home=/tmp",
 		"command",
 	}
 
 	expectKnown := []string{
-		"--debug",
-		"--kubeconfig=/home/foo",
-		"--kubeconfig", "/home/foo",
-		"--kube-context=test1",
-		"--kube-context", "test1",
-		"-n=test2",
-		"-n", "test2",
-		"--namespace=test2",
-		"--namespace", "test2",
+		"--debug", "--kubeconfig=/home/foo", "--kube-context", "test1", "-n", "test2",
 	}
 
 	expectUnknown := []string{
diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go
index 735829432..8aa2f6c06 100644
--- a/cmd/helm/template_test.go
+++ b/cmd/helm/template_test.go
@@ -79,11 +79,6 @@ 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
deleted file mode 100644
index 9fa1c7e6d..000000000
--- a/cmd/helm/testdata/output/template-with-crds.txt
+++ /dev/null
@@ -1,72 +0,0 @@
----
-# 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-client-shorthand.txt b/cmd/helm/testdata/output/version-client-shorthand.txt
index 4b493d31c..0d9b536e6 100644
--- a/cmd/helm/testdata/output/version-client-shorthand.txt
+++ b/cmd/helm/testdata/output/version-client-shorthand.txt
@@ -1,1 +1,1 @@
-version.BuildInfo{Version:"v3.0", GitCommit:"", GitTreeState:"", GoVersion:""}
+version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"", GitTreeState:"", GoVersion:""}
diff --git a/cmd/helm/testdata/output/version-client.txt b/cmd/helm/testdata/output/version-client.txt
index 4b493d31c..0d9b536e6 100644
--- a/cmd/helm/testdata/output/version-client.txt
+++ b/cmd/helm/testdata/output/version-client.txt
@@ -1,1 +1,1 @@
-version.BuildInfo{Version:"v3.0", GitCommit:"", GitTreeState:"", GoVersion:""}
+version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"", GitTreeState:"", GoVersion:""}
diff --git a/cmd/helm/testdata/output/version-short.txt b/cmd/helm/testdata/output/version-short.txt
index d9fb9c736..5e7749489 100644
--- a/cmd/helm/testdata/output/version-short.txt
+++ b/cmd/helm/testdata/output/version-short.txt
@@ -1,1 +1,1 @@
-v3.0
+v3.0+unreleased
diff --git a/cmd/helm/testdata/output/version-template.txt b/cmd/helm/testdata/output/version-template.txt
index 776c1919b..c12e29c2d 100644
--- a/cmd/helm/testdata/output/version-template.txt
+++ b/cmd/helm/testdata/output/version-template.txt
@@ -1,1 +1,1 @@
-Version: v3.0
\ No newline at end of file
+Version: v3.0+unreleased
\ No newline at end of file
diff --git a/cmd/helm/testdata/output/version.txt b/cmd/helm/testdata/output/version.txt
index 4b493d31c..0d9b536e6 100644
--- a/cmd/helm/testdata/output/version.txt
+++ b/cmd/helm/testdata/output/version.txt
@@ -1,1 +1,1 @@
-version.BuildInfo{Version:"v3.0", GitCommit:"", GitTreeState:"", GoVersion:""}
+version.BuildInfo{Version:"v3.0+unreleased", GitCommit:"", GitTreeState:"", GoVersion:""}
diff --git a/internal/tlsutil/tlsutil_test.go b/internal/tlsutil/tlsutil_test.go
index 24551fdec..a737226fd 100644
--- a/internal/tlsutil/tlsutil_test.go
+++ b/internal/tlsutil/tlsutil_test.go
@@ -17,6 +17,7 @@ limitations under the License.
 package tlsutil
 
 import (
+	"crypto/tls"
 	"path/filepath"
 	"testing"
 )
@@ -53,6 +54,26 @@ func TestClientConfig(t *testing.T) {
 	}
 }
 
+func TestServerConfig(t *testing.T) {
+	opts := Options{
+		CaCertFile: testfile(t, testCaCertFile),
+		CertFile:   testfile(t, testCertFile),
+		KeyFile:    testfile(t, testKeyFile),
+		ClientAuth: tls.RequireAndVerifyClientCert,
+	}
+
+	cfg, err := ServerConfig(opts)
+	if err != nil {
+		t.Fatalf("error building tls server config: %v", err)
+	}
+	if got := cfg.MinVersion; got != tls.VersionTLS12 {
+		t.Errorf("expecting TLS version 1.2, got %d", got)
+	}
+	if got := cfg.ClientCAs; got == nil {
+		t.Errorf("expecting non-nil CA pool")
+	}
+}
+
 func testfile(t *testing.T, file string) (path string) {
 	var err error
 	if path, err = filepath.Abs(filepath.Join(tlsTestDir, file)); err != nil {
diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go
index 4637a4b10..bb36b843d 100644
--- a/pkg/action/install_test.go
+++ b/pkg/action/install_test.go
@@ -306,7 +306,7 @@ func TestInstallRelease_KubeVersion(t *testing.T) {
 	vals = map[string]interface{}{}
 	_, err = instAction.Run(buildChart(withKube(">=99.0.0")), vals)
 	is.Error(err)
-	is.Contains(err.Error(), "chart requires kubeVersion")
+	is.Contains(err.Error(), "chart requires kubernetesVersion")
 }
 
 func TestInstallRelease_Wait(t *testing.T) {
diff --git a/pkg/chart/loader/archive_test.go b/pkg/chart/loader/archive_test.go
deleted file mode 100644
index 7d8c8b51e..000000000
--- a/pkg/chart/loader/archive_test.go
+++ /dev/null
@@ -1,110 +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 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
deleted file mode 100644
index fca77fd4b..000000000
--- a/pkg/chartutil/testdata/subpop/charts/subchart1/crds/crdA.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-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 e0692c8c8..80249e240 100644
--- a/pkg/downloader/chart_downloader_test.go
+++ b/pkg/downloader/chart_downloader_test.go
@@ -80,67 +80,6 @@ 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 dd83c3dc2..0c5c08615 100644
--- a/pkg/downloader/manager_test.go
+++ b/pkg/downloader/manager_test.go
@@ -161,7 +161,7 @@ func TestGetRepoNames(t *testing.T) {
 	}
 
 	for _, tt := range tests {
-		l, err := m.resolveRepoNames(tt.req)
+		l, err := m.getRepoNames(tt.req)
 		if err != nil {
 			if tt.err {
 				continue
@@ -181,76 +181,7 @@ 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 the skeleton test code of failing tests for #6416 and bugs due to #5874.
 // This function is used by below tests that ensures success of build operation
 // with optional fields, alias, condition, tags, and even with ranged version.
 // Parent chart includes local-subchart 0.1.0 subchart from a fake repository, by default.
@@ -352,11 +283,3 @@ func TestBuild_WithTags(t *testing.T) {
 		Tags: []string{"tag1", "tag2"},
 	})
 }
-
-// Failing test for #6871
-func TestBuild_WithRepositoryAlias(t *testing.T) {
-	// Dependency repository is aliased in Chart.yaml
-	checkBuildWithOptionalFields(t, "with-repository-alias", chart.Dependency{
-		Repository: "@test",
-	})
-}
diff --git a/pkg/downloader/testdata/repositories.yaml b/pkg/downloader/testdata/repositories.yaml
index 430865269..374d95c8a 100644
--- a/pkg/downloader/testdata/repositories.yaml
+++ b/pkg/downloader/testdata/repositories.yaml
@@ -15,9 +15,4 @@ repositories:
   - name: testing-relative
     url: "http://example.com/helm"
   - name: testing-relative-trailing-slash
-    url: "http://example.com/helm/"
-  - name: testing-ca-file
-    url: "https://example.com"
-    certFile: "cert"
-    keyFile: "key"
-    caFile: "ca"
+    url: "http://example.com/helm/"
\ No newline at end of file
diff --git a/pkg/downloader/testdata/repository/testing-ca-file-index.yaml b/pkg/downloader/testdata/repository/testing-ca-file-index.yaml
deleted file mode 100644
index 17cdde1c6..000000000
--- a/pkg/downloader/testdata/repository/testing-ca-file-index.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-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 f3609fcbd..031527dd0 100644
--- a/pkg/engine/engine_test.go
+++ b/pkg/engine/engine_test.go
@@ -460,15 +460,6 @@ 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,
@@ -486,12 +477,6 @@ 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 2a982d088..b770704c6 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) != 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
+	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") {
@@ -59,21 +59,24 @@ 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\"") {
-				e3 = true
+				e4 = true
 			}
 
 			if strings.Contains(msg.Err.Error(), "chart type is not valid in apiVersion") {
-				e4 = true
+				e5 = true
 			}
 
 			if strings.Contains(msg.Err.Error(), "dependencies are not valid in the Chart file with apiVersion") {
-				e5 = true
+				e6 = true
 			}
 		}
 	}
-	if !e || !e2 || !e3 || !e4 || !e5 || !w || !i {
+	if !e || !e2 || !e3 || !e4 || !e5 || !e6 || !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 d032dd12f..ff2a63583 100644
--- a/pkg/lint/rules/chartfile_test.go
+++ b/pkg/lint/rules/chartfile_test.go
@@ -30,15 +30,18 @@ import (
 )
 
 const (
-	badChartDir = "testdata/badchartfile"
+	badChartDir  = "testdata/badchartfile"
+	goodChartDir = "testdata/goodone"
 )
 
 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) {
@@ -70,6 +73,24 @@ 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
@@ -188,32 +209,36 @@ func TestChartfile(t *testing.T) {
 	Chartfile(&linter)
 	msgs := linter.Messages
 
-	if len(msgs) != 6 {
-		t.Errorf("Expected 6 errors, got %d", len(msgs))
+	if len(msgs) != 7 {
+		t.Errorf("Expected 7 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(), "apiVersion is required. The value must be either \"v1\" or \"v2\"") {
+	if !strings.Contains(msgs[1].Err.Error(), "directory name (badchartfile) and chart name () must be the same") {
 		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") {
+	if !strings.Contains(msgs[2].Err.Error(), "apiVersion is required. The value must be either \"v1\" or \"v2\"") {
 		t.Errorf("Unexpected message 2: %s", msgs[2].Err)
 	}
 
-	if !strings.Contains(msgs[3].Err.Error(), "icon is recommended") {
+	if !strings.Contains(msgs[3].Err.Error(), "version '0.0.0.0' is not a valid SemVer") {
 		t.Errorf("Unexpected message 3: %s", msgs[3].Err)
 	}
 
-	if !strings.Contains(msgs[4].Err.Error(), "chart type is not valid in apiVersion") {
+	if !strings.Contains(msgs[4].Err.Error(), "icon is recommended") {
 		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") {
+	if !strings.Contains(msgs[5].Err.Error(), "chart type is not valid in 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)
+	}
+
 }