diff --git a/pkg/state/create_test.go b/pkg/state/create_test.go index 21fcafca..164d811b 100644 --- a/pkg/state/create_test.go +++ b/pkg/state/create_test.go @@ -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]) diff --git a/pkg/state/state.go b/pkg/state/state.go index b6c83744..dc372ab8 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -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) }