diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 0a30437e4..9d46b02c9 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -19,6 +19,7 @@ package engine import ( "bytes" "fmt" + "strings" "text/template" "github.com/Masterminds/sprig" @@ -31,6 +32,9 @@ type Engine struct { // FuncMap contains the template functions that will be passed to each // render call. This may only be modified before the first call to Render. FuncMap template.FuncMap + // If strict is enabled, template rendering will fail if a template references + // a value that was not passed in. + Strict bool } // New creates a new Go template Engine instance. @@ -92,6 +96,13 @@ func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) { // to share common blocks, but to make the entire thing feel like a file-based // template engine. t := template.New("gotpl") + if e.Strict { + t.Option("missingkey=error") + } else { + // Not that zero will attempt to add default values for types it knows, + // but will still emit for others. We mitigate that later. + t.Option("missingkey=zero") + } files := []string{} for fname, r := range tpls { t = t.New(fname).Funcs(e.FuncMap) @@ -107,7 +118,10 @@ func (e *Engine) render(tpls map[string]renderable) (map[string]string, error) { if err := t.ExecuteTemplate(&buf, file, tpls[file].vals); err != nil { return map[string]string{}, fmt.Errorf("render error in %q: %s", file, err) } - rendered[file] = buf.String() + // Work around the issue where Go will emit "" even if Options(missing=zero) + // is set. Since missing=error will never get here, we do not need to handle + // the Strict case. + rendered[file] = strings.Replace(buf.String(), "", "", -1) buf.Reset() } diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index e8c8e54cc..28de0a779 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -46,6 +46,7 @@ func TestRender(t *testing.T) { Templates: []*chart.Template{ {Name: "test1", Data: []byte("{{.outer | title }} {{.inner | title}}")}, {Name: "test2", Data: []byte("{{.global.callme | lower }}")}, + {Name: "test3", Data: []byte("{{.noValue}}")}, }, Values: &chart.Config{ Raw: "outer: DEFAULT\ninner: DEFAULT", @@ -82,6 +83,10 @@ func TestRender(t *testing.T) { if out["test2"] != expect { t.Errorf("Expected %q, got %q", expect, out["test2"]) } + expect = "" + if out["test3"] != expect { + t.Errorf("Expected %q, got %q", expect, out["test3"]) + } if _, err := e.Render(c, v); err != nil { t.Errorf("Unexpected error: %s", err)