Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions cmd/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ func (d *diffCmd) template(isUpgrade bool) ([]byte, error) {
if d.insecureSkipTLSVerify {
flags = append(flags, "--insecure-skip-tls-verify")
}
// Helm automatically enable --reuse-values when there's no --set, --set-string, --set-json, --set-values, --set-file present.
// Helm automatically reuses the user-supplied values of the last release when there's no --set, --set-string, --set-json, --set-values, --set-file present.
// Let's simulate that in helm-diff.
// See https://medium.com/@kcatstack/understand-helm-upgrade-flags-reset-values-reuse-values-6e58ac8f127e
shouldDefaultReusingValues := len(d.values) == 0 && len(d.stringValues) == 0 && len(d.stringLiteralValues) == 0 && len(d.jsonValues) == 0 && len(d.valueFiles) == 0 && len(d.fileValues) == 0
Expand All @@ -240,12 +240,23 @@ func (d *diffCmd) template(isUpgrade bool) ([]byte, error) {
}
err = d.writeExistingValues(tmpfile, false)
} else {
err = d.writeExistingValues(tmpfile, true)
// Only --reuse-values also reuses the values of the chart that the release was installed from.
// By default, Helm reuses just the user-supplied values, so that changes to the values.yaml
// of the chart take effect. See https://github.com/databus23/helm-diff/issues/464
err = d.writeExistingValues(tmpfile, d.reuseValues)
}
if err != nil {
return nil, err
}
flags = append(flags, "--values", tmpfile.Name())
existingValues, err := os.ReadFile(tmpfile.Name())
if err != nil {
return nil, err
}
// `helm get values` prints "null" for a release without user-supplied values.
// There is nothing to reuse then.
if v := bytes.TrimSpace(existingValues); len(v) > 0 && !bytes.Equal(v, []byte("null")) {
flags = append(flags, "--values", tmpfile.Name())
}
}
for _, value := range d.values {
flags = append(flags, "--set", value)
Expand Down
7 changes: 6 additions & 1 deletion cmd/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,18 @@ func printFakeHelmVersion() {
}

// printFakeHelmOutput prints the output for a fake helm invocation.
// A `helm version` call prints helm version build info; any other
// A `helm version` call prints helm version build info; a `helm get values`
// call prints HELM_DIFF_FAKE_VALUES_OUTPUT if that is set; any other
// invocation prints HELM_DIFF_FAKE_OUTPUT.
func printFakeHelmOutput() {
if len(os.Args) > 1 && os.Args[1] == "version" {
printFakeHelmVersion()
return
}
if v, ok := os.LookupEnv("HELM_DIFF_FAKE_VALUES_OUTPUT"); ok && len(os.Args) > 2 && os.Args[1] == "get" && os.Args[2] == "values" {
fmt.Print(v)
return
}
fmt.Print(os.Getenv("HELM_DIFF_FAKE_OUTPUT"))
}

Expand Down
39 changes: 35 additions & 4 deletions cmd/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,35 +401,60 @@ data:
fakeHelmMode string
args []string
useUpgradeDryRun bool
// existingValues is what `helm get values` prints for an existing release.
// Empty means that it prints the manifest, which stands in for some values.
existingValues string
// wantGetValues is the expected `helm get values` call.
// Empty means that the values must not be fetched at all.
wantGetValues string
// wantValues is whether the fetched values must be passed on with --values.
wantValues bool
}{
{
name: "existing release with --reuse-values",
fakeHelmMode: "capture_args",
args: []string{"--reuse-values"},
wantGetValues: "get values my-release --output yaml --all --namespace prod-apps\n",
wantValues: true,
},
{
name: "existing release with --reset-then-reuse-values",
fakeHelmMode: "capture_args",
args: []string{"--reset-then-reuse-values"},
wantGetValues: "get values my-release --output yaml --namespace prod-apps\n",
wantValues: true,
},
{
name: "existing release with --install --reuse-values",
fakeHelmMode: "capture_args",
args: []string{"--install", "--reuse-values"},
wantGetValues: "get values my-release --output yaml --all --namespace prod-apps\n",
wantValues: true,
},
{
// Helm enables --reuse-values by default when there is no --set, --set-string,
// --set-literal, --set-json, --values or --set-file flag, so the values of an
// existing release are fetched even without any of the reuse flags.
// Helm reuses the user-supplied values of an existing release when there is no
// --set, --set-string, --set-literal, --set-json, --values or --set-file flag.
// Unlike with --reuse-values, the values of the chart that the release was installed
// from are not reused, so the values are fetched without --all.
// See https://github.com/databus23/helm-diff/issues/464
name: "existing release without value flags",
fakeHelmMode: "capture_args",
wantGetValues: "get values my-release --output yaml --all --namespace prod-apps\n",
wantGetValues: "get values my-release --output yaml --namespace prod-apps\n",
wantValues: true,
},
{
name: "existing release without value flags and HELM_DIFF_USE_UPGRADE_DRY_RUN",
fakeHelmMode: "capture_args",
useUpgradeDryRun: true,
wantGetValues: "get values my-release --output yaml --namespace prod-apps\n",
wantValues: true,
},
{
// `helm get values` prints "null" for a release without user-supplied values.
name: "existing release without value flags and without user-supplied values",
fakeHelmMode: "capture_args",
existingValues: "null\n",
wantGetValues: "get values my-release --output yaml --namespace prod-apps\n",
},
{
name: "unreleased with --install",
Expand Down Expand Up @@ -468,6 +493,9 @@ data:
t.Run(tc.name, func(t *testing.T) {
argsFile := t.TempDir() + "/args"
setupFakeHelm(t, tc.fakeHelmMode, manifestYAML, argsFile, "")
if tc.existingValues != "" {
t.Setenv("HELM_DIFF_FAKE_VALUES_OUTPUT", tc.existingValues)
}
renderSubcmd := "template"
if tc.useUpgradeDryRun {
t.Setenv("HELM_DIFF_USE_UPGRADE_DRY_RUN", "true")
Expand Down Expand Up @@ -499,6 +527,9 @@ data:
} else if !strings.Contains(argsContent, tc.wantGetValues) {
t.Errorf("expected 'helm %s', got:\n%s", strings.TrimSpace(tc.wantGetValues), argsContent)
}
if strings.Contains(argsContent, " --values ") != tc.wantValues {
t.Errorf("expected the existing values to be passed with --values: %t, got:\n%s", tc.wantValues, argsContent)
}
})
}
}
Expand Down
Loading