fix: compute mergedReleaseTemplateData lazily in PrepareChartify

Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/100b7974-3268-4dc8-be21-12bd82aa2dbb

Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-04-28 06:08:56 +00:00 committed by GitHub
parent 5792ea4df0
commit badd5b8e00
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 27 additions and 13 deletions

View File

@ -1324,7 +1324,7 @@ host: {{ .Values.ingress.host }}
generatedFiles, err := st.generateTemporaryReleaseValuesFilesWithData(
release,
[]any{"patch.yaml.gotmpl"},
tmplData,
func() (releaseTemplateData, error) { return tmplData, nil },
)
require.NoError(t, err)
require.Len(t, generatedFiles, 1)
@ -1354,7 +1354,7 @@ func TestGenerateTemporaryReleaseValuesFilesWithData_InlineMap(t *testing.T) {
generatedFiles, err := st.generateTemporaryReleaseValuesFilesWithData(
release,
[]any{inlineValues},
tmplData,
func() (releaseTemplateData, error) { return tmplData, nil },
)
require.NoError(t, err)
require.Len(t, generatedFiles, 1)
@ -1376,7 +1376,7 @@ func TestGenerateTemporaryReleaseValuesFilesWithData_UnknownTypeError(t *testing
_, err := st.generateTemporaryReleaseValuesFilesWithData(
release,
[]any{42},
tmplData,
func() (releaseTemplateData, error) { return tmplData, nil },
)
require.Error(t, err)
assert.Contains(t, err.Error(), "unexpected type of value")

View File

@ -404,18 +404,28 @@ func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSp
shouldRun = true
}
var patchTemplateData *releaseTemplateData
if len(release.JSONPatches) > 0 || len(release.StrategicMergePatches) > 0 || len(release.Transformers) > 0 {
td, err := st.mergedReleaseTemplateData(release)
if err != nil {
return nil, clean, fmt.Errorf("failed to compute merged release values for patch rendering: %v", err)
// patchTemplateData is computed lazily on first use: only when an actual string patch/transformer
// file path is rendered. Inline-map entries don't require template data at all, so we avoid
// unnecessary I/O for releases whose patches are all inline maps or that have no string entries.
var (
cachedPatchTemplateData releaseTemplateData
cachedPatchTemplateDataErr error
cachedPatchTemplateDataSet bool
)
getPatchTemplateData := func() (releaseTemplateData, error) {
if !cachedPatchTemplateDataSet {
cachedPatchTemplateDataSet = true
cachedPatchTemplateData, cachedPatchTemplateDataErr = st.mergedReleaseTemplateData(release)
if cachedPatchTemplateDataErr != nil {
cachedPatchTemplateDataErr = fmt.Errorf("failed to compute merged release values for patch rendering: %v", cachedPatchTemplateDataErr)
}
}
patchTemplateData = &td
return cachedPatchTemplateData, cachedPatchTemplateDataErr
}
jsonPatches := release.JSONPatches
if len(jsonPatches) > 0 {
generatedFiles, err := st.generateTemporaryReleaseValuesFilesWithData(release, jsonPatches, *patchTemplateData)
generatedFiles, err := st.generateTemporaryReleaseValuesFilesWithData(release, jsonPatches, getPatchTemplateData)
if err != nil {
return nil, clean, err
}
@ -429,7 +439,7 @@ func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSp
strategicMergePatches := release.StrategicMergePatches
if len(strategicMergePatches) > 0 {
generatedFiles, err := st.generateTemporaryReleaseValuesFilesWithData(release, strategicMergePatches, *patchTemplateData)
generatedFiles, err := st.generateTemporaryReleaseValuesFilesWithData(release, strategicMergePatches, getPatchTemplateData)
if err != nil {
return nil, clean, err
}
@ -443,7 +453,7 @@ func (st *HelmState) PrepareChartify(helm helmexec.Interface, release *ReleaseSp
transformers := release.Transformers
if len(transformers) > 0 {
generatedFiles, err := st.generateTemporaryReleaseValuesFilesWithData(release, transformers, *patchTemplateData)
generatedFiles, err := st.generateTemporaryReleaseValuesFilesWithData(release, transformers, getPatchTemplateData)
if err != nil {
return nil, clean, err
}

View File

@ -4034,8 +4034,12 @@ func (st *HelmState) renderValuesFileToBytesWithData(path string, templateData r
return rawBytes, nil
}
func (st *HelmState) generateTemporaryReleaseValuesFilesWithData(release *ReleaseSpec, values []any, templateData releaseTemplateData) ([]string, error) {
func (st *HelmState) generateTemporaryReleaseValuesFilesWithData(release *ReleaseSpec, values []any, getTemplateData func() (releaseTemplateData, error)) ([]string, error) {
return st.generateTemporaryReleaseValuesFilesCore(release, values, func(path string) ([]byte, error) {
templateData, err := getTemplateData()
if err != nil {
return nil, err
}
return st.renderValuesFileToBytesWithData(path, templateData)
})
}