helpers/pull_policies/pull_policies.go (51 lines of code) (raw):
package pull_policies
import (
"fmt"
"slices"
)
// ComputeEffectivePullPolicies returns the intersection of the specified pullPolices and allowedPullPolicies, or
// an error if pullPolicies is not empty but the intersection IS empty. In other words, it limits pullPolicies to what
// is in allowedPullPolicies, and returns an error if none of pullPolicies was in allowedPullPolicies. All of the
// arguments are ultimately ~[]string, but defined in different ways.
func ComputeEffectivePullPolicies[A ~string, B ~string, C ~[]string](pullPolicies, allowedPullPolicies []A, ciPullPolicies []B, executorPullPoilcies C) ([]A, error) {
if len(pullPolicies) == 0 {
return allowedPullPolicies, nil
}
if len(allowedPullPolicies) == 0 {
return pullPolicies, nil
}
var actuallyAllowed []A
for _, policy := range pullPolicies {
if slices.Contains(allowedPullPolicies, policy) {
actuallyAllowed = append(actuallyAllowed, policy)
}
}
if len(actuallyAllowed) == 0 {
return nil, &incompatiblePullPolicyError[A]{
pullPolicies: pullPolicies,
allowedPullPolicies: allowedPullPolicies,
pullPolicySource: getPullPolicySource(ciPullPolicies, executorPullPoilcies),
}
}
return actuallyAllowed, nil
}
// getPullPolicySource returns the source (i.e. file) of the pull_policy
// configuration used by this runner. This is used to produce a more detailed
// error message. See https://gitlab.com/gitlab-org/gitlab-runner/-/issues/29115
func getPullPolicySource[A ~string, B ~[]string](ciPullPolicies []A, executorPullPolicies B) string {
switch {
case len(ciPullPolicies) != 0:
return pullPolicySourceGitLabCI
case len(executorPullPolicies) != 0:
return pullPolicySourceRunner
default:
return pullPolicySourceDefault
}
}
const (
incompatiblePullPolicy = "pull_policy (%v) defined in %s is not one of the allowed_pull_policies (%v)"
pullPolicySourceGitLabCI = "GitLab pipeline config"
pullPolicySourceRunner = "Runner config"
pullPolicySourceDefault = "Runner config (default)"
)
type incompatiblePullPolicyError[T ~string] struct {
pullPolicySource string
pullPolicies []T
allowedPullPolicies []T
}
func (e *incompatiblePullPolicyError[T]) Error() string {
return fmt.Sprintf(incompatiblePullPolicy, e.pullPolicies, e.pullPolicySource, e.allowedPullPolicies)
}