diff --git a/pkg/environment/environment_test.go b/pkg/environment/environment_test.go index cd4f0fba..0883d28e 100644 --- a/pkg/environment/environment_test.go +++ b/pkg/environment/environment_test.go @@ -205,3 +205,33 @@ func TestEnvironment_GetMergedValues_Issue2281_SparseArrayMerge(t *testing.T) { assert.Equal(t, "second thing", elem1["thing"]) assert.Equal(t, "cmdline", elem1["anotherThing"]) } + +func TestEnvironment_GetMergedValues_Issue2527_DefaultsOverrideValues(t *testing.T) { + env := &Environment{ + Name: "test", + Defaults: map[string]any{ + "helmDefaults": map[string]any{ + "atomic": false, + "wait": true, + "timeout": 300, + }, + }, + Values: map[string]any{ + "appName": "my-app", + "helmDefaults": map[string]any{ + "atomic": true, + "wait": true, + "timeout": 300, + }, + }, + CLIOverrides: map[string]any{}, + } + + mergedValues, err := env.GetMergedValues() + require.NoError(t, err) + + hd := mergedValues["helmDefaults"].(map[string]any) + assert.Equal(t, true, hd["atomic"], "Values should override Defaults atomic value") + assert.Equal(t, true, hd["wait"]) + assert.Equal(t, 300, hd["timeout"]) +} diff --git a/pkg/state/types.go b/pkg/state/types.go index b210bf19..991ac73b 100644 --- a/pkg/state/types.go +++ b/pkg/state/types.go @@ -2,6 +2,7 @@ package state import ( "github.com/helmfile/helmfile/pkg/environment" + "github.com/helmfile/helmfile/pkg/maputil" ) // TemplateSpec defines the structure of a reusable and composable template for helm releases. @@ -21,11 +22,9 @@ type EnvironmentTemplateData struct { } func NewEnvironmentTemplateData(env environment.Environment, namespace string, values map[string]any) *EnvironmentTemplateData { - // Create a copy of the environment with merged values for template access. - // This ensures templates accessing .Environment.Values see the same merged values - // (Defaults + Values + CLIOverrides) as templates accessing .Values directly. envCopy := env - envCopy.Values = values + envCopy.Values = maputil.MergeMaps(env.Values, env.CLIOverrides, + maputil.MergeOptions{ArrayStrategy: maputil.ArrayMergeStrategyMerge}) d := EnvironmentTemplateData{envCopy, namespace, values, nil} d.StateValues = &d.Values return &d diff --git a/pkg/state/types_test.go b/pkg/state/types_test.go new file mode 100644 index 00000000..dd22c8d1 --- /dev/null +++ b/pkg/state/types_test.go @@ -0,0 +1,52 @@ +package state + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/helmfile/helmfile/pkg/environment" +) + +func TestNewEnvironmentTemplateData_EnvironmentValuesExcludesDefaults_Issue2527(t *testing.T) { + env := environment.Environment{ + Name: "myenv", + Defaults: map[string]any{ + "helmDefaults": map[string]any{ + "atomic": true, + "wait": true, + "timeout": 300, + }, + }, + Values: map[string]any{ + "appName": "my-app", + }, + CLIOverrides: map[string]any{ + "cliFlag": "cliValue", + }, + } + + mergedVals := map[string]any{ + "appName": "my-app", + "cliFlag": "cliValue", + "helmDefaults": map[string]any{ + "atomic": true, + "wait": true, + "timeout": 300, + }, + } + + tmplData := NewEnvironmentTemplateData(env, "ns", mergedVals) + require.NotNil(t, tmplData) + + assert.Equal(t, mergedVals, tmplData.Values, ".Values should contain full merged values") + + _, hasDefaults := tmplData.Environment.Values["helmDefaults"] + assert.False(t, hasDefaults, ".Environment.Values should NOT contain Defaults (helmDefaults)") + + assert.Equal(t, "my-app", tmplData.Environment.Values["appName"], + ".Environment.Values should contain env Values") + assert.Equal(t, "cliValue", tmplData.Environment.Values["cliFlag"], + ".Environment.Values should contain CLI overrides") +}