diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 4e8328266..62e6f1087 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -18,6 +18,7 @@ package engine import ( "fmt" + "log" "path" "path/filepath" "sort" @@ -35,6 +36,8 @@ type Engine struct { // If strict is enabled, template rendering will fail if a template references // a value that was not passed in. Strict bool + // In LintMode, some 'required' template values may be missing, so don't fail + LintMode bool } // Render takes a chart, optional values, and value overrides, and attempts to render the Go templates. @@ -114,6 +117,29 @@ func (e Engine) initFunMap(t *template.Template, referenceTpls map[string]render } return result[templateName.(string)], nil } + + // Add the `required` function here so we can use lintMode + funcMap["required"] = func(warn string, val interface{}) (interface{}, error) { + if val == nil { + if e.LintMode { + // Don't fail on missing required values when linting + log.Printf("[INFO] Missing required value: %s", warn) + return "", nil + } + return val, errors.Errorf(warn) + } else if _, ok := val.(string); ok { + if val == "" { + if e.LintMode { + // Don't fail on missing required values when linting + log.Printf("[INFO] Missing required value: %s", warn) + return "", nil + } + return val, errors.Errorf(warn) + } + } + return val, nil + } + t.Funcs(funcMap) } diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index 9d708f193..c557d0285 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -480,6 +480,33 @@ func TestAlterFuncMap_require(t *testing.T) { if gotNum := out["conan/templates/bases"]; gotNum != expectNum { t.Errorf("Expected %q, got %q (%v)", expectNum, gotNum, out) } + + // test required without passing in needed values with lint mode on + // verifies lint replaces required with an empty string (should not fail) + lintValues := chartutil.Values{ + "Values": chartutil.Values{ + "who": "us", + }, + "Chart": c.Metadata, + "Release": chartutil.Values{ + "Name": "That 90s meme", + }, + } + var e Engine + e.LintMode = true + out, err = e.Render(c, lintValues) + if err != nil { + t.Fatal(err) + } + + expectStr = "All your base are belong to us" + if gotStr := out["conan/templates/quote"]; gotStr != expectStr { + t.Errorf("Expected %q, got %q (%v)", expectStr, gotStr, out) + } + expectNum = "All of them!" + if gotNum := out["conan/templates/bases"]; gotNum != expectNum { + t.Errorf("Expected %q, got %q (%v)", expectNum, gotNum, out) + } } func TestAlterFuncMap_tpl(t *testing.T) { diff --git a/pkg/engine/funcs.go b/pkg/engine/funcs.go index 936f91d3c..eb5032c6c 100644 --- a/pkg/engine/funcs.go +++ b/pkg/engine/funcs.go @@ -24,7 +24,6 @@ import ( "github.com/BurntSushi/toml" "github.com/Masterminds/sprig" - "github.com/pkg/errors" yaml "gopkg.in/yaml.v2" ) @@ -54,13 +53,13 @@ func funcMap() template.FuncMap { "fromYaml": fromYAML, "toJson": toJSON, "fromJson": fromJSON, - "required": required, // This is a placeholder for the "include" function, which is // late-bound to a template. By declaring it here, we preserve the // integrity of the linter. - "include": func(string, interface{}) string { return "not implemented" }, - "tpl": func(string, interface{}) interface{} { return "not implemented" }, + "include": func(string, interface{}) string { return "not implemented" }, + "tpl": func(string, interface{}) interface{} { return "not implemented" }, + "required": func(string, interface{}) (interface{}, error) { return "not implemented", nil }, } for k, v := range extra { @@ -70,17 +69,6 @@ func funcMap() template.FuncMap { return f } -func required(warn string, val interface{}) (interface{}, error) { - if val == nil { - return val, errors.Errorf(warn) - } else if _, ok := val.(string); ok { - if val == "" { - return val, errors.Errorf(warn) - } - } - return val, nil -} - // toYAML takes an interface, marshals it to yaml, and returns a string. It will // always return a string, even on marshal error (empty string). // diff --git a/pkg/engine/funcs_test.go b/pkg/engine/funcs_test.go index bbdd6ebe3..4c2addcee 100644 --- a/pkg/engine/funcs_test.go +++ b/pkg/engine/funcs_test.go @@ -30,10 +30,6 @@ func TestFuncs(t *testing.T) { tpl, expect string vars interface{} }{{ - tpl: `All {{ required "A valid 'bases' is required" .bases }} of them!`, - expect: `All 2 of them!`, - vars: map[string]interface{}{"bases": 2}, - }, { tpl: `{{ toYaml . }}`, expect: `foo: bar`, vars: map[string]interface{}{"foo": "bar"}, diff --git a/pkg/lint/rules/template.go b/pkg/lint/rules/template.go index 5f1b2036e..7bafe1723 100644 --- a/pkg/lint/rules/template.go +++ b/pkg/lint/rules/template.go @@ -68,6 +68,7 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace } var e engine.Engine e.Strict = strict + e.LintMode = true renderedContentMap, err := e.Render(chart, valuesToRender) renderOk := linter.RunLinterRule(support.ErrorSev, path, err)