diff --git a/cmd/apply.go b/cmd/apply.go index bc23438d..d2add4b3 100644 --- a/cmd/apply.go +++ b/cmd/apply.go @@ -42,6 +42,7 @@ func NewApplyCmd(globalCfg *config.GlobalImpl) *cobra.Command { f.BoolVar(&applyOptions.DetailedExitcode, "detailed-exitcode", false, "return a non-zero exit code 2 instead of 0 when there were changes detected AND the changes are synced successfully") f.BoolVar(&applyOptions.StripTrailingCR, "strip-trailing-cr", false, "strip trailing carriage return on input") f.StringVar(&applyOptions.DiffArgs, "diff-args", "", `pass args to helm helm-diff`) + f.StringVar(&applyOptions.SyncArgs, "sync-args", "", `pass args to helm upgrade`) f.StringVar(&globalCfg.GlobalOptions.Args, "args", "", "pass args to helm exec") if !runtime.V1Mode { // TODO: Remove this function once Helmfile v0.x diff --git a/cmd/sync.go b/cmd/sync.go index a0db717e..a779da3a 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -32,6 +32,7 @@ func NewSyncCmd(globalCfg *config.GlobalImpl) *cobra.Command { f := cmd.Flags() f.StringVar(&globalCfg.GlobalOptions.Args, "args", "", "pass args to helm sync") + f.StringVar(&syncOptions.SyncArgs, "sync-args", "", "pass args to helm upgrade") f.StringArrayVar(&syncOptions.Set, "set", nil, "additional values to be merged into the helm command --set flag") f.StringArrayVar(&syncOptions.Values, "values", nil, "additional value files to be merged into the helm command --values flag") f.IntVar(&syncOptions.Concurrency, "concurrency", 0, "maximum number of concurrent helm processes to run, 0 is unlimited") diff --git a/docs/index.md b/docs/index.md index 26deeb29..ef1aa27d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -184,6 +184,8 @@ helmDefaults: - "--set k=v" diffArgs: - "--suppress-secrets" + syncArgs: + - "--labels=app.kubernetes.io/managed-by=helmfile" # verify the chart before upgrading (only works with packaged charts not directories) (default false) verify: true keyring: path/to/keyring.gpg diff --git a/pkg/app/app.go b/pkg/app/app.go index 9edfa166..821ccf44 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -1476,6 +1476,7 @@ Do you really want to apply? ResetValues: c.ResetValues(), PostRenderer: c.PostRenderer(), PostRendererArgs: c.PostRendererArgs(), + SyncArgs: c.SyncArgs(), } return subst.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency(), syncOpts) })) @@ -1869,6 +1870,7 @@ Do you really want to sync? ResetValues: c.ResetValues(), PostRenderer: c.PostRenderer(), PostRendererArgs: c.PostRendererArgs(), + SyncArgs: c.SyncArgs(), } return subst.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency(), opts) })) diff --git a/pkg/app/app_test.go b/pkg/app/app_test.go index 91adcbe9..18754e7d 100644 --- a/pkg/app/app_test.go +++ b/pkg/app/app_test.go @@ -2220,6 +2220,7 @@ type applyConfig struct { stripTrailingCR bool interactive bool skipDiffOnInstall bool + syncArgs string diffArgs string logger *zap.SugaredLogger wait bool @@ -2356,6 +2357,10 @@ func (a applyConfig) SkipDiffOnInstall() bool { return a.skipDiffOnInstall } +func (a applyConfig) SyncArgs() string { + return a.syncArgs +} + func (a applyConfig) DiffArgs() string { return a.diffArgs } diff --git a/pkg/app/config.go b/pkg/app/config.go index 193b997e..fb150320 100644 --- a/pkg/app/config.go +++ b/pkg/app/config.go @@ -83,6 +83,7 @@ type ApplyConfigProvider interface { SkipDiffOnInstall() bool DiffArgs() string + SyncArgs() string DAGConfig @@ -104,6 +105,7 @@ type SyncConfigProvider interface { SkipDeps() bool Wait() bool WaitForJobs() bool + SyncArgs() string Validate() bool diff --git a/pkg/config/apply.go b/pkg/config/apply.go index d26a9dd1..aab6ae7f 100644 --- a/pkg/config/apply.go +++ b/pkg/config/apply.go @@ -64,6 +64,8 @@ type ApplyOptions struct { Cascade string // SuppressOutputLineRegex is a list of regexes to suppress output lines SuppressOutputLineRegex []string + // SyncArgs is the list of arguments to pass to helm upgrade. + SyncArgs string } // NewApply creates a new Apply @@ -240,3 +242,8 @@ func (a *ApplyImpl) Cascade() string { func (a *ApplyImpl) SuppressOutputLineRegex() []string { return a.ApplyOptions.SuppressOutputLineRegex } + +// SyncArgs returns the SyncArgs. +func (a *ApplyImpl) SyncArgs() string { + return a.ApplyOptions.SyncArgs +} diff --git a/pkg/config/sync.go b/pkg/config/sync.go index 7bb71f59..6950e39f 100644 --- a/pkg/config/sync.go +++ b/pkg/config/sync.go @@ -32,6 +32,8 @@ type SyncOptions struct { PostRendererArgs []string // Cascade '--cascade' to helmv3 delete, available values: background, foreground, or orphan, default: background Cascade string + // SyncArgs is the list of arguments to pass to the helm upgrade command. + SyncArgs string } // NewSyncOptions creates a new Apply @@ -132,3 +134,8 @@ func (t *SyncImpl) PostRendererArgs() []string { func (t *SyncImpl) Cascade() string { return t.SyncOptions.Cascade } + +// SyncArgs returns the sync args +func (t *SyncImpl) SyncArgs() string { + return t.SyncOptions.SyncArgs +} diff --git a/pkg/state/state.go b/pkg/state/state.go index 4070bcdb..0bb248ca 100644 --- a/pkg/state/state.go +++ b/pkg/state/state.go @@ -152,6 +152,7 @@ type HelmSpec struct { KubeContext string `yaml:"kubeContext,omitempty"` Args []string `yaml:"args,omitempty"` DiffArgs []string `yaml:"diffArgs,omitempty"` + SyncArgs []string `yaml:"syncArgs,omitempty"` Verify bool `yaml:"verify"` Keyring string `yaml:"keyring,omitempty"` // EnableDNS, when set to true, enable DNS lookups when rendering templates @@ -740,6 +741,7 @@ type SyncOpts struct { ResetValues bool PostRenderer string PostRendererArgs []string + SyncArgs string } type SyncOpt interface{ Apply(*SyncOpts) } @@ -2517,6 +2519,20 @@ func (st *HelmState) appendExtraDiffFlags(flags []string, opt *DiffOpts) []strin return flags } +// appendExtraSyncFlags appends extra diff flags to the given flags slice based on the provided options. +// If opt is not nil and opt.SyncArgs is not empty, it collects the arguments from opt.SyncArgs and appends them to flags. +// If st.HelmDefaults.SyncArgs is not nil, it joins the arguments with a space and appends them to flags. +// The updated flags slice is returned. +func (st *HelmState) appendExtraSyncFlags(flags []string, opt *SyncOpts) []string { + switch { + case opt != nil && opt.SyncArgs != "": + flags = append(flags, argparser.CollectArgs(opt.SyncArgs)...) + case st.HelmDefaults.SyncArgs != nil: + flags = append(flags, argparser.CollectArgs(strings.Join(st.HelmDefaults.SyncArgs, " "))...) + } + return flags +} + // appendKeyringFlags append all the helm command-line flags related to keyring func (st *HelmState) appendKeyringFlags(flags []string, release *ReleaseSpec) []string { switch { @@ -2633,6 +2649,8 @@ func (st *HelmState) flagsForUpgrade(helm helmexec.Interface, release *ReleaseSp } flags = st.appendPostRenderArgsFlags(flags, release, postRendererArgs) + flags = st.appendExtraSyncFlags(flags, opt) + common, clean, err := st.namespaceAndValuesFlags(helm, release, workerIndex) if err != nil { return nil, clean, err diff --git a/pkg/state/state_test.go b/pkg/state/state_test.go index f50bb261..c8dd1836 100644 --- a/pkg/state/state_test.go +++ b/pkg/state/state_test.go @@ -3477,3 +3477,99 @@ func TestHideChartURL(t *testing.T) { } } } + +func Test_appendExtraDiffFlags(t *testing.T) { + tests := []struct { + name string + inputFlags []string + inputOpts *DiffOpts + inputDefaults []string + + expected []string + }{ + { + name: "Skipping default flags, because diffOpts is provided", + inputFlags: []string{"aaaaa"}, + inputOpts: &DiffOpts{ + DiffArgs: "-bbbb --cccc", + }, + inputDefaults: []string{"-dddd", "--eeee"}, + expected: []string{"aaaaa", "-bbbb", "--cccc"}, + }, + { + name: "Use default flags, because diffOpts is not provided", + inputFlags: []string{"aaaaa"}, + inputDefaults: []string{"-dddd", "--eeee"}, + expected: []string{"aaaaa", "-dddd", "--eeee"}, + }, + { + name: "Don't add non-flag arguments", + inputFlags: []string{"aaaaa"}, + inputDefaults: []string{"-d=ddd", "non-flag", "--eeee"}, + expected: []string{"aaaaa", "-d=ddd", "--eeee"}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result := (&HelmState{ + ReleaseSetSpec: ReleaseSetSpec{ + HelmDefaults: HelmSpec{ + DiffArgs: test.inputDefaults, + }, + }, + }).appendExtraDiffFlags(test.inputFlags, test.inputOpts) + if !reflect.DeepEqual(result, test.expected) { + t.Errorf("For input %v %v, expected %v, but got %v", test.inputFlags, test.inputOpts, test.expected, result) + } + }) + } +} + +func Test_appendExtraSyncFlags(t *testing.T) { + tests := []struct { + name string + inputFlags []string + inputOpts *SyncOpts + inputDefaults []string + + expected []string + }{ + { + name: "Skipping default flags, because diffOpts is provided", + inputFlags: []string{"aaaaa"}, + inputOpts: &SyncOpts{ + SyncArgs: "-bbbb --cccc", + }, + inputDefaults: []string{"-dddd", "--eeee"}, + expected: []string{"aaaaa", "-bbbb", "--cccc"}, + }, + { + name: "Use default flags, because diffOpts is not provided", + inputFlags: []string{"aaaaa"}, + inputDefaults: []string{"-dddd", "--eeee"}, + expected: []string{"aaaaa", "-dddd", "--eeee"}, + }, + { + name: "Don't add non-flag arguments", + inputFlags: []string{"aaaaa"}, + inputDefaults: []string{"-d=ddd", "non-flag", "--eeee"}, + expected: []string{"aaaaa", "-d=ddd", "--eeee"}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result := (&HelmState{ + ReleaseSetSpec: ReleaseSetSpec{ + HelmDefaults: HelmSpec{ + SyncArgs: test.inputDefaults, + }, + }, + }).appendExtraSyncFlags(test.inputFlags, test.inputOpts) + if !reflect.DeepEqual(result, test.expected) { + t.Errorf("For input %v %v, expected %v, but got %v", test.inputFlags, test.inputOpts, test.expected, result) + } + }) + } +}