Skip to content

Commit 1f4e2bf

Browse files
committed
fix: filter out successful pipelineruns for /ok-to-test /retest
When running /ok-to-test or /retest all the pipelineruns are rerun over again. These pipeline runs instead should be skipped. When parsing for pipelineruns created for a Repository, we check whether any of the matched pipelineruns have been triggered by either the ok-to-test or retest event types. If they have, then we filter them out of the matched pipelineruns.
1 parent c2b17f0 commit 1f4e2bf

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed

pkg/pipelineascode/match.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/openshift-pipelines/pipelines-as-code/pkg/templates"
1919
tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
2020
"go.uber.org/zap"
21+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2122
)
2223

2324
func (p *PacRun) matchRepoPR(ctx context.Context) ([]matcher.Match, *v1alpha1.Repository, error) {
@@ -165,6 +166,77 @@ is that what you want? make sure you use -n when generating the secret, eg: echo
165166
return repo, nil
166167
}
167168

169+
// isAlreadyExecuted checks if the pipeline has already been executed for the given SHA and PR number.
170+
func (p *PacRun) isAlreadyExecuted(ctx context.Context, match matcher.Match) (bool, error) {
171+
// Get existing PipelineRuns for this repository that match the current SHA and PR number
172+
labelSelector := fmt.Sprintf("%s=%s,%s=%d,%s=%s",
173+
apipac.SHA, p.event.SHA,
174+
apipac.PullRequest, p.event.PullRequestNumber,
175+
apipac.Repository, match.Repo.Name)
176+
177+
existingPRs, err := p.run.Clients.Tekton.TektonV1().PipelineRuns(match.Repo.Namespace).List(ctx, metav1.ListOptions{
178+
LabelSelector: labelSelector,
179+
})
180+
if err != nil {
181+
return false, fmt.Errorf("failed to get existing pipelineruns: %w", err)
182+
}
183+
184+
// check for any successful runs for this specific pipeline
185+
targetPRName := strings.TrimSuffix(match.PipelineRun.GetGenerateName(), "-")
186+
if targetPRName == "" {
187+
targetPRName = match.PipelineRun.GetName()
188+
}
189+
190+
for _, pr := range existingPRs.Items {
191+
// Skip pipeline runs that are still running or not done
192+
if !pr.IsDone() || pr.Status.CompletionTime == nil {
193+
continue
194+
}
195+
196+
// if it's the same pipeline
197+
existingPRName := ""
198+
if originalPRName, ok := pr.GetAnnotations()[apipac.OriginalPRName]; ok {
199+
existingPRName = originalPRName
200+
} else {
201+
continue
202+
}
203+
204+
// Only skip if the pipeline was successful
205+
if existingPRName == targetPRName && pr.Status.GetCondition("Succeeded").IsTrue() {
206+
msg := fmt.Sprintf("Skipping pipeline run %s as it has already completed successfully for SHA %s on PR #%d",
207+
targetPRName, p.event.SHA, p.event.PullRequestNumber)
208+
p.eventEmitter.EmitMessage(match.Repo, zap.InfoLevel, "RepositorySkippingPipelineRun", msg)
209+
return true, nil
210+
}
211+
}
212+
213+
return false, nil
214+
}
215+
216+
// filterAlreadySuccessfulPipelines filters out pipeline runs that have already been executed successfully.
217+
func (p *PacRun) filterAlreadySuccessfulPipelines(ctx context.Context, matchedPRs []matcher.Match) []matcher.Match {
218+
filteredMatches := []matcher.Match{}
219+
for _, match := range matchedPRs {
220+
alreadyExecuted, err := p.isAlreadyExecuted(ctx, match)
221+
if err != nil {
222+
prName := match.PipelineRun.GetGenerateName()
223+
if prName == "" {
224+
prName = match.PipelineRun.GetName()
225+
}
226+
msg := fmt.Sprintf("Error checking if pipeline %s was already executed: %v",
227+
prName, err)
228+
p.eventEmitter.EmitMessage(match.Repo, zap.WarnLevel, "RepositoryCheckExecution", msg)
229+
filteredMatches = append(filteredMatches, match)
230+
continue
231+
}
232+
233+
if !alreadyExecuted {
234+
filteredMatches = append(filteredMatches, match)
235+
}
236+
}
237+
return filteredMatches
238+
}
239+
168240
// getPipelineRunsFromRepo fetches pipelineruns from git repository and prepare them for creation.
169241
func (p *PacRun) getPipelineRunsFromRepo(ctx context.Context, repo *v1alpha1.Repository) ([]matcher.Match, error) {
170242
provenance := "source"
@@ -262,6 +334,11 @@ func (p *PacRun) getPipelineRunsFromRepo(ctx context.Context, repo *v1alpha1.Rep
262334
}
263335
return nil, nil
264336
}
337+
338+
// filter out pipelines that have already been executed successfully
339+
if p.event.EventType == opscomments.RetestAllCommentEventType.String() || p.event.EventType == opscomments.OkToTestCommentEventType.String() {
340+
matchedPRs = p.filterAlreadySuccessfulPipelines(ctx, matchedPRs)
341+
}
265342
}
266343

267344
// if the event is a comment event, but we don't have any match from the keys.OnComment then do the ACL checks again

0 commit comments

Comments
 (0)