fix: pass --timeout flag through to helm for sync and apply (#2495)

* fix: propagate timeout flag

Signed-off-by: Hristiyan Ivanov <hristiyan.d.ivanov@gmail.com>

* test: add test for propagating timeout flag

Signed-off-by: Hristiyan Ivanov <hristiyan.d.ivanov@gmail.com>

* feat: add timeout flag to apply command

Signed-off-by: Hristiyan Ivanov <hristiyan.d.ivanov@gmail.com>

* test: add test for timeout flag for helmfile apply

Signed-off-by: Hristiyan Ivanov <hristiyan.d.ivanov@gmail.com>

* fix: improve description of timeout flag

Signed-off-by: Hristiyan Ivanov <hristiyan.d.ivanov@gmail.com>

---------

Signed-off-by: Hristiyan Ivanov <hristiyan.d.ivanov@gmail.com>
This commit is contained in:
Hristiyan Ivanov 2026-03-22 00:34:33 +01:00 committed by GitHub
parent 43b426892e
commit 5c67cbcd6a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 92 additions and 1 deletions

View File

@ -61,6 +61,7 @@ func NewApplyCmd(globalCfg *config.GlobalImpl) *cobra.Command {
f.BoolVar(&applyOptions.SuppressDiff, "suppress-diff", false, "suppress diff in the output. Usable in new installs")
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.IntVar(&applyOptions.Timeout, "timeout", 0, `Override helmDefaults.timeout in seconds for "helm upgrade --install --timeout" (default 0, which uses helmDefaults.timeout or helm's default if not set)`)
f.BoolVar(&applyOptions.ReuseValues, "reuse-values", false, `Override helmDefaults.reuseValues "helm upgrade --install --reuse-values"`)
f.BoolVar(&applyOptions.ResetValues, "reset-values", false, `Override helmDefaults.reuseValues "helm upgrade --install --reset-values"`)
f.StringVar(&applyOptions.PostRenderer, "post-renderer", "", `pass --post-renderer to "helm template" or "helm upgrade --install"`)

View File

@ -47,7 +47,7 @@ func NewSyncCmd(globalCfg *config.GlobalImpl) *cobra.Command {
f.BoolVar(&syncOptions.SyncReleaseLabels, "sync-release-labels", false, "sync release labels to the target release")
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.IntVar(&syncOptions.Timeout, "timeout", 0, `Override helmDefaults.timeout setting "helm upgrade --install --timeout" (default 0, which means no timeout)`)
f.IntVar(&syncOptions.Timeout, "timeout", 0, `Override helmDefaults.timeout in seconds for "helm upgrade --install --timeout" (default 0, which uses helmDefaults.timeout or helm's default if not set)`)
f.BoolVar(&syncOptions.ReuseValues, "reuse-values", false, `Override helmDefaults.reuseValues "helm upgrade --install --reuse-values"`)
f.BoolVar(&syncOptions.ResetValues, "reset-values", false, `Override helmDefaults.reuseValues "helm upgrade --install --reset-values"`)
f.StringVar(&syncOptions.PostRenderer, "post-renderer", "", `pass --post-renderer to "helm template" or "helm upgrade --install"`)

View File

@ -1785,6 +1785,7 @@ Do you really want to apply?
Wait: c.Wait(),
WaitRetries: c.WaitRetries(),
WaitForJobs: c.WaitForJobs(),
Timeout: c.Timeout(),
ReuseValues: c.ReuseValues(),
ResetValues: c.ResetValues(),
PostRenderer: c.PostRenderer(),
@ -2253,6 +2254,7 @@ Do you really want to sync?
Wait: c.Wait(),
WaitRetries: c.WaitRetries(),
WaitForJobs: c.WaitForJobs(),
Timeout: c.Timeout(),
ReuseValues: c.ReuseValues(),
ResetValues: c.ResetValues(),
PostRenderer: c.PostRenderer(),

View File

@ -25,6 +25,7 @@ func TestApply_2(t *testing.T) {
fields fields
ns string
concurrency int
timeout int
skipDiffOnInstall bool
error string
files map[string]string
@ -84,6 +85,7 @@ func TestApply_2(t *testing.T) {
syncErr := app.Apply(applyConfig{
// if we check log output, concurrency must be 1. otherwise the test becomes non-deterministic.
concurrency: tc.concurrency,
timeout: tc.timeout,
logger: logger,
skipDiffOnInstall: tc.skipDiffOnInstall,
skipNeeds: tc.fields.skipNeeds,
@ -653,4 +655,30 @@ foo 4 Fri Nov 1 08:40:07 2019 DEPLOYED raw-3.1.0 3.1.0 default
concurrency: 1,
})
})
t.Run("timeout flag is passed to helm", func(t *testing.T) {
check(t, testcase{
files: map[string]string{
"/path/to/helmfile.yaml": `
releases:
- name: my-release
chart: incubator/raw
namespace: default
`,
},
timeout: 300,
concurrency: 1,
upgraded: []exectest.Release{
{Name: "my-release", Flags: []string{"--timeout", "300s", "--kube-context", "default", "--namespace", "default"}},
},
diffs: map[exectest.DiffKey]error{
{Name: "my-release", Chart: "incubator/raw", Flags: "--kube-context default --namespace default --reset-values --detailed-exitcode"}: helmexec.ExitError{Code: 2},
},
lists: map[exectest.ListKey]string{
{Filter: "^my-release$", Flags: listFlags("default", "default")}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
my-release 4 Fri Nov 1 08:40:07 2019 DEPLOYED raw-3.1.0 3.1.0 default
`,
},
})
})
}

View File

@ -25,6 +25,7 @@ func TestSync(t *testing.T) {
fields fields
ns string
concurrency int
timeout int
skipDiffOnInstall bool
error string
files map[string]string
@ -81,6 +82,7 @@ func TestSync(t *testing.T) {
syncErr := app.Sync(applyConfig{
concurrency: tc.concurrency,
timeout: tc.timeout,
logger: logger,
skipDiffOnInstall: tc.skipDiffOnInstall,
skipNeeds: tc.fields.skipNeeds,
@ -478,4 +480,27 @@ releases:
concurrency: 1,
})
})
t.Run("timeout flag is passed to helm", func(t *testing.T) {
check(t, testcase{
files: map[string]string{
"/path/to/helmfile.yaml": `
releases:
- name: my-release
chart: incubator/raw
namespace: default
`,
},
timeout: 600,
concurrency: 1,
upgraded: []exectest.Release{
{Name: "my-release", Flags: []string{"--timeout", "600s", "--kube-context", "default", "--namespace", "default"}},
},
lists: map[exectest.ListKey]string{
{Filter: "^my-release$", Flags: listFlags("default", "default")}: `NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
my-release 4 Fri Nov 1 08:40:07 2019 DEPLOYED raw-3.1.0 3.1.0 default
`,
},
})
})
}

View File

@ -2369,6 +2369,7 @@ type applyConfig struct {
wait bool
waitRetries int
waitForJobs bool
timeout int
reuseValues bool
postRenderer string
postRendererArgs []string
@ -2409,6 +2410,10 @@ func (a applyConfig) WaitForJobs() bool {
return a.waitForJobs
}
func (a applyConfig) Timeout() int {
return a.timeout
}
func (a applyConfig) Values() []string {
return a.values
}

View File

@ -59,6 +59,7 @@ type ApplyConfigProvider interface {
Wait() bool
WaitRetries() int
WaitForJobs() bool
Timeout() int
IncludeTests() bool
@ -114,6 +115,7 @@ type SyncConfigProvider interface {
Wait() bool
WaitRetries() int
WaitForJobs() bool
Timeout() int
SyncArgs() string
Validate() bool

View File

@ -0,0 +1,21 @@
merged environment: &{default map[] map[] map[]}
1 release(s) found in helmfile.yaml
Affected releases are:
my-release (incubator/raw) UPDATED
invoking preapply hooks for 1 groups of releases in this order:
GROUP RELEASES
1 default/default/my-release
invoking preapply hooks for releases in group 1/1: default/default/my-release
processing 1 groups of releases in this order:
GROUP RELEASES
1 default/default/my-release
processing releases in group 1/1: default/default/my-release
UPDATED RELEASES:
NAME NAMESPACE CHART VERSION DURATION
my-release default incubator/raw 3.1.0 0s

View File

@ -57,6 +57,8 @@ type ApplyOptions struct {
WaitRetries int
// WaitForJobs is true if the helm command should wait for the jobs to be completed
WaitForJobs bool
// Timeout is the timeout for helm operations in seconds
Timeout int
// Propagate '--skip-schema-validation' to helmv3 template and helm install
SkipSchemaValidation bool
// ReuseValues is true if the helm command should reuse the values
@ -235,6 +237,11 @@ func (a *ApplyImpl) WaitForJobs() bool {
return a.ApplyOptions.WaitForJobs
}
// Timeout returns the timeout.
func (a *ApplyImpl) Timeout() int {
return a.ApplyOptions.Timeout
}
// ReuseValues returns the ReuseValues.
func (a *ApplyImpl) ReuseValues() bool {
if !a.ResetValues() {