@@ -20,19 +20,47 @@ import (
20
20
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/triggertype"
21
21
)
22
22
23
+ type matchingCond func (pr tektonv1.PipelineRun ) bool
24
+
23
25
var cancelMergePatch = map [string ]interface {}{
24
26
"spec" : map [string ]interface {}{
25
27
"status" : tektonv1 .PipelineRunSpecStatusCancelledRunFinally ,
26
28
},
27
29
}
28
30
29
- // cancelInProgress cancels all PipelineRuns associated with a given repository and pull request,
31
+ func (p * PacRun ) cancelAllInProgressBelongingToPullRequest (ctx context.Context , repo * v1alpha1.Repository ) error {
32
+ labelSelector := getLabelSelector (map [string ]string {
33
+ keys .URLRepository : formatting .CleanValueKubernetes (p .event .Repository ),
34
+ keys .PullRequest : strconv .Itoa (int (p .event .PullRequestNumber )),
35
+ })
36
+ prs , err := p .run .Clients .Tekton .TektonV1 ().PipelineRuns (repo .Namespace ).List (ctx , metav1.ListOptions {
37
+ LabelSelector : labelSelector ,
38
+ })
39
+ if err != nil {
40
+ return fmt .Errorf ("failed to list pipelineRuns : %w" , err )
41
+ }
42
+
43
+ if len (prs .Items ) == 0 {
44
+ msg := fmt .Sprintf ("no pipelinerun found for repository: %v and pullRequest %v" ,
45
+ p .event .Repository , p .event .PullRequestNumber )
46
+ p .eventEmitter .EmitMessage (repo , zap .InfoLevel , "RepositoryPipelineRun" , msg )
47
+ return nil
48
+ }
49
+
50
+ p .cancelPipelineRuns (ctx , prs , repo , func (_ tektonv1.PipelineRun ) bool {
51
+ return true
52
+ })
53
+
54
+ return nil
55
+ }
56
+
57
+ // cancelInProgressMatchingPR cancels all PipelineRuns associated with a given repository and pull request,
30
58
// except for the one that triggered the cancellation. It first checks if the cancellation is in progress
31
59
// and if the repository has a concurrency limit. If a concurrency limit is set, it returns an error as
32
60
// cancellation is not supported with concurrency limits. It then retrieves the original pull request name
33
61
// from the annotations and lists all PipelineRuns with matching labels. For each PipelineRun that is not
34
62
// already done, cancelled, or gracefully stopped, it patches the PipelineRun to cancel it.
35
- func (p * PacRun ) cancelInProgress (ctx context.Context , matchPR * tektonv1.PipelineRun , repo * v1alpha1.Repository ) error {
63
+ func (p * PacRun ) cancelInProgressMatchingPR (ctx context.Context , matchPR * tektonv1.PipelineRun , repo * v1alpha1.Repository ) error {
36
64
if matchPR == nil {
37
65
return nil
38
66
}
@@ -67,51 +95,28 @@ func (p *PacRun) cancelInProgress(ctx context.Context, matchPR *tektonv1.Pipelin
67
95
if err != nil {
68
96
return fmt .Errorf ("failed to list pipelineRuns : %w" , err )
69
97
}
70
- var wg sync.WaitGroup
71
- for _ , pr := range prs .Items {
72
- if pr .GetName () == matchPR .GetName () {
73
- continue
74
- }
98
+
99
+ p .cancelPipelineRuns (ctx , prs , repo , func (pr tektonv1.PipelineRun ) bool {
100
+ // skip our own for cancellation
75
101
if sourceBranch , ok := pr .GetAnnotations ()[keys .SourceBranch ]; ok {
76
102
// NOTE(chmouel): Every PR has their own branch and so is every push to different branch
77
103
// it means we only cancel pipelinerun of the same name that runs to
78
104
// the unique branch. Note: HeadBranch is the branch from where the PR
79
105
// comes from in git jargon.
80
106
if sourceBranch != p .event .HeadBranch {
81
107
p .logger .Infof ("cancel-in-progress: skipping pipelinerun %v/%v as it is not from the same branch, annotation source-branch: %s event headbranch: %s" , pr .GetNamespace (), pr .GetName (), sourceBranch , p .event .HeadBranch )
82
- continue
108
+ return false
83
109
}
84
110
}
85
111
86
- if pr .IsPending () {
87
- p .logger .Infof ("cancel-in-progress: skipping pipelinerun %v/%v as it is pending" , pr .GetNamespace (), pr .GetName ())
88
- }
89
-
90
- if pr .IsDone () {
91
- p .logger .Infof ("cancel-in-progress: skipping pipelinerun %v/%v as it is done" , pr .GetNamespace (), pr .GetName ())
92
- continue
93
- }
94
- if pr .IsCancelled () || pr .IsGracefullyCancelled () || pr .IsGracefullyStopped () {
95
- p .logger .Infof ("cancel-in-progress: skipping pipelinerun %v/%v as it is already in %v state" , pr .GetNamespace (), pr .GetName (), pr .Spec .Status )
96
- continue
97
- }
98
-
99
- p .logger .Infof ("cancel-in-progress: cancelling pipelinerun %v/%v" , pr .GetNamespace (), pr .GetName ())
100
- wg .Add (1 )
101
- go func (ctx context.Context , pr tektonv1.PipelineRun ) {
102
- defer wg .Done ()
103
- if _ , err := action .PatchPipelineRun (ctx , p .logger , "cancel patch" , p .run .Clients .Tekton , & pr , cancelMergePatch ); err != nil {
104
- errMsg := fmt .Sprintf ("failed to cancel pipelineRun %s/%s: %s" , pr .GetNamespace (), pr .GetName (), err .Error ())
105
- p .eventEmitter .EmitMessage (repo , zap .ErrorLevel , "RepositoryPipelineRun" , errMsg )
106
- }
107
- }(ctx , pr )
108
- }
109
- wg .Wait ()
110
-
112
+ return pr .GetName () != matchPR .GetName ()
113
+ })
111
114
return nil
112
115
}
113
116
114
- func (p * PacRun ) cancelPipelineRuns (ctx context.Context , repo * v1alpha1.Repository ) error {
117
+ // cancelPipelineRunsOpsComment cancels all PipelineRuns associated with a given repository and pull request.
118
+ // when the user issue a cancel comment.
119
+ func (p * PacRun ) cancelPipelineRunsOpsComment (ctx context.Context , repo * v1alpha1.Repository ) error {
115
120
labelSelector := getLabelSelector (map [string ]string {
116
121
keys .URLRepository : formatting .CleanValueKubernetes (p .event .Repository ),
117
122
keys .SHA : formatting .CleanValueKubernetes (p .event .SHA ),
@@ -137,22 +142,40 @@ func (p *PacRun) cancelPipelineRuns(ctx context.Context, repo *v1alpha1.Reposito
137
142
return nil
138
143
}
139
144
140
- var wg sync.WaitGroup
141
- for _ , pr := range prs .Items {
145
+ p .cancelPipelineRuns (ctx , prs , repo , func (pr tektonv1.PipelineRun ) bool {
142
146
if p .event .TargetCancelPipelineRun != "" {
143
147
if prName , ok := pr .GetAnnotations ()[keys .OriginalPRName ]; ! ok || prName != p .event .TargetCancelPipelineRun {
144
- continue
148
+ return false
145
149
}
146
150
}
147
- if pr .IsDone () {
148
- p .logger .Infof ("pipelinerun %v/%v is done, skipping cancellation" , pr .GetNamespace (), pr .GetName ())
151
+ return true
152
+ })
153
+
154
+ return nil
155
+ }
156
+
157
+ func (p * PacRun ) cancelPipelineRuns (ctx context.Context , prs * tektonv1.PipelineRunList , repo * v1alpha1.Repository , condition matchingCond ) {
158
+ var wg sync.WaitGroup
159
+ for _ , pr := range prs .Items {
160
+ if ! condition (pr ) {
149
161
continue
150
162
}
163
+
151
164
if pr .IsCancelled () || pr .IsGracefullyCancelled () || pr .IsGracefullyStopped () {
152
- p .logger .Infof ("pipelinerun %v/%v is already in %v state" , pr .GetNamespace (), pr .GetName (), pr .Spec .Status )
165
+ p .logger .Infof ("cancel-in-progress: skipping cancelling pipelinerun %v/%v, already in %v state" , pr .GetNamespace (), pr .GetName (), pr .Spec .Status )
153
166
continue
154
167
}
155
168
169
+ if pr .IsDone () {
170
+ p .logger .Infof ("cancel-in-progress: skipping cancelling pipelinerun %v/%v, already done" , pr .GetNamespace (), pr .GetName ())
171
+ continue
172
+ }
173
+
174
+ if pr .IsPending () {
175
+ p .logger .Infof ("cancel-in-progress: skipping cancelling pipelinerun %v/%v in pending state" , pr .GetNamespace (), pr .GetName ())
176
+ }
177
+
178
+ p .logger .Infof ("cancel-in-progress: cancelling pipelinerun %v/%v" , pr .GetNamespace (), pr .GetName ())
156
179
wg .Add (1 )
157
180
go func (ctx context.Context , pr tektonv1.PipelineRun ) {
158
181
defer wg .Done ()
@@ -163,8 +186,6 @@ func (p *PacRun) cancelPipelineRuns(ctx context.Context, repo *v1alpha1.Reposito
163
186
}(ctx , pr )
164
187
}
165
188
wg .Wait ()
166
-
167
- return nil
168
189
}
169
190
170
191
func getLabelSelector (labelsMap map [string ]string ) string {
0 commit comments