diff --git a/README.md b/README.md index 86a8bc3..f0e9a39 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,19 @@ docker run --rm -v "$PWD:/work" ghcr.io/digitalstudium/helmfmt:latest \ --files templates/deployment.yaml templates/service.yaml ``` +### Helmfile templates + +[Helmfile](https://helmfile.readthedocs.io/) value files use extra template +functions on top of Helm/Sprig (`env`, `requiredEnv`, `exec`, `readFile`, +`fetchSecretValue`, ...). `helmfmt` accepts these functions as well, so it also +formats helmfile files. The `.gotmpl` extension (e.g. `helmfile.yaml.gotmpl`, +`values/demo.yaml.gotmpl`) is included by default: + +```bash +helmfmt --check --files helmfile.yaml.gotmpl values/demo.yaml.gotmpl +cat values/demo.yaml | helmfmt --check +``` + --- ## Configuration @@ -239,7 +252,7 @@ docker run --rm -v "$PWD:/work" ghcr.io/digitalstudium/helmfmt:latest \ ```json { "indent_size": 2, - "extensions": [".yaml", ".yml", ".tpl"], + "extensions": [".yaml", ".yml", ".tpl", ".gotmpl"], "rules": { "indent": { "tpl": { diff --git a/format.go b/format.go index 9382a34..79801a7 100644 --- a/format.go +++ b/format.go @@ -44,14 +44,16 @@ var ( func stub(args ...interface{}) interface{} { return nil } // helmFuncMap returns a template.FuncMap containing stub registrations for -// every sprig function (minus env/expandenv which Helm drops) plus Helm's own -// additions. Only the presence of each name matters for parse-time syntax -// validation; the stubs are never executed. +// every sprig function (minus env/expandenv which Helm drops), Helm's own +// additions, and the template functions helmfile registers on top of +// Helm/Sprig (env, requiredEnv, exec, readFile, ...). Only the presence of +// each name matters for parse-time syntax validation; the stubs are never +// executed. // // The sprigStubNames slice is generated by `go generate` from the actual // sprig.TxtFuncMap(), so it stays in sync when sprig adds new functions. func helmFuncMap() template.FuncMap { - f := make(template.FuncMap, len(sprigStubNames)+10) + f := make(template.FuncMap, len(sprigStubNames)+25) for _, name := range sprigStubNames { f[name] = stub } @@ -64,18 +66,26 @@ func helmFuncMap() template.FuncMap { for _, name := range helmExtras { f[name] = stub } + // Helmfile-specific functions not in Helm/sprig + helmfileExtras := []string{ + "env", "requiredEnv", "exec", "envExec", + "readFile", "readDir", "readDirEntries", + "getOrNil", "setValueAtPath", + "fetchSecretValue", "expandSecretRefs", "kustomizeBuild", + } + for _, name := range helmfileExtras { + f[name] = stub + } return f } -// validateTemplateSyntax validates the given template source string using -// Helm function set. Returns an error if the template has invalid syntax. +// validateTemplateSyntax validates the given template source string using the +// combined Helm/helmfile function set. Returns an error if the template has +// invalid syntax. func validateTemplateSyntax(src string) error { - // Get Helm's built-in function map - helmFuncMap := helmFuncMap() - - // Create and parse template with helm function map - _, err := template.New("validation").Funcs(helmFuncMap).Parse(src) + // Create and parse template with the function map + _, err := template.New("validation").Funcs(helmFuncMap()).Parse(src) if err != nil { return fmt.Errorf("invalid template syntax: %w", err) } diff --git a/main.go b/main.go index c4b8d02..a97e94d 100644 --- a/main.go +++ b/main.go @@ -37,7 +37,7 @@ func loadConfig() *Config { // Default config config := &Config{ IndentSize: 2, - Extensions: []string{".yaml", ".yml", ".tpl"}, + Extensions: []string{".yaml", ".yml", ".tpl", ".gotmpl"}, Rules: RulesConfig{ Indent: map[string]RuleConfig{ "tpl": {Disabled: true, Exclude: []string{}}, diff --git a/templates_test/helmfile_values.yaml b/templates_test/helmfile_values.yaml new file mode 100644 index 0000000..29a3969 --- /dev/null +++ b/templates_test/helmfile_values.yaml @@ -0,0 +1,3 @@ +name: "Helmfile .gotmpl values with env/requiredEnv" +input_file: "templates/helmfile_values.yaml.gotmpl" +expected_file: "templates_expected/helmfile_values.yaml.gotmpl" diff --git a/templates_test/templates/helmfile_values.yaml.gotmpl b/templates_test/templates/helmfile_values.yaml.gotmpl new file mode 100644 index 0000000..5beb220 --- /dev/null +++ b/templates_test/templates/helmfile_values.yaml.gotmpl @@ -0,0 +1,7 @@ +{{- if env "FEATURE_ENABLED" }} +{{ range $name := .Values.releases }} +{{- $token := requiredEnv "GITHUB_TOKEN" }} +name: {{ $name }} +registry: {{ env "REGISTRY" | default "private.azurecr.io" }} +{{- end }} +{{- end }} diff --git a/templates_test/templates_expected/helmfile_values.yaml.gotmpl b/templates_test/templates_expected/helmfile_values.yaml.gotmpl new file mode 100644 index 0000000..ec3c400 --- /dev/null +++ b/templates_test/templates_expected/helmfile_values.yaml.gotmpl @@ -0,0 +1,7 @@ +{{- if env "FEATURE_ENABLED" }} + {{ range $name := .Values.releases }} + {{- $token := requiredEnv "GITHUB_TOKEN" }} +name: {{ $name }} +registry: {{ env "REGISTRY" | default "private.azurecr.io" }} + {{- end }} +{{- end }}