@@ -15,7 +15,6 @@ import (
1515 "github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/keys"
1616 "github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/v1alpha1"
1717 "github.com/openshift-pipelines/pipelines-as-code/pkg/events"
18- "github.com/openshift-pipelines/pipelines-as-code/pkg/formatting"
1918 "github.com/openshift-pipelines/pipelines-as-code/pkg/opscomments"
2019 "github.com/openshift-pipelines/pipelines-as-code/pkg/params"
2120 "github.com/openshift-pipelines/pipelines-as-code/pkg/params/clients"
@@ -2604,41 +2603,7 @@ func TestGetName(t *testing.T) {
26042603 }
26052604}
26062605
2607- // checkForExistingSuccessfulPipelineRun is a helper function for testing.
2608- // It checks if there's an existing successful PipelineRun for the same SHA.
2609- func checkForExistingSuccessfulPipelineRun (ctx context.Context , logger * zap.SugaredLogger , cs * params.Run , event * info.Event , repo * v1alpha1.Repository ) * tektonv1.PipelineRun {
2610- // Only check for /retest and /ok-to-test commands
2611- if event .EventType != opscomments .RetestAllCommentEventType .String () &&
2612- event .EventType != opscomments .OkToTestCommentEventType .String () ||
2613- event .SHA == "" {
2614- return nil
2615- }
2616-
2617- labelSelector := fmt .Sprintf ("%s=%s" , keys .SHA , formatting .CleanValueKubernetes (event .SHA ))
2618- existingPRs , err := cs .Clients .Tekton .TektonV1 ().PipelineRuns (repo .GetNamespace ()).List (ctx , metav1.ListOptions {
2619- LabelSelector : labelSelector ,
2620- })
2621- if err != nil {
2622- logger .Errorf ("failed to list existing PipelineRuns for SHA %s: %v" , event .SHA , err )
2623- return nil
2624- }
2625-
2626- // Find the most recent successful PipelineRun
2627- var mostRecentSuccessfulPR * tektonv1.PipelineRun
2628- for i := range existingPRs .Items {
2629- pr := & existingPRs .Items [i ]
2630- if pr .Status .GetCondition (apis .ConditionSucceeded ).IsTrue () {
2631- if mostRecentSuccessfulPR == nil ||
2632- pr .CreationTimestamp .After (mostRecentSuccessfulPR .CreationTimestamp .Time ) {
2633- mostRecentSuccessfulPR = pr
2634- }
2635- }
2636- }
2637-
2638- return mostRecentSuccessfulPR
2639- }
2640-
2641- func TestCheckForExistingSuccessfulPipelineRun (t * testing.T ) {
2606+ func TestFilterSuccessfulTemplates (t * testing.T ) {
26422607 ctx , _ := rtesting .SetupFakeContext (t )
26432608 logger := zap .NewExample ().Sugar ()
26442609
@@ -2649,19 +2614,24 @@ func TestCheckForExistingSuccessfulPipelineRun(t *testing.T) {
26492614 },
26502615 }
26512616
2652- // Create a successful PipelineRun
2653- pr := & tektonv1.PipelineRun {
2617+ // Create test PipelineRuns with different templates and statuses
2618+ now := metav1 .Now ()
2619+ earlierTime := metav1 .NewTime (now .Add (- 1 * time .Hour ))
2620+ laterTime := metav1 .NewTime (now .Add (1 * time .Hour ))
2621+
2622+ // Template A: has successful run - should be filtered out
2623+ successfulPRA := & tektonv1.PipelineRun {
26542624 ObjectMeta : metav1.ObjectMeta {
2655- Name : "test-pr " ,
2625+ Name : "template-a-successful " ,
26562626 Namespace : "test-ns" ,
26572627 Labels : map [string ]string {
26582628 keys .SHA : "test-sha" ,
2659- keys .OriginalPRName : "test-pr " ,
2629+ keys .OriginalPRName : "template-a " ,
26602630 },
26612631 Annotations : map [string ]string {
2662- keys .OriginalPRName : "test-pr " ,
2632+ keys .OriginalPRName : "template-a " ,
26632633 },
2664- CreationTimestamp : metav1 . Now () ,
2634+ CreationTimestamp : now ,
26652635 },
26662636 Status : tektonv1.PipelineRunStatus {
26672637 Status : knativeduckv1.Status {
@@ -2675,20 +2645,19 @@ func TestCheckForExistingSuccessfulPipelineRun(t *testing.T) {
26752645 },
26762646 }
26772647
2678- // Create a failed PipelineRun with the same SHA but older
2679- earlierTime := metav1 .NewTime (time .Now ().Add (- 1 * time .Hour ))
2680- failedPR := & tektonv1.PipelineRun {
2648+ // Template B: has failed run - should be kept
2649+ failedPRB := & tektonv1.PipelineRun {
26812650 ObjectMeta : metav1.ObjectMeta {
2682- Name : "failed-pr " ,
2651+ Name : "template-b-failed " ,
26832652 Namespace : "test-ns" ,
26842653 Labels : map [string ]string {
26852654 keys .SHA : "test-sha" ,
2686- keys .OriginalPRName : "failed-pr " ,
2655+ keys .OriginalPRName : "template-b " ,
26872656 },
26882657 Annotations : map [string ]string {
2689- keys .OriginalPRName : "failed-pr " ,
2658+ keys .OriginalPRName : "template-b " ,
26902659 },
2691- CreationTimestamp : earlierTime ,
2660+ CreationTimestamp : now ,
26922661 },
26932662 Status : tektonv1.PipelineRunStatus {
26942663 Status : knativeduckv1.Status {
@@ -2702,9 +2671,109 @@ func TestCheckForExistingSuccessfulPipelineRun(t *testing.T) {
27022671 },
27032672 }
27042673
2674+ // Template D: has multiple successful runs - should be filtered out (most recent wins)
2675+ olderSuccessfulPRD := & tektonv1.PipelineRun {
2676+ ObjectMeta : metav1.ObjectMeta {
2677+ Name : "template-d-older-success" ,
2678+ Namespace : "test-ns" ,
2679+ Labels : map [string ]string {
2680+ keys .SHA : "test-sha" ,
2681+ keys .OriginalPRName : "template-d" ,
2682+ },
2683+ Annotations : map [string ]string {
2684+ keys .OriginalPRName : "template-d" ,
2685+ },
2686+ CreationTimestamp : earlierTime ,
2687+ },
2688+ Status : tektonv1.PipelineRunStatus {
2689+ Status : knativeduckv1.Status {
2690+ Conditions : knativeduckv1.Conditions {
2691+ apis.Condition {
2692+ Type : apis .ConditionSucceeded ,
2693+ Status : corev1 .ConditionTrue ,
2694+ },
2695+ },
2696+ },
2697+ },
2698+ }
2699+
2700+ newerSuccessfulPRD := & tektonv1.PipelineRun {
2701+ ObjectMeta : metav1.ObjectMeta {
2702+ Name : "template-d-newer-success" ,
2703+ Namespace : "test-ns" ,
2704+ Labels : map [string ]string {
2705+ keys .SHA : "test-sha" ,
2706+ keys .OriginalPRName : "template-d" ,
2707+ },
2708+ Annotations : map [string ]string {
2709+ keys .OriginalPRName : "template-d" ,
2710+ },
2711+ CreationTimestamp : laterTime ,
2712+ },
2713+ Status : tektonv1.PipelineRunStatus {
2714+ Status : knativeduckv1.Status {
2715+ Conditions : knativeduckv1.Conditions {
2716+ apis.Condition {
2717+ Type : apis .ConditionSucceeded ,
2718+ Status : corev1 .ConditionTrue ,
2719+ },
2720+ },
2721+ },
2722+ },
2723+ }
2724+
2725+ // PipelineRun with different SHA - should not interfere
2726+ differentSHAPR := & tektonv1.PipelineRun {
2727+ ObjectMeta : metav1.ObjectMeta {
2728+ Name : "different-sha-pr" ,
2729+ Namespace : "test-ns" ,
2730+ Labels : map [string ]string {
2731+ keys .SHA : "different-sha" ,
2732+ keys .OriginalPRName : "template-a" ,
2733+ },
2734+ Annotations : map [string ]string {
2735+ keys .OriginalPRName : "template-a" ,
2736+ },
2737+ CreationTimestamp : now ,
2738+ },
2739+ Status : tektonv1.PipelineRunStatus {
2740+ Status : knativeduckv1.Status {
2741+ Conditions : knativeduckv1.Conditions {
2742+ apis.Condition {
2743+ Type : apis .ConditionSucceeded ,
2744+ Status : corev1 .ConditionTrue ,
2745+ },
2746+ },
2747+ },
2748+ },
2749+ }
2750+
2751+ // PipelineRun without original PR name identification - should be ignored
2752+ noOriginalNamePR := & tektonv1.PipelineRun {
2753+ ObjectMeta : metav1.ObjectMeta {
2754+ Name : "no-original-name-pr" ,
2755+ Namespace : "test-ns" ,
2756+ Labels : map [string ]string {keys .SHA : "test-sha" },
2757+ Annotations : map [string ]string {},
2758+ CreationTimestamp : now ,
2759+ },
2760+ Status : tektonv1.PipelineRunStatus {
2761+ Status : knativeduckv1.Status {
2762+ Conditions : knativeduckv1.Conditions {
2763+ apis.Condition {
2764+ Type : apis .ConditionSucceeded ,
2765+ Status : corev1 .ConditionTrue ,
2766+ },
2767+ },
2768+ },
2769+ },
2770+ }
2771+
27052772 // Setup test clients
27062773 tdata := testclient.Data {
2707- PipelineRuns : []* tektonv1.PipelineRun {pr , failedPR },
2774+ PipelineRuns : []* tektonv1.PipelineRun {
2775+ successfulPRA , failedPRB , olderSuccessfulPRD , newerSuccessfulPRD , differentSHAPR , noOriginalNamePR ,
2776+ },
27082777 Repositories : []* v1alpha1.Repository {repo },
27092778 }
27102779 stdata , _ := testclient .SeedTestData (t , ctx , tdata )
@@ -2717,35 +2786,94 @@ func TestCheckForExistingSuccessfulPipelineRun(t *testing.T) {
27172786 },
27182787 }
27192788
2789+ // Create matched templates
2790+ createMatchedPR := func (name string ) Match {
2791+ return Match {
2792+ PipelineRun : & tektonv1.PipelineRun {
2793+ ObjectMeta : metav1.ObjectMeta {
2794+ Name : name ,
2795+ },
2796+ },
2797+ }
2798+ }
2799+
27202800 tests := []struct {
2721- name string
2722- eventType string
2723- sha string
2724- wantPR bool
2801+ name string
2802+ eventType string
2803+ sha string
2804+ matchedPRs []Match
2805+ expectedNames []string // Names of templates that should remain after filtering
27252806 }{
27262807 {
2727- name : "Retest command with matching SHA should find successful PR " ,
2808+ name : "Retest command filters templates with successful runs " ,
27282809 eventType : opscomments .RetestAllCommentEventType .String (),
27292810 sha : "test-sha" ,
2730- wantPR : true ,
2811+ matchedPRs : []Match {
2812+ createMatchedPR ("template-a" ), // has successful run - should be filtered
2813+ createMatchedPR ("template-b" ), // has failed run - should be kept
2814+ createMatchedPR ("template-c" ), // no previous runs - should be kept
2815+ createMatchedPR ("template-d" ), // has multiple successful runs - should be filtered
2816+ },
2817+ expectedNames : []string {"template-b" , "template-c" },
27312818 },
27322819 {
2733- name : "Ok-to-test command with matching SHA should find successful PR " ,
2820+ name : "Ok-to-test command filters templates with successful runs " ,
27342821 eventType : opscomments .OkToTestCommentEventType .String (),
27352822 sha : "test-sha" ,
2736- wantPR : true ,
2823+ matchedPRs : []Match {
2824+ createMatchedPR ("template-a" ), // has successful run - should be filtered
2825+ createMatchedPR ("template-b" ), // has failed run - should be kept
2826+ createMatchedPR ("template-c" ), // no previous runs - should be kept
2827+ },
2828+ expectedNames : []string {"template-b" , "template-c" },
27372829 },
27382830 {
2739- name : "Retest command with non-matching SHA should not find PR" ,
2831+ name : "Different event type does not filter anything" ,
2832+ eventType : opscomments .TestAllCommentEventType .String (),
2833+ sha : "test-sha" ,
2834+ matchedPRs : []Match {
2835+ createMatchedPR ("template-a" ),
2836+ createMatchedPR ("template-b" ),
2837+ createMatchedPR ("template-c" ),
2838+ createMatchedPR ("template-d" ),
2839+ },
2840+ expectedNames : []string {"template-a" , "template-b" , "template-c" , "template-d" },
2841+ },
2842+ {
2843+ name : "Empty SHA does not filter anything" ,
27402844 eventType : opscomments .RetestAllCommentEventType .String (),
2741- sha : "other-sha" ,
2742- wantPR : false ,
2845+ sha : "" ,
2846+ matchedPRs : []Match {
2847+ createMatchedPR ("template-a" ),
2848+ createMatchedPR ("template-b" ),
2849+ },
2850+ expectedNames : []string {"template-a" , "template-b" },
27432851 },
27442852 {
2745- name : "Different event type should not find PR" ,
2746- eventType : opscomments .TestAllCommentEventType .String (),
2853+ name : "Different SHA does not find existing runs" ,
2854+ eventType : opscomments .RetestAllCommentEventType .String (),
2855+ sha : "different-sha-2" ,
2856+ matchedPRs : []Match {
2857+ createMatchedPR ("template-a" ),
2858+ createMatchedPR ("template-b" ),
2859+ },
2860+ expectedNames : []string {"template-a" , "template-b" },
2861+ },
2862+ {
2863+ name : "All templates filtered results in empty list" ,
2864+ eventType : opscomments .RetestAllCommentEventType .String (),
2865+ sha : "test-sha" ,
2866+ matchedPRs : []Match {createMatchedPR ("template-a" )}, // only template with successful run
2867+ expectedNames : []string {},
2868+ },
2869+ {
2870+ name : "Templates without original PR name identification are ignored" ,
2871+ eventType : opscomments .RetestAllCommentEventType .String (),
27472872 sha : "test-sha" ,
2748- wantPR : false ,
2873+ matchedPRs : []Match {
2874+ createMatchedPR ("template-e" ), // has no original PR name - should be kept
2875+ },
2876+ expectedNames : []string {"template-e" },
27492877 },
27502878 }
27512879
@@ -2756,18 +2884,50 @@ func TestCheckForExistingSuccessfulPipelineRun(t *testing.T) {
27562884 SHA : tt .sha ,
27572885 }
27582886
2759- foundPR := checkForExistingSuccessfulPipelineRun (ctx , logger , cs , event , repo )
2887+ // For non-filtering event types, we simulate the calling pattern where
2888+ // filterSuccessfulTemplates is only called for retest and ok-to-test events
2889+ if event .EventType != opscomments .RetestAllCommentEventType .String () &&
2890+ event .EventType != opscomments .OkToTestCommentEventType .String () {
2891+ // For other events, the function is not called, so return original list
2892+ filtered := tt .matchedPRs
2893+ assert .Equal (t , len (tt .matchedPRs ), len (filtered ))
2894+ return
2895+ }
2896+
2897+ filtered := filterSuccessfulTemplates (ctx , logger , cs , event , repo , tt .matchedPRs )
27602898
2761- if tt .wantPR && foundPR == nil {
2762- t .Errorf ("Expected to find a successful PipelineRun, but got nil" )
2899+ // Check that the correct number of templates remain
2900+ assert .Equal (t , len (tt .expectedNames ), len (filtered ),
2901+ "Expected %d templates but got %d" , len (tt .expectedNames ), len (filtered ))
2902+
2903+ // Check that the correct templates remain
2904+ var actualNames []string
2905+ for _ , match := range filtered {
2906+ actualNames = append (actualNames , getName (match .PipelineRun ))
27632907 }
27642908
2765- if ! tt .wantPR && foundPR != nil {
2766- t .Errorf ("Expected not to find a PipelineRun, but found %s" , foundPR .Name )
2909+ // Check that we have the expected templates
2910+ for _ , expectedName := range tt .expectedNames {
2911+ found := false
2912+ for _ , actualName := range actualNames {
2913+ if actualName == expectedName {
2914+ found = true
2915+ break
2916+ }
2917+ }
2918+ assert .Assert (t , found , "Expected template %s not found in %v" , expectedName , actualNames )
27672919 }
27682920
2769- if tt .wantPR && foundPR != nil {
2770- assert .Equal (t , "test-pr" , foundPR .Name )
2921+ // Check that we don't have unexpected templates
2922+ for _ , actualName := range actualNames {
2923+ found := false
2924+ for _ , expectedName := range tt .expectedNames {
2925+ if actualName == expectedName {
2926+ found = true
2927+ break
2928+ }
2929+ }
2930+ assert .Assert (t , found , "Unexpected template %s found in %v" , actualName , actualNames )
27712931 }
27722932 })
27732933 }
0 commit comments