Skip to content

Commit 2d5c024

Browse files
committed
fix: filter out already successful pipelineruns
1 parent 6974ba9 commit 2d5c024

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

pkg/pipelineascode/match.go

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

267351
// 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)