diff --git a/pkg/action/hooks.go b/pkg/action/hooks.go index 40c1ffdb6..c81e8997f 100644 --- a/pkg/action/hooks.go +++ b/pkg/action/hooks.go @@ -38,7 +38,7 @@ func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent, } } - // hooke are pre-ordered by kind, so keep order stable + // hooks are pre-ordered by kind, so keep order stable sort.Stable(hookByWeight(executingHooks)) for _, h := range executingHooks { @@ -107,6 +107,39 @@ func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent, return nil } +func (cfg *Configuration) hasPostInstallHooks(rl *release.Release) bool { + for _, h := range rl.Hooks { + for _, e := range h.Events { + if e == release.HookPostInstall { + return true + } + } + } + return false +} + +func (cfg *Configuration) hasPostUpgradeHooks(rl *release.Release) bool { + for _, h := range rl.Hooks { + for _, e := range h.Events { + if e == release.HookPostUpgrade { + return true + } + } + } + return false +} + +func (cfg *Configuration) hasPostRollbackHooks(rl *release.Release) bool { + for _, h := range rl.Hooks { + for _, e := range h.Events { + if e == release.HookPostRollback { + return true + } + } + } + return false +} + // hookByWeight is a sorter for hooks type hookByWeight []*release.Hook diff --git a/pkg/action/hooks_test.go b/pkg/action/hooks_test.go new file mode 100644 index 000000000..843807de5 --- /dev/null +++ b/pkg/action/hooks_test.go @@ -0,0 +1,133 @@ +/* +Copyright The Helm Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package action + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "helm.sh/helm/v4/pkg/release" +) + +func TestConfiguration_hasPostInstallHooks(t *testing.T) { + type args struct { + rl *release.Release + } + tests := []struct { + name string + args args + want bool + }{ + {name: "return true when chart has post-install hooks", + args: args{rl: &release.Release{ + Hooks: []*release.Hook{{Events: []release.HookEvent{release.HookPostInstall}}}, + }, + }, + want: true, + }, + {name: "return false when chart does not have post-install hooks", + args: args{rl: &release.Release{ + Hooks: []*release.Hook{{Events: []release.HookEvent{release.HookPreDelete}}}, + }}, + want: false, + }, + {name: "return false when chart does not have any hooks", + args: args{rl: &release.Release{ + Hooks: []*release.Hook{{Events: []release.HookEvent{}}}, + }}, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cfg := &Configuration{} + assert.Equalf(t, tt.want, cfg.hasPostInstallHooks(tt.args.rl), "hasPostInstallHooks(%v)", tt.args.rl) + }) + } +} +func TestConfiguration_hasPostUpgradeHooks(t *testing.T) { + type args struct { + rl *release.Release + } + tests := []struct { + name string + args args + want bool + }{ + {name: "return true when chart has post-upgrade hooks", + args: args{rl: &release.Release{ + Hooks: []*release.Hook{{Events: []release.HookEvent{release.HookPostUpgrade}}}, + }, + }, + want: true, + }, + {name: "return false when chart does not have post-upgrade hooks", + args: args{rl: &release.Release{ + Hooks: []*release.Hook{{Events: []release.HookEvent{release.HookPreDelete}}}, + }}, + want: false, + }, + {name: "return false when chart does not have any hooks", + args: args{rl: &release.Release{ + Hooks: []*release.Hook{{Events: []release.HookEvent{}}}, + }}, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cfg := &Configuration{} + assert.Equalf(t, tt.want, cfg.hasPostUpgradeHooks(tt.args.rl), "hasPostUpgradeHooks(%v)", tt.args.rl) + }) + } +} +func TestConfiguration_hasPostRollbackHooks(t *testing.T) { + type args struct { + rl *release.Release + } + tests := []struct { + name string + args args + want bool + }{ + {name: "return true when chart has post-rollback hooks", + args: args{rl: &release.Release{ + Hooks: []*release.Hook{{Events: []release.HookEvent{release.HookPostRollback}}}, + }, + }, + want: true, + }, + {name: "return false when chart does not have post-rollback hooks", + args: args{rl: &release.Release{ + Hooks: []*release.Hook{{Events: []release.HookEvent{release.HookPreDelete}}}, + }}, + want: false, + }, + {name: "return false when chart does not have any hooks", + args: args{rl: &release.Release{ + Hooks: []*release.Hook{{Events: []release.HookEvent{}}}, + }}, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cfg := &Configuration{} + assert.Equalf(t, tt.want, cfg.hasPostRollbackHooks(tt.args.rl), "hasPostRollbackHooks(%v)", tt.args.rl) + }) + } +} diff --git a/pkg/action/install.go b/pkg/action/install.go index a5026266d..3ae8d440f 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -432,7 +432,9 @@ func (i *Install) performInstall(c chan<- resultMessage, rel *release.Release, t } } - if i.Wait { + waitBeforePostHooks := !i.DisableHooks && i.cfg.hasPostInstallHooks(rel) || i.cfg.hasPostUpgradeHooks(rel) + + if i.Wait || waitBeforePostHooks { if i.WaitForJobs { if err := i.cfg.KubeClient.WaitWithJobs(resources, i.Timeout); err != nil { i.reportToRun(c, rel, err) diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index f4ae896e3..a03a24acf 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -222,7 +222,9 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas } } - if r.Wait { + waitBeforePostHooks := !r.DisableHooks && r.cfg.hasPostRollbackHooks(targetRelease) + + if r.Wait || waitBeforePostHooks { if r.WaitForJobs { if err := r.cfg.KubeClient.WaitWithJobs(target, r.Timeout); err != nil { targetRelease.SetStatus(release.StatusFailed, fmt.Sprintf("Release %q failed: %s", targetRelease.Name, err.Error()))