Repository: helm/helm
File: pkg/action/hooks.go (Go)

Code before:
	"helm.sh/helm/v4/pkg/kube"

	"go.yaml.in/yaml/v3"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	release "helm.sh/helm/v4/pkg/release/v1"
)

// execHook executes all of the hooks for the given hook event.
func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent, waitStrategy kube.WaitStrategy, timeout time.Duration, serverSideApply bool) error {
	shutdown, err := cfg.execHookWithDelayedShutdown(rl, hook, waitStrategy, timeout, serverSideApply)
	if shutdown == nil {
		return nil
	}
	if err != nil {
		if err := shutdown(); err != nil {
			return err
		}
		return err
	}
	return shutdown()
}

type ExecuteShutdownHooks = func() error

func ShutdownNoOp() error {
	return nil
}

// execHookWithDelayedShutdown executes all of the hooks for the given hook event and returns a shutdownHook function to trigger deletions after doing other things like e.g. retrieving logs.
func (cfg *Configuration) execHookWithDelayedShutdown(rl *release.Release, hook release.HookEvent, waitStrategy kube.WaitStrategy, timeout time.Duration, serverSideApply bool) (ExecuteShutdownHooks, error) {
	executingHooks := []*release.Hook{}

	for _, h := range rl.Hooks {
		for _, e := range h.Events {
			if e == hook {
				executingHooks = append(executingHooks, h)
			}
		}
	}

	// hooke are pre-ordered by kind, so keep order stable
	sort.Stable(hookByWeight(executingHooks))

	for i, h := range executingHooks {
		// Set default delete policy to before-hook-creation
		cfg.hookSetDeletePolicy(h)

		if err := cfg.deleteHookByPolicy(h, release.HookBeforeHookCreation, waitStrategy, timeout); err != nil {
			return ShutdownNoOp, err
		}

Review comment (suggestion):
I'd leave this privately scoped (`shutdownNoOp`) and make it public only if necessary. It allow flexibility of making changes later on

Code after:
	"helm.sh/helm/v4/pkg/kube"

	"go.yaml.in/yaml/v3"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	release "helm.sh/helm/v4/pkg/release/v1"
)

// execHook executes all of the hooks for the given hook event.
func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent, waitStrategy kube.WaitStrategy, timeout time.Duration, serverSideApply bool) error {
	shutdown, err := cfg.execHookWithDelayedShutdown(rl, hook, waitStrategy, timeout, serverSideApply)
	if shutdown == nil {
		return err
	}
	if err != nil {
		if err := shutdown(); err != nil {
			return err
		}
		return err
	}
	return shutdown()
}

type ExecuteShutdownFunc = func() error

func shutdownNoOp() error {
	return nil
}

// execHookWithDelayedShutdown executes all of the hooks for the given hook event and returns a shutdownHook function to trigger deletions after doing other things like e.g. retrieving logs.
func (cfg *Configuration) execHookWithDelayedShutdown(rl *release.Release, hook release.HookEvent, waitStrategy kube.WaitStrategy, timeout time.Duration, serverSideApply bool) (ExecuteShutdownFunc, error) {
	executingHooks := []*release.Hook{}

	for _, h := range rl.Hooks {
		for _, e := range h.Events {
			if e == hook {
				executingHooks = append(executingHooks, h)
			}
		}
	}

	// hooke are pre-ordered by kind, so keep order stable
	sort.Stable(hookByWeight(executingHooks))

	for i, h := range executingHooks {
		// Set default delete policy to before-hook-creation
		cfg.hookSetDeletePolicy(h)

		if err := cfg.deleteHookByPolicy(h, release.HookBeforeHookCreation, waitStrategy, timeout); err != nil {
			return shutdownNoOp, err
		}