Repository: helm/helm
Pull request #7556 (2020-02-07 19:15:09)

Fix 'helm template' to also print invalid yaml
Signed-off-by: Reinhard Naegele <unguiculus@gmail.com>


Patch:
diff --git a/cmd/helm/template.go b/cmd/helm/template.go
index 320718344..22565d3e3 100644
--- a/cmd/helm/template.go
+++ b/cmd/helm/template.go
@@ -64,57 +64,65 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
 			client.APIVersions = chartutil.VersionSet(extraAPIs)
 			client.IncludeCRDs = includeCrds
 			rel, err := runInstall(args, client, valueOpts, out)
-			if err != nil {
+
+			if err != nil && !settings.Debug {
+				if rel != nil {
+					return fmt.Errorf("%w\n\nUse --debug flag to render out invalid YAML", err)
+				}
 				return err
 			}
 
-			var manifests bytes.Buffer
-			fmt.Fprintln(&manifests, strings.TrimSpace(rel.Manifest))
+			// We ignore a potential error here because, when the --debug flag was specified,
+			// we always want to print the YAML, even if it is not valid. The error is still returned afterwards.
+			if rel != nil {
+				var manifests bytes.Buffer
+				fmt.Fprintln(&manifests, strings.TrimSpace(rel.Manifest))
 
-			if !client.DisableHooks {
-				for _, m := range rel.Hooks {
-					fmt.Fprintf(&manifests, "---\n# Source: %s\n%s\n", m.Path, m.Manifest)
+				if !client.DisableHooks {
+					for _, m := range rel.Hooks {
+						fmt.Fprintf(&manifests, "---\n# Source: %s\n%s\n", m.Path, m.Manifest)
+					}
 				}
-			}
 
-			// if we have a list of files to render, then check that each of the
-			// provided files exists in the chart.
-			if len(showFiles) > 0 {
-				splitManifests := releaseutil.SplitManifests(manifests.String())
-				manifestNameRegex := regexp.MustCompile("# Source: [^/]+/(.+)")
-				var manifestsToRender []string
-				for _, f := range showFiles {
-					missing := true
-					for _, manifest := range splitManifests {
-						submatch := manifestNameRegex.FindStringSubmatch(manifest)
-						if len(submatch) == 0 {
-							continue
+				// if we have a list of files to render, then check that each of the
+				// provided files exists in the chart.
+				if len(showFiles) > 0 {
+					splitManifests := releaseutil.SplitManifests(manifests.String())
+					manifestNameRegex := regexp.MustCompile("# Source: [^/]+/(.+)")
+					var manifestsToRender []string
+					for _, f := range showFiles {
+						missing := true
+						for _, manifest := range splitManifests {
+							submatch := manifestNameRegex.FindStringSubmatch(manifest)
+							if len(submatch) == 0 {
+								continue
+							}
+							manifestName := submatch[1]
+							// manifest.Name is rendered using linux-style filepath separators on Windows as
+							// well as macOS/linux.
+							manifestPathSplit := strings.Split(manifestName, "/")
+							manifestPath := filepath.Join(manifestPathSplit...)
+
+							// if the filepath provided matches a manifest path in the
+							// chart, render that manifest
+							if f == manifestPath {
+								manifestsToRender = append(manifestsToRender, manifest)
+								missing = false
+							}
 						}
-						manifestName := submatch[1]
-						// manifest.Name is rendered using linux-style filepath separators on Windows as
-						// well as macOS/linux.
-						manifestPathSplit := strings.Split(manifestName, "/")
-						manifestPath := filepath.Join(manifestPathSplit...)
-
-						// if the filepath provided matches a manifest path in the
-						// chart, render that manifest
-						if f == manifestPath {
-							manifestsToRender = append(manifestsToRender, manifest)
-							missing = false
+						if missing {
+							return fmt.Errorf("could not find template %s in chart", f)
 						}
 					}
-					if missing {
-						return fmt.Errorf("could not find template %s in chart", f)
+					for _, m := range manifestsToRender {
+						fmt.Fprintf(out, "---\n%s\n", m)
 					}
+				} else {
+					fmt.Fprintf(out, "%s", manifests.String())
 				}
-				for _, m := range manifestsToRender {
-					fmt.Fprintf(out, "---\n%s\n", m)
-				}
-			} else {
-				fmt.Fprintf(out, "%s", manifests.String())
 			}
 
-			return nil
+			return err
 		},
 	}
 


Test patch:
diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go
index dc7987d01..3fd139fad 100644
--- a/cmd/helm/template_test.go
+++ b/cmd/helm/template_test.go
@@ -102,6 +102,18 @@ func TestTemplateCmd(t *testing.T) {
 			// don't accidentally get the expected result.
 			repeat: 10,
 		},
+		{
+			name:      "chart with template with invalid yaml",
+			cmd:       fmt.Sprintf("template '%s'", "testdata/testcharts/chart-with-template-with-invalid-yaml"),
+			wantError: true,
+			golden:    "output/template-with-invalid-yaml.txt",
+		},
+		{
+			name:      "chart with template with invalid yaml (--debug)",
+			cmd:       fmt.Sprintf("template '%s' --debug", "testdata/testcharts/chart-with-template-with-invalid-yaml"),
+			wantError: true,
+			golden:    "output/template-with-invalid-yaml-debug.txt",
+		},
 	}
 	runTestCmd(t, tests)
 }
diff --git a/cmd/helm/testdata/output/template-with-invalid-yaml-debug.txt b/cmd/helm/testdata/output/template-with-invalid-yaml-debug.txt
new file mode 100644
index 000000000..c1f51185c
--- /dev/null
+++ b/cmd/helm/testdata/output/template-with-invalid-yaml-debug.txt
@@ -0,0 +1,13 @@
+---
+# Source: chart-with-template-with-invalid-yaml/templates/alpine-pod.yaml
+apiVersion: v1
+kind: Pod
+metadata:
+  name: "RELEASE-NAME-my-alpine"
+spec:
+  containers:
+  - name: waiter
+    image: "alpine:3.9"
+    command: ["/bin/sleep","9000"]
+invalid
+Error: YAML parse error on chart-with-template-with-invalid-yaml/templates/alpine-pod.yaml: error converting YAML to JSON: yaml: line 11: could not find expected ':'
diff --git a/cmd/helm/testdata/output/template-with-invalid-yaml.txt b/cmd/helm/testdata/output/template-with-invalid-yaml.txt
new file mode 100644
index 000000000..687227b90
--- /dev/null
+++ b/cmd/helm/testdata/output/template-with-invalid-yaml.txt
@@ -0,0 +1,3 @@
+Error: YAML parse error on chart-with-template-with-invalid-yaml/templates/alpine-pod.yaml: error converting YAML to JSON: yaml: line 11: could not find expected ':'
+
+Use --debug flag to render out invalid YAML
diff --git a/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/Chart.yaml b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/Chart.yaml
new file mode 100644
index 000000000..29b477b06
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/Chart.yaml
@@ -0,0 +1,8 @@
+apiVersion: v1
+description: Deploy a basic Alpine Linux pod
+home: https://helm.sh/helm
+name: chart-with-template-with-invalid-yaml
+sources:
+  - https://github.com/helm/helm
+version: 0.1.0
+type: application
diff --git a/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/README.md b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/README.md
new file mode 100644
index 000000000..fcf7ee017
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/README.md
@@ -0,0 +1,13 @@
+#Alpine: A simple Helm chart
+
+Run a single pod of Alpine Linux.
+
+This example was generated using the command `helm create alpine`.
+
+The `templates/` directory contains a very simple pod resource with a
+couple of parameters.
+
+The `values.yaml` file contains the default values for the
+`alpine-pod.yaml` template.
+
+You can install this example using `helm install ./alpine`.
diff --git a/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/templates/alpine-pod.yaml b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/templates/alpine-pod.yaml
new file mode 100644
index 000000000..697cb50fe
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/templates/alpine-pod.yaml
@@ -0,0 +1,10 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: "{{.Release.Name}}-{{.Values.Name}}"
+spec:
+  containers:
+  - name: waiter
+    image: "alpine:3.9"
+    command: ["/bin/sleep","9000"]
+invalid
diff --git a/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/values.yaml b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/values.yaml
new file mode 100644
index 000000000..807e12aea
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/chart-with-template-with-invalid-yaml/values.yaml
@@ -0,0 +1,1 @@
+Name: my-alpine