diff --git a/cmd/apply.go b/cmd/apply.go index 862a0377..d458e4b9 100644 --- a/cmd/apply.go +++ b/cmd/apply.go @@ -59,7 +59,7 @@ func NewApplyCmd(globalCfg *config.GlobalImpl) *cobra.Command { f.BoolVar(&applyOptions.SkipDeps, "skip-deps", false, `skip running "helm repo update" and "helm dependency build"`) f.BoolVar(&applyOptions.Wait, "wait", false, `Override helmDefaults.wait setting "helm upgrade --install --wait"`) f.BoolVar(&applyOptions.WaitForJobs, "wait-for-jobs", false, `Override helmDefaults.waitForJobs setting "helm upgrade --install --wait-for-jobs"`) - f.BoolVar(&applyOptions.ReuseValues, "reuse-values", false, "reuse the last release's values and merge in any overrides from other sources") + f.BoolVar(&applyOptions.ReuseValues, "reuse-values", false, `Override helmDefaults.reuseValues "helm upgrade --install --reuse-values"`) return cmd } diff --git a/cmd/diff.go b/cmd/diff.go index 18ac5a18..4796baea 100644 --- a/cmd/diff.go +++ b/cmd/diff.go @@ -49,7 +49,7 @@ func NewDiffCmd(globalCfg *config.GlobalImpl) *cobra.Command { f.StringVar(&diffOptions.Output, "output", "", "output format for diff plugin") f.BoolVar(&diffOptions.SuppressSecrets, "suppress-secrets", false, "suppress secrets in the output. highly recommended to specify on CI/CD use-cases") f.StringArrayVar(&diffOptions.Suppress, "suppress", nil, "suppress specified Kubernetes objects in the output. Can be provided multiple times. For example: --suppress KeycloakClient --suppress VaultSecret") - f.BoolVar(&diffOptions.ReuseValues, "reuse-values", false, "reuse the last release's values and merge in any overrides from other sources") + f.BoolVar(&diffOptions.ReuseValues, "reuse-values", false, `Override helmDefaults.reuseValues "helm diff upgrade --install --reuse-values"`) return cmd } diff --git a/cmd/sync.go b/cmd/sync.go index de0632aa..33ab4cff 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -43,7 +43,7 @@ func NewSyncCmd(globalCfg *config.GlobalImpl) *cobra.Command { f.BoolVar(&syncOptions.SkipDeps, "skip-deps", false, `skip running "helm repo update" and "helm dependency build"`) f.BoolVar(&syncOptions.Wait, "wait", false, `Override helmDefaults.wait setting "helm upgrade --install --wait"`) f.BoolVar(&syncOptions.WaitForJobs, "wait-for-jobs", false, `Override helmDefaults.waitForJobs setting "helm upgrade --install --wait-for-jobs"`) - f.BoolVar(&syncOptions.ReuseValues, "reuse-values", false, "reuse the last release's values and merge in any overrides from other sources") + f.BoolVar(&syncOptions.ReuseValues, "reuse-values", false, `Override helmDefaults.reuseValues "helm upgrade --install --reuse-values"`) return cmd } diff --git a/docs/index.md b/docs/index.md index 7604c80f..35fb0ea8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -213,6 +213,8 @@ helmDefaults: # When set to `true`, skips running `helm dep up` and `helm dep build` on this release's chart. # Useful when the chart is broken, like seen in https://github.com/roboll/helmfile/issues/1547 skipDeps: false + # if set to true, reuses the last release's values and merges them with ones provided in helmfile. + reuseValues: false # these labels will be applied to all releases in a Helmfile. Useful in templating if you have a helmfile per environment or customer and don't want to copy the same label to each release commonLabels: diff --git a/pkg/state/state.go b/pkg/state/state.go index 4b991692..578e639d 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -150,6 +150,8 @@ type HelmSpec struct { // This is relevant only when your release uses a local chart or a directory containing K8s manifests or a Kustomization // as a Helm chart. SkipDeps bool `yaml:"skipDeps"` + // on helm upgrade/diff, reuse values currently set in the release and merge them with the ones defined within helmfile + ReuseValues bool `yaml:"reuseValues"` TLS bool `yaml:"tls"` TLSCACert string `yaml:"tlsCACert,omitempty"` @@ -584,7 +586,7 @@ func (st *HelmState) prepareSyncReleases(helm helmexec.Interface, additionalValu flags = append(flags, "--wait-for-jobs") } - if opts.ReuseValues { + if opts.ReuseValues || st.HelmDefaults.ReuseValues { flags = append(flags, "--reuse-values") } else { flags = append(flags, "--reset-values") @@ -1626,6 +1628,62 @@ type diffPrepareResult struct { upgradeDueToSkippedDiff bool } +func (st *HelmState) commonDiffFlags(detailedExitCode bool, includeTests bool, suppress []string, suppressSecrets bool, showSecrets bool, noHooks bool, opt *DiffOpts) []string { + var flags []string + + if detailedExitCode { + flags = append(flags, "--detailed-exitcode") + } + + if includeTests { + flags = append(flags, "--include-tests") + } + + for _, s := range suppress { + flags = append(flags, "--suppress", s) + } + + if suppressSecrets { + flags = append(flags, "--suppress-secrets") + } + + if showSecrets { + flags = append(flags, "--show-secrets") + } + + if noHooks { + flags = append(flags, "--no-hooks") + } + + if opt.NoColor { + flags = append(flags, "--no-color") + } else if opt.Color { + flags = append(flags, "--color") + } + + if opt.Context > 0 { + flags = append(flags, "--context", fmt.Sprintf("%d", opt.Context)) + } + + if opt.Output != "" { + flags = append(flags, "--output", opt.Output) + } + + if opt.ReuseValues || st.HelmDefaults.ReuseValues { + flags = append(flags, "--reuse-values") + } else { + flags = append(flags, "--reset-values") + } + + if opt.Set != nil { + for _, s := range opt.Set { + flags = append(flags, "--set", s) + } + } + + return flags +} + func (st *HelmState) prepareDiffReleases(helm helmexec.Interface, additionalValues []string, concurrency int, detailedExitCode bool, includeTests bool, suppress []string, suppressSecrets bool, showSecrets bool, noHooks bool, opts ...DiffOpt) ([]diffPrepareResult, []error) { opt := &DiffOpts{} for _, o := range opts { @@ -1670,6 +1728,7 @@ func (st *HelmState) prepareDiffReleases(helm helmexec.Interface, additionalValu jobs := make(chan *ReleaseSpec, numReleases) results := make(chan diffPrepareResult, numReleases) resultsMap := map[string]diffPrepareResult{} + commonDiffFlags := st.commonDiffFlags(detailedExitCode, includeTests, suppress, suppressSecrets, showSecrets, noHooks, opt) rs := []diffPrepareResult{} errs := []error{} @@ -1719,55 +1778,7 @@ func (st *HelmState) prepareDiffReleases(helm helmexec.Interface, additionalValu flags = append(flags, "--values", valfile) } - if detailedExitCode { - flags = append(flags, "--detailed-exitcode") - } - - if includeTests { - flags = append(flags, "--include-tests") - } - - for _, s := range suppress { - flags = append(flags, "--suppress", s) - } - - if suppressSecrets { - flags = append(flags, "--suppress-secrets") - } - - if showSecrets { - flags = append(flags, "--show-secrets") - } - - if noHooks { - flags = append(flags, "--no-hooks") - } - - if opt.NoColor { - flags = append(flags, "--no-color") - } else if opt.Color { - flags = append(flags, "--color") - } - - if opt.Context > 0 { - flags = append(flags, "--context", fmt.Sprintf("%d", opt.Context)) - } - - if opt.Output != "" { - flags = append(flags, "--output", opt.Output) - } - - if opt.ReuseValues { - flags = append(flags, "--reuse-values") - } else { - flags = append(flags, "--reset-values") - } - - if opt.Set != nil { - for _, s := range opt.Set { - flags = append(flags, "--set", s) - } - } + flags = append(flags, commonDiffFlags...) if len(errs) > 0 { rsErrs := make([]*ReleaseError, len(errs)) diff --git a/pkg/state/state_test.go b/pkg/state/state_test.go index 311c8594..3e706205 100644 --- a/pkg/state/state_test.go +++ b/pkg/state/state_test.go @@ -2507,9 +2507,10 @@ func TestHelmState_Delete(t *testing.T) { func TestDiffpareSyncReleases(t *testing.T) { tests := []struct { - name string - flags []string - diffOptions *DiffOpts + name string + flags []string + diffOptions *DiffOpts + helmDefaults *HelmSpec }{ { name: "reuse-values", @@ -2517,11 +2518,21 @@ func TestDiffpareSyncReleases(t *testing.T) { diffOptions: &DiffOpts{ ReuseValues: true, }, + helmDefaults: &HelmSpec{}, }, { - name: "reset-values", - flags: []string{"--reset-values"}, + name: "reset-values", + flags: []string{"--reset-values"}, + diffOptions: &DiffOpts{}, + helmDefaults: &HelmSpec{}, + }, + { + name: "default-reuse-values", + flags: []string{"--reuse-values"}, diffOptions: &DiffOpts{}, + helmDefaults: &HelmSpec{ + ReuseValues: true, + }, }, } @@ -2534,7 +2545,8 @@ func TestDiffpareSyncReleases(t *testing.T) { } state := &HelmState{ ReleaseSetSpec: ReleaseSetSpec{ - Releases: releases, + Releases: releases, + HelmDefaults: *tt.helmDefaults, }, logger: logger, valsRuntime: valsRuntime, @@ -2555,9 +2567,10 @@ func TestDiffpareSyncReleases(t *testing.T) { func TestPrepareSyncReleases(t *testing.T) { tests := []struct { - name string - flags []string - syncOptions *SyncOpts + name string + flags []string + syncOptions *SyncOpts + helmDefaults *HelmSpec }{ { name: "reuse-values", @@ -2565,11 +2578,21 @@ func TestPrepareSyncReleases(t *testing.T) { syncOptions: &SyncOpts{ ReuseValues: true, }, + helmDefaults: &HelmSpec{}, }, { - name: "reset-values", - flags: []string{"--reset-values"}, + name: "reset-values", + flags: []string{"--reset-values"}, + syncOptions: &SyncOpts{}, + helmDefaults: &HelmSpec{}, + }, + { + name: "reuse-default-values", + flags: []string{"--reuse-values"}, syncOptions: &SyncOpts{}, + helmDefaults: &HelmSpec{ + ReuseValues: true, + }, }, } @@ -2582,7 +2605,8 @@ func TestPrepareSyncReleases(t *testing.T) { } state := &HelmState{ ReleaseSetSpec: ReleaseSetSpec{ - Releases: releases, + Releases: releases, + HelmDefaults: *tt.helmDefaults, }, logger: logger, valsRuntime: valsRuntime,