refactor: extract generateTemporaryReleaseValuesFilesCore to eliminate duplication; fix temp dir leaks in tests

Agent-Logs-Url: https://github.com/helmfile/helmfile/sessions/b254ddda-aa95-4e2f-8dd9-1ce4c40eedb6

Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-04-27 06:41:08 +00:00 committed by GitHub
parent 71bae6beb0
commit 09bf3c22a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 80 additions and 137 deletions

View File

@ -2,7 +2,6 @@ package state
import (
"fmt"
"os"
"path/filepath"
"reflect"
"testing"
@ -15,6 +14,7 @@ import (
"go.uber.org/zap/zaptest"
"github.com/helmfile/helmfile/pkg/environment"
"github.com/helmfile/helmfile/pkg/envvar"
"github.com/helmfile/helmfile/pkg/filesystem"
"github.com/helmfile/helmfile/pkg/remote"
"github.com/helmfile/helmfile/pkg/testhelper"
@ -1303,6 +1303,8 @@ releaseNamespace: {{ .Release.Namespace }}
}
func TestGenerateTemporaryReleaseValuesFilesWithData_StringPath(t *testing.T) {
t.Setenv(envvar.TempDir, t.TempDir())
patchFile := "/project/patch.yaml.gotmpl"
patchContent := `enabled: {{ .Values.ingress.enabled }}
host: {{ .Values.ingress.host }}
@ -1326,11 +1328,6 @@ host: {{ .Values.ingress.host }}
)
require.NoError(t, err)
require.Len(t, generatedFiles, 1)
t.Cleanup(func() {
for _, f := range generatedFiles {
_ = os.Remove(f)
}
})
// The temp files are created on the real OS filesystem via os.Create, so we read them with os.ReadFile
content, err := filesystem.DefaultFileSystem().ReadFile(generatedFiles[0])
@ -1340,6 +1337,8 @@ host: {{ .Values.ingress.host }}
}
func TestGenerateTemporaryReleaseValuesFilesWithData_InlineMap(t *testing.T) {
t.Setenv(envvar.TempDir, t.TempDir())
st := newTestHelmStateWithFiles(t, map[string]string{})
release := &ReleaseSpec{Name: "myrelease", Chart: "mychart"}
@ -1359,11 +1358,6 @@ func TestGenerateTemporaryReleaseValuesFilesWithData_InlineMap(t *testing.T) {
)
require.NoError(t, err)
require.Len(t, generatedFiles, 1)
t.Cleanup(func() {
for _, f := range generatedFiles {
_ = os.Remove(f)
}
})
// The temp files are created on the real OS filesystem via os.Create, so we read them with os.ReadFile
content, err := filesystem.DefaultFileSystem().ReadFile(generatedFiles[0])

View File

@ -4024,109 +4024,9 @@ func (st *HelmState) renderValuesFileToBytesWithData(path string, templateData r
}
func (st *HelmState) generateTemporaryReleaseValuesFilesWithData(release *ReleaseSpec, values []any, templateData releaseTemplateData) ([]string, error) {
generatedFiles := []string{}
for _, value := range values {
switch typedValue := value.(type) {
case string:
paths, skip, err := st.storage().resolveFile(st.getReleaseMissingFileHandler(release), "values", typedValue, st.getReleaseMissingFileHandlerConfig(release).resolveFileOptions()...)
if err != nil {
return generatedFiles, err
}
if skip {
continue
}
if len(paths) > 1 {
return generatedFiles, fmt.Errorf("glob patterns are not supported in patch/transformer values yet. please submit a feature request if necessary")
}
path := paths[0]
yamlBytes, err := st.renderValuesFileToBytesWithData(path, templateData)
if err != nil {
return generatedFiles, fmt.Errorf("failed to render values files \"%s\": %v", typedValue, err)
}
if err := func() error {
valfile, err := createTempValuesFile(release, yamlBytes)
if err != nil {
return err
}
defer func() {
_ = valfile.Close()
}()
if _, err := valfile.Write(yamlBytes); err != nil {
return fmt.Errorf("failed to write %s: %v", valfile.Name(), err)
}
st.logger.Debugf("Successfully generated the value file at %s. produced:\n%s", path, string(yamlBytes))
generatedFiles = append(generatedFiles, valfile.Name())
return nil
}(); err != nil {
return generatedFiles, err
}
case map[any]any:
strMap, err := maputil.CastKeysToStrings(typedValue)
if err != nil {
return generatedFiles, err
}
if err := func() error {
valfile, err := createTempValuesFile(release, strMap)
if err != nil {
return err
}
defer func() {
_ = valfile.Close()
}()
encoder := yaml.NewEncoder(valfile)
defer func() {
_ = encoder.Close()
}()
if err := encoder.Encode(strMap); err != nil {
return err
}
generatedFiles = append(generatedFiles, valfile.Name())
return nil
}(); err != nil {
return generatedFiles, err
}
case map[string]any:
if err := func() error {
valfile, err := createTempValuesFile(release, typedValue)
if err != nil {
return err
}
defer func() {
_ = valfile.Close()
}()
encoder := yaml.NewEncoder(valfile)
defer func() {
_ = encoder.Close()
}()
if err := encoder.Encode(typedValue); err != nil {
return err
}
generatedFiles = append(generatedFiles, valfile.Name())
return nil
}(); err != nil {
return generatedFiles, err
}
default:
return generatedFiles, fmt.Errorf("unexpected type of value: value=%v, type=%T", typedValue, typedValue)
}
}
return generatedFiles, nil
return st.generateTemporaryReleaseValuesFilesCore(release, values, func(path string) ([]byte, error) {
return st.renderValuesFileToBytesWithData(path, templateData)
})
}
func (st *HelmState) newReleaseTemplateFuncMap(dir string) template.FuncMap {
@ -4265,6 +4165,14 @@ func (st *HelmState) getMissingFileHandler() *string {
}
func (st *HelmState) generateTemporaryReleaseValuesFiles(release *ReleaseSpec, values []any) ([]string, error) {
return st.generateTemporaryReleaseValuesFilesCore(release, values, func(path string) ([]byte, error) {
return st.RenderReleaseValuesFileToBytes(release, path)
})
}
// generateTemporaryReleaseValuesFilesCore is the shared implementation for generating temporary values files.
// renderStringValue is called for each string value entry after the file path has been resolved.
func (st *HelmState) generateTemporaryReleaseValuesFilesCore(release *ReleaseSpec, values []any, renderStringValue func(path string) ([]byte, error)) ([]string, error) {
generatedFiles := []string{}
for _, value := range values {
@ -4283,45 +4191,86 @@ func (st *HelmState) generateTemporaryReleaseValuesFiles(release *ReleaseSpec, v
}
path := paths[0]
yamlBytes, err := st.RenderReleaseValuesFileToBytes(release, path)
yamlBytes, err := renderStringValue(path)
if err != nil {
return generatedFiles, fmt.Errorf("failed to render values files \"%s\": %v", typedValue, err)
}
valfile, err := createTempValuesFile(release, yamlBytes)
if err := func() error {
valfile, err := createTempValuesFile(release, yamlBytes)
if err != nil {
return err
}
defer func() {
_ = valfile.Close()
}()
if _, err := valfile.Write(yamlBytes); err != nil {
return fmt.Errorf("failed to write %s: %v", valfile.Name(), err)
}
st.logger.Debugf("Successfully generated the value file at %s. produced:\n%s", path, string(yamlBytes))
generatedFiles = append(generatedFiles, valfile.Name())
return nil
}(); err != nil {
return generatedFiles, err
}
case map[any]any:
strMap, err := maputil.CastKeysToStrings(typedValue)
if err != nil {
return generatedFiles, err
}
defer func() {
_ = valfile.Close()
}()
if err := func() error {
valfile, err := createTempValuesFile(release, strMap)
if err != nil {
return err
}
defer func() {
_ = valfile.Close()
}()
if _, err := valfile.Write(yamlBytes); err != nil {
return generatedFiles, fmt.Errorf("failed to write %s: %v", valfile.Name(), err)
}
encoder := yaml.NewEncoder(valfile)
defer func() {
_ = encoder.Close()
}()
st.logger.Debugf("Successfully generated the value file at %s. produced:\n%s", path, string(yamlBytes))
if err := encoder.Encode(strMap); err != nil {
return err
}
generatedFiles = append(generatedFiles, valfile.Name())
case map[any]any, map[string]any:
valfile, err := createTempValuesFile(release, typedValue)
if err != nil {
generatedFiles = append(generatedFiles, valfile.Name())
return nil
}(); err != nil {
return generatedFiles, err
}
defer func() {
_ = valfile.Close()
}()
case map[string]any:
if err := func() error {
valfile, err := createTempValuesFile(release, typedValue)
if err != nil {
return err
}
defer func() {
_ = valfile.Close()
}()
encoder := yaml.NewEncoder(valfile)
defer func() {
_ = encoder.Close()
}()
encoder := yaml.NewEncoder(valfile)
defer func() {
_ = encoder.Close()
}()
if err := encoder.Encode(typedValue); err != nil {
if err := encoder.Encode(typedValue); err != nil {
return err
}
generatedFiles = append(generatedFiles, valfile.Name())
return nil
}(); err != nil {
return generatedFiles, err
}
generatedFiles = append(generatedFiles, valfile.Name())
default:
return generatedFiles, fmt.Errorf("unexpected type of value: value=%v, type=%T", typedValue, typedValue)
}