Skip to content

Commit d03f05e

Browse files
authored
Merge branch 'main' into fix-update-concurrency-group-expression-in-e2e-wor
2 parents 040ca77 + 6bd5498 commit d03f05e

File tree

13 files changed

+892
-176
lines changed

13 files changed

+892
-176
lines changed

config/302-pac-configmap.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,18 @@ data:
9090
error-detection-simple-regexp: |-
9191
^(?P<filename>[^:]*):(?P<line>[0-9]+):(?P<column>[0-9]+)?([ ]*)?(?P<error>.*)
9292
93+
# Global setting to control whether Pipelines-as-Code should automatically cancel
94+
# any in-progress PipelineRuns associated with a pull request when that pull request is updated.
95+
# This helps prevent multiple redundant runs from executing simultaneously.
96+
# Default value: false.
97+
enable-cancel-in-progress-on-pull-requests: "false"
98+
99+
# Global setting to determine whether Pipelines-as-Code should automatically cancel
100+
# in-progress PipelineRuns triggered by a push event, if a new push occurs on the same branch.
101+
# This prevents overlapping or redundant runs for the same branch.
102+
# Default value: false.
103+
enable-cancel-in-progress-on-push: "false"
104+
93105
# Since public bitbucket doesn't have the concept of Secret, we need to be
94106
# able to secure the request by querying https://ip-ranges.atlassian.com/,
95107
# this only happen for public bitbucket (ie: when provider.url is not set in

docs/content/docs/install/operator_installation.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ spec:
3333
auto-configure-new-github-repo: 'false'
3434
error-log-snippet: 'true'
3535
error-detection-from-container-logs: 'false'
36+
enable-cancel-in-progress-on-pull-requests: 'false'
37+
enable-cancel-in-progress-on-push: 'false'
3638
hub-url: 'https://api.hub.tekton.dev/v1'
3739
hub-catalog-name: tekton
3840
error-detection-max-number-of-lines: '50'

docs/content/docs/install/settings.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,32 @@ There is a few things you can configure through the config map
139139
risk and should be aware of the potential security vulnerabilities.
140140
(only GitHub and Gitea is supported at the moment).
141141

142+
### Global Cancel In Progress Settings
143+
144+
* `enable-cancel-in-progress-on-pull-requests`
145+
146+
If the `enable-cancel-in-progress-on-pull-requests` setting is enabled (true), Pipelines-as-Code will automatically cancel
147+
any in-progress PipelineRuns associated with a pull request when a new update (such as a new commit) is pushed to that pull request.
148+
This ensures that only the latest commit is processed, helping conserve compute resources and avoid running outdated PipelineRuns
149+
tied to previous commits.
150+
151+
It's important to note that if this global setting is disabled (false), Pipelines-as-Code will still honor the cancel-in-progress annotation
152+
at the individual PipelineRun level. In such cases, if a PipelineRun includes this annotation, it will take precedence over the global setting,
153+
and Pipelines-as-Code will cancel any matching in-progress runs when the pull request is updated.
154+
155+
This is disabled by default.
156+
157+
* `enable-cancel-in-progress-on-push`
158+
159+
If the `enable-cancel-in-progress-on-push` setting is enabled (true), Pipelines-as-Code will automatically cancel any in-progress PipelineRuns
160+
triggered by a push event when a new push is made to the same branch. This helps ensure that only the most recent commit is processed, preventing unnecessary execution of outdated PipelineRuns and optimizing resource usage.
161+
162+
Additionally, if this global setting is disabled (false), Pipelines-as-Code will still respect the cancel-in-progress annotation
163+
on individual PipelineRuns. In such cases, the annotation will override the global configuration, and Pipelines-as-Code will
164+
cancel any in-progress runs for that specific PipelineRun when a new push occurs on the same branch.
165+
166+
This is disabled by default.
167+
142168
### Tekton Hub support
143169

144170
Pipelines-as-Code supports fetching task with its remote annotations feature, by default it will fetch it from the [public tekton hub](https://hub.tekton.dev/) but you can configure it to point to your own with these settings:

pkg/matcher/annotation_matcher.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode"
1212
"github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/keys"
1313
apipac "github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/v1alpha1"
14+
"github.com/openshift-pipelines/pipelines-as-code/pkg/events"
1415
"github.com/openshift-pipelines/pipelines-as-code/pkg/opscomments"
1516
"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
1617
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
@@ -149,7 +150,42 @@ func getName(prun *tektonv1.PipelineRun) string {
149150
return name
150151
}
151152

152-
func MatchPipelinerunByAnnotation(ctx context.Context, logger *zap.SugaredLogger, pruns []*tektonv1.PipelineRun, cs *params.Run, event *info.Event, vcx provider.Interface) ([]Match, error) {
153+
// checkPipelineRunAnnotation checks if the Pipelinerun has
154+
// `on-event`/`on-target-branch annotations` with `on-cel-expression`
155+
// and if present then warns the user that `on-cel-expression` will take precedence.
156+
func checkPipelineRunAnnotation(prun *tektonv1.PipelineRun, eventEmitter *events.EventEmitter, repo *apipac.Repository) {
157+
// Define the annotations to check in a slice for easy iteration
158+
checks := []struct {
159+
key string
160+
value string
161+
}{
162+
{"on-event", prun.GetObjectMeta().GetAnnotations()[keys.OnEvent]},
163+
{"on-target-branch", prun.GetObjectMeta().GetAnnotations()[keys.OnTargetBranch]},
164+
}
165+
166+
// Preallocate the annotations slice with the exact capacity needed
167+
annotations := make([]string, 0, len(checks))
168+
169+
// Iterate through each check and append the key if the value is non-empty
170+
for _, check := range checks {
171+
if check.value != "" {
172+
annotations = append(annotations, check.key)
173+
}
174+
}
175+
176+
prName := getName(prun)
177+
if len(annotations) > 0 {
178+
ignoredAnnotations := strings.Join(annotations, ", ")
179+
msg := fmt.Sprintf(
180+
"Warning: The Pipelinerun '%s' has 'on-cel-expression' defined along with [%s] annotation(s). The 'on-cel-expression' will take precedence and these annotations will be ignored",
181+
prName,
182+
ignoredAnnotations,
183+
)
184+
eventEmitter.EmitMessage(repo, zap.WarnLevel, "RespositoryTakesOnCelExpressionPrecedence", msg)
185+
}
186+
}
187+
188+
func MatchPipelinerunByAnnotation(ctx context.Context, logger *zap.SugaredLogger, pruns []*tektonv1.PipelineRun, cs *params.Run, event *info.Event, vcx provider.Interface, eventEmitter *events.EventEmitter, repo *apipac.Repository) ([]Match, error) {
153189
matchedPRs := []Match{}
154190
infomsg := fmt.Sprintf("matching pipelineruns to event: URL=%s, target-branch=%s, source-branch=%s, target-event=%s",
155191
event.URL,
@@ -236,6 +272,8 @@ func MatchPipelinerunByAnnotation(ctx context.Context, logger *zap.SugaredLogger
236272
}
237273

238274
if celExpr, ok := prun.GetObjectMeta().GetAnnotations()[keys.OnCelExpression]; ok {
275+
checkPipelineRunAnnotation(prun, eventEmitter, repo)
276+
239277
out, err := celEvaluate(ctx, celExpr, event, vcx)
240278
if err != nil {
241279
logger.Errorf("there was an error evaluating the CEL expression, skipping: %v", err)

pkg/matcher/annotation_matcher_test.go

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/jonboulle/clockwork"
1515
"github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/keys"
1616
"github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/v1alpha1"
17+
"github.com/openshift-pipelines/pipelines-as-code/pkg/events"
1718
"github.com/openshift-pipelines/pipelines-as-code/pkg/opscomments"
1819
"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
1920
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/clients"
@@ -1414,9 +1415,10 @@ func runTest(ctx context.Context, t *testing.T, tt annotationTest, vcx provider.
14141415
Info: info.Info{},
14151416
}
14161417

1418+
eventEmitter := events.NewEventEmitter(cs.Kube, logger)
14171419
matches, err := MatchPipelinerunByAnnotation(ctx, logger,
14181420
tt.args.pruns,
1419-
client, &tt.args.runevent, vcx,
1421+
client, &tt.args.runevent, vcx, eventEmitter, nil,
14201422
)
14211423

14221424
if tt.wantLog != "" {
@@ -1533,6 +1535,7 @@ func TestMatchPipelinerunByAnnotation(t *testing.T) {
15331535
wantErr bool
15341536
wantPrName string
15351537
wantLog []string
1538+
logLevel int
15361539
}{
15371540
{
15381541
name: "good-match-with-only-one",
@@ -1609,6 +1612,38 @@ func TestMatchPipelinerunByAnnotation(t *testing.T) {
16091612
wantErr: false,
16101613
wantPrName: pipelineCel.GetName(),
16111614
},
1615+
{
1616+
name: "cel-expression-takes-precedence-over-annotations",
1617+
args: args{
1618+
pruns: []*tektonv1.PipelineRun{
1619+
{
1620+
ObjectMeta: metav1.ObjectMeta{
1621+
Name: "pipeline-on-cel-test",
1622+
Annotations: map[string]string{
1623+
keys.OnEvent: "[pull_request]",
1624+
keys.OnTargetBranch: "[main]",
1625+
keys.OnCelExpression: `event == "pull_request" && target_branch == "main" && source_branch == "warn-for-cel"`,
1626+
},
1627+
},
1628+
},
1629+
},
1630+
runevent: info.Event{
1631+
URL: "https://hello/moto",
1632+
TriggerTarget: "pull_request",
1633+
EventType: "pull_request",
1634+
BaseBranch: "main",
1635+
HeadBranch: "warn-for-cel",
1636+
PullRequestNumber: 10,
1637+
Request: &info.Request{
1638+
Header: http.Header{},
1639+
},
1640+
},
1641+
},
1642+
wantErr: false,
1643+
wantLog: []string{
1644+
`Warning: The Pipelinerun 'pipeline-on-cel-test' has 'on-cel-expression' defined along with [on-event, on-target-branch] annotation(s). The 'on-cel-expression' will take precedence and these annotations will be ignored`,
1645+
},
1646+
},
16121647
{
16131648
name: "no-match-on-label",
16141649
args: args{
@@ -1914,7 +1949,9 @@ func TestMatchPipelinerunByAnnotation(t *testing.T) {
19141949
Clients: clients.Clients{},
19151950
Info: info.Info{},
19161951
}
1917-
matches, err := MatchPipelinerunByAnnotation(ctx, logger, tt.args.pruns, cs, &tt.args.runevent, &ghprovider.Provider{})
1952+
1953+
eventEmitter := events.NewEventEmitter(cs.Clients.Kube, logger)
1954+
matches, err := MatchPipelinerunByAnnotation(ctx, logger, tt.args.pruns, cs, &tt.args.runevent, &ghprovider.Provider{}, eventEmitter, nil)
19181955
if (err != nil) != tt.wantErr {
19191956
t.Errorf("MatchPipelinerunByAnnotation() error = %v, wantErr %v", err, tt.wantErr)
19201957
return

pkg/params/settings/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ type Settings struct {
6363
ErrorDetectionNumberOfLines int `default:"50" json:"error-detection-max-number-of-lines"`
6464
ErrorDetectionSimpleRegexp string `default:"^(?P<filename>[^:]*):(?P<line>[0-9]+):(?P<column>[0-9]+)?([ ]*)?(?P<error>.*)" json:"error-detection-simple-regexp"`
6565

66+
EnableCancelInProgressOnPullRequests bool `json:"enable-cancel-in-progress-on-pull-requests"`
67+
EnableCancelInProgressOnPush bool `json:"enable-cancel-in-progress-on-push"`
68+
6669
CustomConsoleName string `json:"custom-console-name"`
6770
CustomConsoleURL string `json:"custom-console-url"`
6871
CustomConsolePRdetail string `json:"custom-console-url-pr-details"`

pkg/params/settings/config_test.go

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,31 @@ func TestSyncConfig(t *testing.T) {
2121
name: "With all default values",
2222
configMap: map[string]string{},
2323
expectedStruct: Settings{
24-
ApplicationName: "Pipelines as Code CI",
25-
HubCatalogs: nil,
26-
RemoteTasks: true,
27-
MaxKeepRunsUpperLimit: 0,
28-
DefaultMaxKeepRuns: 0,
29-
BitbucketCloudCheckSourceIP: true,
30-
BitbucketCloudAdditionalSourceIP: "",
31-
TektonDashboardURL: "",
32-
AutoConfigureNewGitHubRepo: false,
33-
AutoConfigureRepoNamespaceTemplate: "",
34-
SecretAutoCreation: true,
35-
SecretGHAppRepoScoped: true,
36-
SecretGhAppTokenScopedExtraRepos: "",
37-
ErrorLogSnippet: true,
38-
ErrorDetection: true,
39-
ErrorDetectionNumberOfLines: 50,
40-
ErrorDetectionSimpleRegexp: "^(?P<filename>[^:]*):(?P<line>[0-9]+):(?P<column>[0-9]+)?([ ]*)?(?P<error>.*)",
41-
CustomConsoleName: "",
42-
CustomConsoleURL: "",
43-
CustomConsolePRdetail: "",
44-
CustomConsolePRTaskLog: "",
45-
CustomConsoleNamespaceURL: "",
46-
RememberOKToTest: false,
24+
ApplicationName: "Pipelines as Code CI",
25+
HubCatalogs: nil,
26+
RemoteTasks: true,
27+
MaxKeepRunsUpperLimit: 0,
28+
DefaultMaxKeepRuns: 0,
29+
BitbucketCloudCheckSourceIP: true,
30+
BitbucketCloudAdditionalSourceIP: "",
31+
TektonDashboardURL: "",
32+
AutoConfigureNewGitHubRepo: false,
33+
AutoConfigureRepoNamespaceTemplate: "",
34+
SecretAutoCreation: true,
35+
SecretGHAppRepoScoped: true,
36+
SecretGhAppTokenScopedExtraRepos: "",
37+
ErrorLogSnippet: true,
38+
ErrorDetection: true,
39+
ErrorDetectionNumberOfLines: 50,
40+
ErrorDetectionSimpleRegexp: "^(?P<filename>[^:]*):(?P<line>[0-9]+):(?P<column>[0-9]+)?([ ]*)?(?P<error>.*)",
41+
EnableCancelInProgressOnPullRequests: false,
42+
EnableCancelInProgressOnPush: false,
43+
CustomConsoleName: "",
44+
CustomConsoleURL: "",
45+
CustomConsolePRdetail: "",
46+
CustomConsolePRTaskLog: "",
47+
CustomConsoleNamespaceURL: "",
48+
RememberOKToTest: false,
4749
},
4850
},
4951
{

0 commit comments

Comments
 (0)