Skip to content

Commit 435b6e4

Browse files
chmouelzakisk
andauthored
fix: Avoid webhook feedback loop on no-ops comment events (#2504)
Added logic to prevent errors from no-ops comment events from creating a feedback loop. When a "no-ops" comment event occurs, the MetadataResolve error is now skipped, preventing the creation of a comment that would re-trigger the same event. The test case for Gitea was updated to account for this change. It now waits for a short period to allow any potential feedback loops to settle and then asserts that only a single failure comment was posted, rather than multiple duplicates. Jira: https://issues.redhat.com/browse/SRVKP-10912 Signed-off-by: Chmouel Boudjnah <chmouel@redhat.com> Co-authored-by: Zaki Shaikh <zashaikh@redhat.com>
1 parent 3015674 commit 435b6e4

File tree

4 files changed

+104
-4
lines changed

4 files changed

+104
-4
lines changed

pkg/pipelineascode/match.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,12 @@ func (p *PacRun) getPipelineRunsFromRepo(ctx context.Context, repo *v1alpha1.Rep
252252
p.debugf("getPipelineRunsFromRepo: pipelineRuns count=%d", len(pipelineRuns))
253253
pipelineRuns, err = resolve.MetadataResolve(pipelineRuns)
254254
if err != nil && len(pipelineRuns) == 0 {
255+
// Don't report errors for no-ops comment events to avoid a webhook feedback loop:
256+
// reporting creates a comment, which triggers another webhook, which hits the same error.
257+
if p.event.EventType == opscomments.NoOpsCommentEventType.String() {
258+
p.logger.Infof("skipping MetadataResolve error for no-ops comment event: %s", err)
259+
return nil, nil
260+
}
255261
p.eventEmitter.EmitMessage(repo, zap.ErrorLevel, "FailedToResolvePipelineRunMetadata", err.Error())
256262
return nil, err
257263
}

pkg/pipelineascode/match_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,13 +316,26 @@ func TestGetPipelineRunsFromRepo(t *testing.T) {
316316
},
317317
}
318318

319+
noOpsCommentEvent := &info.Event{
320+
SHA: "principale",
321+
Organization: "organizationes",
322+
Repository: "lagaffe",
323+
URL: "https://service/documentation",
324+
HeadBranch: "main",
325+
BaseBranch: "main",
326+
Sender: "fantasio",
327+
EventType: opscomments.NoOpsCommentEventType.String(),
328+
TriggerTarget: "pull_request",
329+
}
330+
319331
tests := []struct {
320332
name string
321333
repositories *v1alpha1.Repository
322334
tektondir string
323335
expectedNumberOfPruns int
324336
event *info.Event
325337
logSnippet string
338+
wantErr bool
326339
}{
327340
{
328341
name: "more than one pipelinerun in .tekton dir",
@@ -422,6 +435,33 @@ func TestGetPipelineRunsFromRepo(t *testing.T) {
422435
expectedNumberOfPruns: 0,
423436
event: okToTestEvent,
424437
},
438+
{
439+
name: "same name pipelineruns error on regular event",
440+
repositories: &v1alpha1.Repository{
441+
ObjectMeta: metav1.ObjectMeta{
442+
Name: "testrepo",
443+
Namespace: "test",
444+
},
445+
Spec: v1alpha1.RepositorySpec{},
446+
},
447+
tektondir: "testdata/same_name_pipelineruns",
448+
event: pullRequestEvent,
449+
wantErr: true,
450+
},
451+
{
452+
name: "same name pipelineruns skipped on no-ops comment event",
453+
repositories: &v1alpha1.Repository{
454+
ObjectMeta: metav1.ObjectMeta{
455+
Name: "testrepo",
456+
Namespace: "test",
457+
},
458+
Spec: v1alpha1.RepositorySpec{},
459+
},
460+
tektondir: "testdata/same_name_pipelineruns",
461+
expectedNumberOfPruns: 0,
462+
event: noOpsCommentEvent,
463+
logSnippet: "skipping MetadataResolve error for no-ops comment event",
464+
},
425465
}
426466
for _, tt := range tests {
427467
t.Run(tt.name, func(t *testing.T) {
@@ -464,6 +504,10 @@ func TestGetPipelineRunsFromRepo(t *testing.T) {
464504
p := NewPacs(tt.event, vcx, cs, pacInfo, k8int, logger, nil)
465505
p.eventEmitter = events.NewEventEmitter(stdata.Kube, logger)
466506
matchedPRs, err := p.getPipelineRunsFromRepo(ctx, tt.repositories)
507+
if tt.wantErr {
508+
assert.Assert(t, err != nil, "expected an error but got nil")
509+
return
510+
}
467511
assert.NilError(t, err)
468512
matchedPRNames := make([]string, len(matchedPRs))
469513
for i := range matchedPRs {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
apiVersion: tekton.dev/v1beta1
2+
kind: PipelineRun
3+
metadata:
4+
name: duplicate-pr
5+
annotations:
6+
pipelinesascode.tekton.dev/on-target-branch: "[main]"
7+
pipelinesascode.tekton.dev/on-event: "[pull_request]"
8+
spec:
9+
pipelineSpec:
10+
tasks:
11+
- name: max
12+
taskSpec:
13+
steps:
14+
- name: success
15+
image: registry.access.redhat.com/ubi9/ubi-minimal
16+
script: 'exit 0'
17+
---
18+
apiVersion: tekton.dev/v1beta1
19+
kind: PipelineRun
20+
metadata:
21+
name: duplicate-pr
22+
annotations:
23+
pipelinesascode.tekton.dev/on-target-branch: "[main]"
24+
pipelinesascode.tekton.dev/on-event: "[pull_request]"
25+
spec:
26+
pipelineSpec:
27+
tasks:
28+
- name: max
29+
taskSpec:
30+
steps:
31+
- name: success
32+
image: registry.access.redhat.com/ubi9/ubi-minimal
33+
script: 'exit 0'

test/gitea_test.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,11 +1016,28 @@ func TestGiteaPipelineRunWithSameName(t *testing.T) {
10161016
ExpectEvents: true,
10171017
Regexp: regexp.MustCompile(".*found multiple pipelinerun in .tekton with the same name*"),
10181018
}
1019-
ctx, f := tgitea.TestPR(t, topts)
1019+
_, f := tgitea.TestPR(t, topts)
10201020
defer f()
1021-
errre := regexp.MustCompile("found multiple pipelinerun in .tekton with the same name")
1022-
maxLines := int64(1000)
1023-
assert.NilError(t, twait.RegexpMatchingInControllerLog(ctx, topts.ParamsRun, *errre, 10, "controller", &maxLines))
1021+
1022+
// Wait for any webhook feedback loop to settle, then verify only 1 failure
1023+
// comment was posted (not duplicates from re-triggered no-op comment events).
1024+
time.Sleep(10 * time.Second)
1025+
1026+
comments, _, err := topts.GiteaCNX.Client().ListRepoIssueComments(
1027+
topts.PullRequest.Base.Repository.Owner.UserName,
1028+
topts.PullRequest.Base.Repository.Name,
1029+
forgejo.ListIssueCommentOptions{})
1030+
assert.NilError(t, err)
1031+
1032+
failureRe := regexp.MustCompile("found multiple pipelinerun in .tekton with the same name")
1033+
var failureCount int
1034+
for _, comment := range comments {
1035+
if failureRe.MatchString(comment.Body) {
1036+
failureCount++
1037+
}
1038+
}
1039+
assert.Equal(t, failureCount, 1,
1040+
"expected 1 failure comment but found %d", failureCount)
10241041
}
10251042

10261043
// TestGiteaProvenanceForDefaultBranch tests the provenance feature of the PipelineRun.

0 commit comments

Comments
 (0)