Repository: helm/helm (go)

Issue:
Helm does not handle template errors
### Steps to reproduce

```sh
helm create bar
echo '{{ .Values.bad.doh }}' > bar/templates/foo.yaml
helm template ./bar/
```
### Expected result
Helm should return error and exist with non-zero exit code, as in previous versions:
```
1 ✗ (43.5ms) 09:45:19 invidian@dellxps15mateusz /tmp $ ./foo/linux-amd64/helm version
version.BuildInfo{Version:"v3.0.3", GitCommit:"ac925eb7279f4a6955df663a0128044a8a6b7593", GitTreeState:"clean", GoVersion:"go1.13.6"}
0 ✓ (52.6ms) 09:47:39 invidian@dellxps15mateusz /tmp $ ./foo/linux-amd64/helm template ./bar/
Error: template: bar/templates/foo.yaml:1:10: executing "bar/templates/foo.yaml" at <.Values.bad.doh>: nil pointer evaluating interface {}.doh
1 ✗ (52.0ms) 09:47:41 invidian@dellxps15mateusz /tmp $
```

### Actual output
Helm does not print any warning and exits gracefully:
```
1 ✗ (52.0ms) 09:47:41 invidian@dellxps15mateusz /tmp $ helm version
version.BuildInfo{Version:"v3.1.0", GitCommit:"b29d20baf09943e134c2fa5e1e1cab3bf93315fa", GitTreeState:"clean", GoVersion:"go1.13.7"}
0 ✓ (49.1ms) 09:47:53 invidian@dellxps15mateusz /tmp $ helm template ./bar/

0 ✓ (49.6ms) 09:47:55 invidian@dellxps15mateusz /tmp $
```

Output of `helm version`:
```
version.BuildInfo{Version:"v3.1.0", GitCommit:"b29d20baf09943e134c2fa5e1e1cab3bf93315fa", GitTreeState:"clean", GoVersion:"go1.13.7"}
```




Pull request:
fix(render): Render error not being propagated
Errors when rendering templates are not being propagated up the stack. This means that any template issues like in #7593 would not return an error to the user and just fail silently and without any output. This PR fixes this.

Fixes #7593 

Patch:
diff --git a/pkg/action/install.go b/pkg/action/install.go
index 49c9b5728..79abfae33 100644
--- a/pkg/action/install.go
+++ b/pkg/action/install.go
@@ -460,7 +460,7 @@ func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values
 	}
 
 	if err2 != nil {
-		return hs, b, "", err
+		return hs, b, "", err2
 	}
 
 	// NOTES.txt gets rendered like all the other files, but because it's not a hook nor a resource,


Test patch:
diff --git a/pkg/action/action_test.go b/pkg/action/action_test.go
index df6a48e7f..36ef261a3 100644
--- a/pkg/action/action_test.go
+++ b/pkg/action/action_test.go
@@ -230,6 +230,20 @@ func withSampleTemplates() chartOption {
 	}
 }
 
+func withSampleIncludingIncorrectTemplates() chartOption {
+	return func(opts *chartOptions) {
+		sampleTemplates := []*chart.File{
+			// This adds basic templates and partials.
+			{Name: "templates/goodbye", Data: []byte("goodbye: world")},
+			{Name: "templates/empty", Data: []byte("")},
+			{Name: "templates/incorrect", Data: []byte("{{ .Values.bad.doh }}")},
+			{Name: "templates/with-partials", Data: []byte(`hello: {{ template "_planet" . }}`)},
+			{Name: "templates/partials/_planet", Data: []byte(`{{define "_planet"}}Earth{{end}}`)},
+		}
+		opts.Templates = append(opts.Templates, sampleTemplates...)
+	}
+}
+
 func withMultipleManifestTemplate() chartOption {
 	return func(opts *chartOptions) {
 		sampleTemplates := []*chart.File{
diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go
index ba350819d..bf47895a1 100644
--- a/pkg/action/install_test.go
+++ b/pkg/action/install_test.go
@@ -240,6 +240,21 @@ func TestInstallRelease_DryRun(t *testing.T) {
 	is.Equal(res.Info.Description, "Dry run complete")
 }
 
+func TestInstallReleaseIncorrectTemplate_DryRun(t *testing.T) {
+	is := assert.New(t)
+	instAction := installAction(t)
+	instAction.DryRun = true
+	vals := map[string]interface{}{}
+	_, err := instAction.Run(buildChart(withSampleIncludingIncorrectTemplates()), vals)
+	expectedErr := "\"hello/templates/incorrect\" at <.Values.bad.doh>: nil pointer evaluating interface {}.doh"
+	if err == nil {
+		t.Fatalf("Install should fail containing error: %s", expectedErr)
+	}
+	if err != nil {
+		is.Contains(err.Error(), expectedErr)
+	}
+}
+
 func TestInstallRelease_NoHooks(t *testing.T) {
 	is := assert.New(t)
 	instAction := installAction(t)