diff --git a/cmd/helm/template.go b/cmd/helm/template.go index c04bc2dc8..fc1f44392 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -117,31 +117,10 @@ func (t *templateCmd) run(cmd *cobra.Command, args []string) error { } else { return err } - // verify specified templates exist relative to chart - rf := []string{} - var af string - var err error - if len(t.renderFiles) > 0 { - for _, f := range t.renderFiles { - if !filepath.IsAbs(f) { - af, err = filepath.Abs(filepath.Join(t.chartPath, f)) - if err != nil { - return fmt.Errorf("could not resolve template path: %s", err) - } - } else { - af = f - } - rf = append(rf, af) - - if _, err := os.Stat(af); err != nil { - return fmt.Errorf("could not resolve template path: %s", err) - } - } - } // verify that output-dir exists if provided if t.outputDir != "" { - _, err = os.Stat(t.outputDir) + _, err := os.Stat(t.outputDir) if os.IsNotExist(err) { return fmt.Errorf("output-dir '%s' does not exist", t.outputDir) } @@ -232,19 +211,7 @@ func (t *templateCmd) run(cmd *cobra.Command, args []string) error { m := tiller.Manifest{Name: k, Content: v, Head: &util.SimpleHead{Kind: h}} listManifests = append(listManifests, m) } - in := func(needle string, haystack []string) bool { - // make needle path absolute - d := strings.Split(needle, string(os.PathSeparator)) - dd := d[1:] - an := filepath.Join(t.chartPath, strings.Join(dd, string(os.PathSeparator))) - - for _, h := range haystack { - if h == an { - return true - } - } - return false - } + if settings.Debug { rel := &release.Release{ Name: t.releaseName, @@ -257,10 +224,45 @@ func (t *templateCmd) run(cmd *cobra.Command, args []string) error { printRelease(os.Stdout, rel) } - for _, m := range tiller.SortByKind(listManifests) { - if len(t.renderFiles) > 0 && !in(m.Name, rf) { - continue + var manifestsToRender []tiller.Manifest + + // if we have a list of files to render, then check that each of the + // provided files exists in the chart. + if len(t.renderFiles) > 0 { + for _, f := range t.renderFiles { + missing := true + if !filepath.IsAbs(f) { + newF, err := filepath.Abs(filepath.Join(t.chartPath, f)) + if err != nil { + return fmt.Errorf("could not turn template path %s into absolute path: %s", f, err) + } + f = newF + } + + for _, manifest := range listManifests { + manifestPathSplit := strings.Split(manifest.Name, string(filepath.Separator)) + // remove the chart name from the path + manifestPathSplit = manifestPathSplit[1:] + toJoin := append([]string{t.chartPath}, manifestPathSplit...) + manifestPath := filepath.Join(toJoin...) + + // 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) + } } + } else { + // no renderFiles provided, render all manifests in the chart + manifestsToRender = listManifests + } + + for _, m := range tiller.SortByKind(manifestsToRender) { data := m.Content b := filepath.Base(m.Name) if !t.showNotes && b == "NOTES.txt" { diff --git a/cmd/helm/template_test.go b/cmd/helm/template_test.go index eefa46774..68ed87cd2 100644 --- a/cmd/helm/template_test.go +++ b/cmd/helm/template_test.go @@ -27,10 +27,13 @@ import ( "testing" ) -var chartPath = "./../../pkg/chartutil/testdata/subpop/charts/subchart1" +var ( + subchart1ChartPath = "./../../pkg/chartutil/testdata/subpop/charts/subchart1" + frobnitzChartPath = "./../../pkg/chartutil/testdata/frobnitz" +) func TestTemplateCmd(t *testing.T) { - absChartPath, err := filepath.Abs(chartPath) + subchart1AbsChartPath, err := filepath.Abs(subchart1ChartPath) if err != nil { t.Fatal(err) } @@ -40,74 +43,95 @@ func TestTemplateCmd(t *testing.T) { args []string expectKey string expectValue string + expectError string }{ { name: "check_name", desc: "check for a known name in chart", - args: []string{chartPath}, + args: []string{subchart1ChartPath}, expectKey: "subchart1/templates/service.yaml", expectValue: "protocol: TCP\n name: nginx", }, { name: "check_set_name", desc: "verify --set values exist", - args: []string{chartPath, "-x", "templates/service.yaml", "--set", "service.name=apache"}, + args: []string{subchart1ChartPath, "-x", "templates/service.yaml", "--set", "service.name=apache"}, expectKey: "subchart1/templates/service.yaml", expectValue: "protocol: TCP\n name: apache", }, { name: "check_execute", desc: "verify --execute single template", - args: []string{chartPath, "-x", "templates/service.yaml", "--set", "service.name=apache"}, + args: []string{subchart1ChartPath, "-x", "templates/service.yaml", "--set", "service.name=apache"}, expectKey: "subchart1/templates/service.yaml", expectValue: "protocol: TCP\n name: apache", }, + { + name: "check_execute_non_existent", + desc: "verify --execute fails on a template that doesnt exist", + args: []string{subchart1ChartPath, "-x", "templates/thisdoesntexist.yaml"}, + expectError: "could not find template", + }, { name: "check_execute_absolute", desc: "verify --execute single template", - args: []string{chartPath, "-x", absChartPath + "/" + "templates/service.yaml", "--set", "service.name=apache"}, + args: []string{subchart1ChartPath, "-x", subchart1AbsChartPath + "/" + "templates/service.yaml", "--set", "service.name=apache"}, expectKey: "subchart1/templates/service.yaml", expectValue: "protocol: TCP\n name: apache", }, + { + name: "check_execute_subchart_template", + desc: "verify --execute single template on a subchart template", + args: []string{subchart1ChartPath, "-x", "charts/subcharta/templates/service.yaml", "--set", "subcharta.service.name=foobar"}, + expectKey: "subchart1/charts/subcharta/templates/service.yaml", + expectValue: "protocol: TCP\n name: foobar", + }, + { + name: "check_execute_subchart_template_for_tgz_subchart", + desc: "verify --execute single template on a subchart template where the subchart is a .tgz in the chart directory", + args: []string{frobnitzChartPath, "-x", "charts/mariner/templates/placeholder.tpl", "--set", "mariner.name=moon"}, + expectKey: "frobnitz/charts/mariner/templates/placeholder.tpl", + expectValue: "Goodbye moon", + }, { name: "check_namespace", desc: "verify --namespace", - args: []string{chartPath, "--namespace", "test"}, + args: []string{subchart1ChartPath, "--namespace", "test"}, expectKey: "subchart1/templates/service.yaml", expectValue: "namespace: \"test\"", }, { name: "check_release_name", desc: "verify --release exists", - args: []string{chartPath, "--name", "test"}, + args: []string{subchart1ChartPath, "--name", "test"}, expectKey: "subchart1/templates/service.yaml", expectValue: "release-name: \"test\"", }, { name: "check_notes", desc: "verify --notes shows notes", - args: []string{chartPath, "--notes", "true"}, + args: []string{subchart1ChartPath, "--notes", "true"}, expectKey: "subchart1/templates/NOTES.txt", expectValue: "Sample notes for subchart1", }, { name: "check_values_files", desc: "verify --values files values exist", - args: []string{chartPath, "--values", chartPath + "/charts/subchartA/values.yaml"}, + args: []string{subchart1ChartPath, "--values", subchart1ChartPath + "/charts/subchartA/values.yaml"}, expectKey: "subchart1/templates/service.yaml", expectValue: "name: apache", }, { name: "check_name_template", desc: "verify --name-template result exists", - args: []string{chartPath, "--name-template", "foobar-{{ b64enc \"abc\" }}-baz"}, + args: []string{subchart1ChartPath, "--name-template", "foobar-{{ b64enc \"abc\" }}-baz"}, expectKey: "subchart1/templates/service.yaml", expectValue: "release-name: \"foobar-YWJj-baz\"", }, { name: "check_kube_version", desc: "verify --kube-version overrides the kubernetes version", - args: []string{chartPath, "--kube-version", "1.6"}, + args: []string{subchart1ChartPath, "--kube-version", "1.6"}, expectKey: "subchart1/templates/service.yaml", expectValue: "kube-version/major: \"1\"\n kube-version/minor: \"6\"\n kube-version/gitversion: \"v1.6.0\"", }, @@ -115,7 +139,8 @@ func TestTemplateCmd(t *testing.T) { var buf bytes.Buffer for _, tt := range tests { - t.Run(tt.name, func(T *testing.T) { + tt := tt + t.Run(tt.name, func(t *testing.T) { // capture stdout old := os.Stdout r, w, _ := os.Pipe() @@ -125,8 +150,21 @@ func TestTemplateCmd(t *testing.T) { cmd := newTemplateCmd(out) cmd.SetArgs(tt.args) err := cmd.Execute() - if err != nil { - t.Errorf("expected: %v, got %v", tt.expectValue, err) + + if tt.expectError != "" { + if err == nil { + t.Errorf("expected err: %s, but no error occurred", tt.expectError) + } + // non nil error, check if it contains the expected error + if strings.Contains(err.Error(), tt.expectError) { + // had the error we were looking for, this test case is + // done + return + } else { + t.Fatalf("expected err: %q, got: %q", tt.expectError, err) + } + } else if err != nil { + t.Errorf("expected no error, got %v", err) } // restore stdout w.Close() diff --git a/pkg/chartutil/testdata/frobnitz-1.2.3.tgz b/pkg/chartutil/testdata/frobnitz-1.2.3.tgz index fb21cd08f..cd12d2c1e 100644 Binary files a/pkg/chartutil/testdata/frobnitz-1.2.3.tgz and b/pkg/chartutil/testdata/frobnitz-1.2.3.tgz differ diff --git a/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz b/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz index 3af333e76..78fabe241 100644 Binary files a/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz and b/pkg/chartutil/testdata/frobnitz/charts/mariner-4.3.2.tgz differ diff --git a/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz b/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz index 0b66d27fe..cd2ac4e46 100644 Binary files a/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz and b/pkg/chartutil/testdata/mariner/charts/albatross-0.1.0.tgz differ diff --git a/pkg/chartutil/testdata/mariner/templates/placeholder.tpl b/pkg/chartutil/testdata/mariner/templates/placeholder.tpl index 29c11843a..9804717d1 100644 --- a/pkg/chartutil/testdata/mariner/templates/placeholder.tpl +++ b/pkg/chartutil/testdata/mariner/templates/placeholder.tpl @@ -1 +1,3 @@ # This is a placeholder. + +Goodbye {{.Values.name | default "world"}}