Repository: helm/helm (go)

Issue:
Error: Chart.lock is out of sync with Chart.yaml when using dependencies and version ranges
Output of `helm version`:
```
$ helm version
version.BuildInfo{Version:"v3.0.0", GitCommit:"e29ce2a54e96cd02ccfce88bee4f58bb6e2a28b6", GitTreeState:"clean", GoVersion:"go1.13.4"}
```

This is what I am experiencing, easily recreated as below:
```
 $ helm create 1
Creating 1
 $ helm create 2
Creating 2
 $ vim 2/Chart.yaml
```
and add to the chart:
```
dependencies:
- name: 1
  repository: file://../1
  version: ^0.1.0
- name: mysql
  condition: mysql.enabled
  repository: https://kubernetes-charts.storage.googleapis.com
  version: ^1.4.0
- name: redis
  condition: redis.enabled
  repository: https://kubernetes-charts.storage.googleapis.com
  version: ^3.0.0
```

and then:
```
 $ helm dep up 2
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "incubator" chart repository
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈Happy Helming!⎈
Saving 3 charts
Downloading mysql from repo https://kubernetes-charts.storage.googleapis.com
Downloading redis from repo https://kubernetes-charts.storage.googleapis.com
Deleting outdated charts
 $ helm dep build 2
Error: Chart.lock is out of sync with Chart.yaml
```

Any ideas?



Pull request description:
fix "Chart.lock is out of sync with Chart.yaml"
fixed #7101

I have found that downloadAll() might overwrite version in Chart.lock.

It's because this function will download a specific version of chart to dir "charts/" and then the specific version will overwrite the version in Chart.lock.

My solution is recalculate lock digest after downloadAll().



Patch:
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
 	}
 


Test patch:
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/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) {