diff --git a/pkg/state/create_test.go b/pkg/state/create_test.go index 9c0303f0..224472e7 100644 --- a/pkg/state/create_test.go +++ b/pkg/state/create_test.go @@ -100,9 +100,11 @@ bar: {{ readFile "bar.txt" }} } valuesFile := "/example/path/to/values.yaml.gotmpl" - valuesContent := []byte(`env: {{ .Environment.Name }}`) + valuesContent := []byte(`env: {{ .Environment.Name }} +releaseName: {{ .Release.Name }}`) - expectedValues := `env: production` + expectedValues := `env: production +releaseName: myrelease` testFs := testhelper.NewTestFs(map[string]string{ fooYamlFile: string(fooYamlContent), @@ -124,7 +126,11 @@ bar: {{ readFile "bar.txt" }} t.Errorf("unexpected environment values: expected=%v, actual=%v", expected, actual) } - actualValuesData, err := state.RenderValuesFileToBytes(valuesFile) + var release = ReleaseSpec{ + Name: "myrelease", + } + + actualValuesData, err := state.RenderReleaseValuesFileToBytes(&release, valuesFile) if err != nil { t.Errorf("unexpected error: %v", err) } diff --git a/pkg/state/helmx.go b/pkg/state/helmx.go index 611a6fef..d0a2b39f 100644 --- a/pkg/state/helmx.go +++ b/pkg/state/helmx.go @@ -114,7 +114,7 @@ func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSp jsonPatches := release.JSONPatches if len(jsonPatches) > 0 { - generatedFiles, err := st.generateTemporaryValuesFiles(jsonPatches, release.MissingFileHandler) + generatedFiles, err := st.generateTemporaryReleaseValuesFiles(release, jsonPatches, release.MissingFileHandler) if err != nil { return nil, clean, err } @@ -130,7 +130,7 @@ func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSp strategicMergePatches := release.StrategicMergePatches if len(strategicMergePatches) > 0 { - generatedFiles, err := st.generateTemporaryValuesFiles(strategicMergePatches, release.MissingFileHandler) + generatedFiles, err := st.generateTemporaryReleaseValuesFiles(release, strategicMergePatches, release.MissingFileHandler) if err != nil { return nil, clean, err } diff --git a/pkg/state/state.go b/pkg/state/state.go index 41c7c27d..a2d02c49 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -2084,8 +2084,14 @@ func (st *HelmState) flagsForLint(helm helmexec.Interface, release *ReleaseSpec, return flags, files, nil } -func (st *HelmState) RenderValuesFileToBytes(path string) ([]byte, error) { - r := tmpl.NewFileRenderer(st.readFile, filepath.Dir(path), st.valuesFileTemplateData()) +func (st *HelmState) RenderReleaseValuesFileToBytes(release *ReleaseSpec, path string) ([]byte, error) { + vals, err := st.Values() + if err != nil { + return nil, err + } + templateData := st.createReleaseTemplateData(release, vals) + + r := tmpl.NewFileRenderer(st.readFile, filepath.Dir(path), templateData) rawBytes, err := r.RenderToBytes(path) if err != nil { return nil, err @@ -2164,7 +2170,7 @@ func (st *HelmState) removeFiles(files []string) { } } -func (st *HelmState) generateTemporaryValuesFiles(values []interface{}, missingFileHandler *string) ([]string, error) { +func (st *HelmState) generateTemporaryReleaseValuesFiles(release *ReleaseSpec, values []interface{}, missingFileHandler *string) ([]string, error) { generatedFiles := []string{} for _, value := range values { @@ -2183,7 +2189,7 @@ func (st *HelmState) generateTemporaryValuesFiles(values []interface{}, missingF } path := paths[0] - yamlBytes, err := st.RenderValuesFileToBytes(path) + yamlBytes, err := st.RenderReleaseValuesFileToBytes(release, path) if err != nil { return generatedFiles, fmt.Errorf("failed to render values files \"%s\": %v", typedValue, err) } @@ -2240,7 +2246,7 @@ func (st *HelmState) generateVanillaValuesFiles(release *ReleaseSpec) ([]string, return nil, fmt.Errorf("Failed to render values in %s for release %s: type %T isn't supported", st.FilePath, release.Name, valuesMapSecretsRendered["values"]) } - generatedFiles, err := st.generateTemporaryValuesFiles(valuesSecretsRendered, release.MissingFileHandler) + generatedFiles, err := st.generateTemporaryReleaseValuesFiles(release, valuesSecretsRendered, release.MissingFileHandler) if err != nil { return nil, err } diff --git a/pkg/state/state_exec_tmpl.go b/pkg/state/state_exec_tmpl.go index 68f0af7f..c1b627db 100644 --- a/pkg/state/state_exec_tmpl.go +++ b/pkg/state/state_exec_tmpl.go @@ -12,19 +12,16 @@ func (st *HelmState) Values() (map[string]interface{}, error) { return st.Env.GetMergedValues() } -func (st *HelmState) mustLoadVals() map[string]interface{} { - vals, err := st.Values() - if err != nil { - panic(err) - } - return vals -} - -func (st *HelmState) valuesFileTemplateData() EnvironmentTemplateData { - return EnvironmentTemplateData{ +func (st *HelmState) createReleaseTemplateData(release *ReleaseSpec, vals map[string]interface{}) releaseTemplateData { + return releaseTemplateData{ Environment: st.Env, - Namespace: st.OverrideNamespace, - Values: st.mustLoadVals(), + Values: vals, + Release: releaseTemplateDataRelease{ + Name: release.Name, + Chart: release.Chart, + Namespace: release.Namespace, + Labels: release.Labels, + }, } } @@ -88,11 +85,7 @@ func (st *HelmState) ExecuteTemplates() (*HelmState, error) { for i, rt := range st.Releases { successFlag := false for it, prev := 0, &rt; it < 6; it++ { - tmplData := releaseTemplateData{ - Environment: st.Env, - Release: *prev, - Values: vals, - } + tmplData := st.createReleaseTemplateData(prev, vals) renderer := tmpl.NewFileRenderer(st.readFile, st.basePath, tmplData) r, err := rt.ExecuteTemplateExpressions(renderer) if err != nil { diff --git a/pkg/state/types.go b/pkg/state/types.go index fed10683..06a4eec5 100644 --- a/pkg/state/types.go +++ b/pkg/state/types.go @@ -19,12 +19,28 @@ type EnvironmentTemplateData struct { Values map[string]interface{} } -// releaseTemplateData provides variables accessible while executing golang text/template expressions in releases of a helmfile YAML file +// releaseTemplateData provides variables accessible while executing golang text/template expressions in release templates +// and release values templates within a Helmfile YAML file. type releaseTemplateData struct { // Environment is accessible as `.Environment` from any template expression executed by the renderer Environment environment.Environment - // Release is accessible as `.Release` from any template expression executed by the renderer - Release ReleaseSpec + // Release is accessible as `.Release` from any template expression executed by the renderer. + // It contains a subset of ReleaseSpec that is known to be useful to dynamically render values. + Release releaseTemplateDataRelease // Values is accessible as `.Values` and it contains default state values overrode by environment values and override values. Values map[string]interface{} } + +type releaseTemplateDataRelease struct { + // Name is basically ReleaseSpec.Name exposed to the template + Name string + + // Namespace is HelmState.OverrideNamespace, or if it's empty, ReleaseSpec.Namespace. + Namespace string + + // Labels is ReleaseSpec.Labels + Labels map[string]string + + // Chart is ReleaseSpec.Chart + Chart string +}