diff --git a/docs/content/_index.md b/docs/content/_index.md index 9e5b0481e3..c6c0405dbc 100644 --- a/docs/content/_index.md +++ b/docs/content/_index.md @@ -35,7 +35,7 @@ tracking using a Git workflow. <---> -- Pull-request "*GitOps*" actions through comments with `/retest`, `/test ` and so on. +- Pull-request "*GitOps*" actions through comments with `/retest` (reruns failed pipelines), `/test ` (force rerun specific pipeline) and so on. - Automatic Task resolution in Pipelines (local Tasks, Artifact Hub, and remote URLs) diff --git a/docs/content/docs/guide/gitops_commands.md b/docs/content/docs/guide/gitops_commands.md index 9aa412eebb..dbef715e29 100644 --- a/docs/content/docs/guide/gitops_commands.md +++ b/docs/content/docs/guide/gitops_commands.md @@ -11,7 +11,7 @@ The advantage of using a `GitOps command` is that it provides a journal of all t ## GitOps Commands on Pull Requests -For example, when you are on a Pull Request, you may want to restart all your PipelineRuns. To do so, you can add a comment on your Pull Request starting with `/retest`, and all PipelineRuns attached to that Pull Request will be restarted. +For example, when you are on a Pull Request, you may want to restart failed PipelineRuns. To do so, you can add a comment on your Pull Request starting with `/retest`, and all **failed** PipelineRuns attached to that Pull Request will be restarted. If all previous PipelineRuns for the same commit were successful, no new PipelineRuns will be created to avoid unnecessary duplication. Example: @@ -22,6 +22,23 @@ failure is not with your PR but seems to be an infrastructure issue. /retest ``` +The `/retest` command will only create new PipelineRuns if: + +- Previously **failed** PipelineRuns for the same commit, OR +- No PipelineRun has been run for the same commit yet + +If a successful PipelineRun already exists for the same commit, `/retest` will **skip** triggering a new PipelineRun to avoid unnecessary duplication. + +**To force a rerun regardless of previous status**, use: + +```text +/retest +``` + +This will always trigger a new PipelineRun, even if previous runs were successful. + +Similar to `/retest`, the `/ok-to-test` command will only trigger new PipelineRuns if no successful PipelineRun already exists for the same commit. This prevents duplicate runs when repository owners repeatedly test the same commit by `/test` and `/retest` command. + If you have multiple `PipelineRun` and you want to target a specific `PipelineRun`, you can use the `/test` command followed by the specific PipelineRun name to restart it. Example: ```text @@ -335,12 +352,12 @@ Here are the possible event types: - `test-all-comment`: The event is a single `/test` that would test every matched PipelineRun. - `test-comment`: The event is a `/test ` comment that would test a specific PipelineRun. -- `retest-all-comment`: The event is a single `/retest` that would retest every matched PipelineRun. +- `retest-all-comment`: The event is a single `/retest` that would retest every matched **failed** PipelineRun. If a successful PipelineRun already exists for the same commit, no new PipelineRun will be created. - `retest-comment`: The event is a `/retest ` that would retest a specific PipelineRun. - `on-comment`: The event is coming from a custom comment that would trigger a PipelineRun. - `cancel-all-comment`: The event is a single `/cancel` that would cancel every matched PipelineRun. - `cancel-comment`: The event is a `/cancel ` that would cancel a specific PipelineRun. -- `ok-to-test-comment`: The event is a `/ok-to-test` that would allow running the CI for an unauthorized user. +- `ok-to-test-comment`: The event is a `/ok-to-test` that would allow running the CI for an unauthorized user. If a successful PipelineRun already exists for the same commit, no new PipelineRun will be created. If a repository owner comments `/ok-to-test` on a pull request from an external contributor but no PipelineRun **matches** the `pull_request` event (or the repository has no `.tekton` directory), Pipelines-as-Code sets a **neutral** commit status. This indicates that no PipelineRun was matched, allowing other workflows—such as auto-merge—to proceed without being blocked. diff --git a/docs/content/docs/guide/policy.md b/docs/content/docs/guide/policy.md index 49b4b1fab0..6eae73b2fd 100644 --- a/docs/content/docs/guide/policy.md +++ b/docs/content/docs/guide/policy.md @@ -23,7 +23,7 @@ or other supported Git providers (currently GitHub and Gitea). to trigger the CI for a pull request by commenting `/ok-to-test`. This enables CI to run on pull requests submitted by contributors who are not collaborators of the repository or organization. It also applies to `/test` and `/retest` - commands. This action takes precedence over the `pull_request` action. + commands. Note that `/retest` will only trigger failed PipelineRuns. This action takes precedence over the `pull_request` action. ## Configuring Policies in the Repository CR diff --git a/hack/gh-workflow-ci.sh b/hack/gh-workflow-ci.sh index 6fd06152f6..f9235e2766 100755 --- a/hack/gh-workflow-ci.sh +++ b/hack/gh-workflow-ci.sh @@ -75,7 +75,7 @@ get_tests() { ghglabre="Github|Gitlab|Bitbucket" if [[ ${target} == "providers" ]]; then grep -hioP "^func Test.*(${ghglabre})(\w+)\(" "${testfiles[@]}" | sed -e 's/func[ ]*//' -e 's/($//' - elif [[ ${target} == "gitea_others" ]]; then + elif [[ ${target} == "gitea_others" ]]; then grep -hioP '^func Test(\w+)\(' "${testfiles[@]}" | grep -iPv "(${ghglabre})" | sed -e 's/func[ ]*//' -e 's/($//' else echo "Invalid target: ${target}" diff --git a/pkg/matcher/annotation_matcher.go b/pkg/matcher/annotation_matcher.go index ac190a1202..4e8d9f8756 100644 --- a/pkg/matcher/annotation_matcher.go +++ b/pkg/matcher/annotation_matcher.go @@ -11,6 +11,7 @@ import ( apipac "github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/v1alpha1" pacerrors "github.com/openshift-pipelines/pipelines-as-code/pkg/errors" "github.com/openshift-pipelines/pipelines-as-code/pkg/events" + "github.com/openshift-pipelines/pipelines-as-code/pkg/formatting" "github.com/openshift-pipelines/pipelines-as-code/pkg/opscomments" "github.com/openshift-pipelines/pipelines-as-code/pkg/params" "github.com/openshift-pipelines/pipelines-as-code/pkg/params/info" @@ -21,6 +22,8 @@ import ( "github.com/google/cel-go/common/types" tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" "go.uber.org/zap" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" ) const ( @@ -366,12 +369,77 @@ func MatchPipelinerunByAnnotation(ctx context.Context, logger *zap.SugaredLogger } if len(matchedPRs) > 0 { + // Filter out templates that already have successful PipelineRuns for /retest and /ok-to-test + if event.EventType == opscomments.RetestAllCommentEventType.String() || + event.EventType == opscomments.OkToTestCommentEventType.String() { + return filterSuccessfulTemplates(ctx, logger, cs, event, repo, matchedPRs), nil + } return matchedPRs, nil } return nil, fmt.Errorf("%s", buildAvailableMatchingAnnotationErr(event, pruns)) } +// filterSuccessfulTemplates filters out templates that already have successful PipelineRuns +// when executing /ok-to-test or /retest gitops commands, implementing per-template checking. +func filterSuccessfulTemplates(ctx context.Context, logger *zap.SugaredLogger, cs *params.Run, event *info.Event, repo *apipac.Repository, matchedPRs []Match) []Match { + if event.SHA == "" { + return matchedPRs + } + + // Get all existing PipelineRuns for this SHA + labelSelector := fmt.Sprintf("%s=%s", keys.SHA, formatting.CleanValueKubernetes(event.SHA)) + existingPRs, err := cs.Clients.Tekton.TektonV1().PipelineRuns(repo.GetNamespace()).List(ctx, metav1.ListOptions{ + LabelSelector: labelSelector, + }) + if err != nil { + logger.Errorf("failed to list existing PipelineRuns for SHA %s: %v", event.SHA, err) + return matchedPRs // Return all templates if we can't check + } + + // Create a map of template names to their most recent successful run + successfulTemplates := make(map[string]*tektonv1.PipelineRun) + + for i := range existingPRs.Items { + pr := &existingPRs.Items[i] + + // Get the original template name this PipelineRun came from + originalPRName, ok := pr.GetAnnotations()[keys.OriginalPRName] + if !ok { + originalPRName, ok = pr.GetLabels()[keys.OriginalPRName] + } + if !ok { + continue // Skip PipelineRuns without template identification + } + + // Check if this PipelineRun succeeded + if pr.Status.GetCondition(apis.ConditionSucceeded).IsTrue() { + // Keep the most recent successful run for each template + if existing, exists := successfulTemplates[originalPRName]; !exists || + pr.CreationTimestamp.After(existing.CreationTimestamp.Time) { + successfulTemplates[originalPRName] = pr + } + } + } + + // Filter out templates that have successful runs + var filteredPRs []Match + + for _, match := range matchedPRs { + templateName := getName(match.PipelineRun) + + if successfulPR, hasSuccessfulRun := successfulTemplates[templateName]; hasSuccessfulRun { + logger.Infof("skipping template '%s' for sha %s as it already has a successful pipelinerun '%s'", + templateName, event.SHA, successfulPR.Name) + } else { + filteredPRs = append(filteredPRs, match) + } + } + + // Return the filtered list (which may be empty if all templates were skipped) + return filteredPRs +} + func buildAvailableMatchingAnnotationErr(event *info.Event, pruns []*tektonv1.PipelineRun) string { errmsg := "available annotations of the PipelineRuns annotations in .tekton/ dir:" for _, prun := range pruns { diff --git a/pkg/matcher/annotation_matcher_test.go b/pkg/matcher/annotation_matcher_test.go index 0a2c4592b1..89ea92c83b 100644 --- a/pkg/matcher/annotation_matcher_test.go +++ b/pkg/matcher/annotation_matcher_test.go @@ -30,7 +30,10 @@ import ( zapobserver "go.uber.org/zap/zaptest/observer" "gotest.tools/v3/assert" "gotest.tools/v3/golden" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" + knativeduckv1 "knative.dev/pkg/apis/duck/v1" rtesting "knative.dev/pkg/reconciler/testing" ) @@ -2599,3 +2602,333 @@ func TestGetName(t *testing.T) { }) } } + +func TestFilterSuccessfulTemplates(t *testing.T) { + ctx, _ := rtesting.SetupFakeContext(t) + logger := zap.NewExample().Sugar() + + repo := &v1alpha1.Repository{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-repo", + Namespace: "test-ns", + }, + } + + // Create test PipelineRuns with different templates and statuses + now := metav1.Now() + earlierTime := metav1.NewTime(now.Add(-1 * time.Hour)) + laterTime := metav1.NewTime(now.Add(1 * time.Hour)) + + // Template A: has successful run - should be filtered out + successfulPRA := &tektonv1.PipelineRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "template-a-successful", + Namespace: "test-ns", + Labels: map[string]string{ + keys.SHA: "test-sha", + keys.OriginalPRName: "template-a", + }, + Annotations: map[string]string{ + keys.OriginalPRName: "template-a", + }, + CreationTimestamp: now, + }, + Status: tektonv1.PipelineRunStatus{ + Status: knativeduckv1.Status{ + Conditions: knativeduckv1.Conditions{ + apis.Condition{ + Type: apis.ConditionSucceeded, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + } + + // Template B: has failed run - should be kept + failedPRB := &tektonv1.PipelineRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "template-b-failed", + Namespace: "test-ns", + Labels: map[string]string{ + keys.SHA: "test-sha", + keys.OriginalPRName: "template-b", + }, + Annotations: map[string]string{ + keys.OriginalPRName: "template-b", + }, + CreationTimestamp: now, + }, + Status: tektonv1.PipelineRunStatus{ + Status: knativeduckv1.Status{ + Conditions: knativeduckv1.Conditions{ + apis.Condition{ + Type: apis.ConditionSucceeded, + Status: corev1.ConditionFalse, + }, + }, + }, + }, + } + + // Template D: has multiple successful runs - should be filtered out (most recent wins) + olderSuccessfulPRD := &tektonv1.PipelineRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "template-d-older-success", + Namespace: "test-ns", + Labels: map[string]string{ + keys.SHA: "test-sha", + keys.OriginalPRName: "template-d", + }, + Annotations: map[string]string{ + keys.OriginalPRName: "template-d", + }, + CreationTimestamp: earlierTime, + }, + Status: tektonv1.PipelineRunStatus{ + Status: knativeduckv1.Status{ + Conditions: knativeduckv1.Conditions{ + apis.Condition{ + Type: apis.ConditionSucceeded, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + } + + newerSuccessfulPRD := &tektonv1.PipelineRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "template-d-newer-success", + Namespace: "test-ns", + Labels: map[string]string{ + keys.SHA: "test-sha", + keys.OriginalPRName: "template-d", + }, + Annotations: map[string]string{ + keys.OriginalPRName: "template-d", + }, + CreationTimestamp: laterTime, + }, + Status: tektonv1.PipelineRunStatus{ + Status: knativeduckv1.Status{ + Conditions: knativeduckv1.Conditions{ + apis.Condition{ + Type: apis.ConditionSucceeded, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + } + + // PipelineRun with different SHA - should not interfere + differentSHAPR := &tektonv1.PipelineRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "different-sha-pr", + Namespace: "test-ns", + Labels: map[string]string{ + keys.SHA: "different-sha", + keys.OriginalPRName: "template-a", + }, + Annotations: map[string]string{ + keys.OriginalPRName: "template-a", + }, + CreationTimestamp: now, + }, + Status: tektonv1.PipelineRunStatus{ + Status: knativeduckv1.Status{ + Conditions: knativeduckv1.Conditions{ + apis.Condition{ + Type: apis.ConditionSucceeded, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + } + + // PipelineRun without original PR name identification - should be ignored + noOriginalNamePR := &tektonv1.PipelineRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "no-original-name-pr", + Namespace: "test-ns", + Labels: map[string]string{keys.SHA: "test-sha"}, + Annotations: map[string]string{}, + CreationTimestamp: now, + }, + Status: tektonv1.PipelineRunStatus{ + Status: knativeduckv1.Status{ + Conditions: knativeduckv1.Conditions{ + apis.Condition{ + Type: apis.ConditionSucceeded, + Status: corev1.ConditionTrue, + }, + }, + }, + }, + } + + // Setup test clients + tdata := testclient.Data{ + PipelineRuns: []*tektonv1.PipelineRun{ + successfulPRA, failedPRB, olderSuccessfulPRD, newerSuccessfulPRD, differentSHAPR, noOriginalNamePR, + }, + Repositories: []*v1alpha1.Repository{repo}, + } + stdata, _ := testclient.SeedTestData(t, ctx, tdata) + + cs := ¶ms.Run{ + Clients: clients.Clients{ + Log: logger, + Tekton: stdata.Pipeline, + Kube: stdata.Kube, + }, + } + + // Create matched templates + createMatchedPR := func(name string) Match { + return Match{ + PipelineRun: &tektonv1.PipelineRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + }, + } + } + + tests := []struct { + name string + eventType string + sha string + matchedPRs []Match + expectedNames []string // Names of templates that should remain after filtering + }{ + { + name: "Retest command filters templates with successful runs", + eventType: opscomments.RetestAllCommentEventType.String(), + sha: "test-sha", + matchedPRs: []Match{ + createMatchedPR("template-a"), // has successful run - should be filtered + createMatchedPR("template-b"), // has failed run - should be kept + createMatchedPR("template-c"), // no previous runs - should be kept + createMatchedPR("template-d"), // has multiple successful runs - should be filtered + }, + expectedNames: []string{"template-b", "template-c"}, + }, + { + name: "Ok-to-test command filters templates with successful runs", + eventType: opscomments.OkToTestCommentEventType.String(), + sha: "test-sha", + matchedPRs: []Match{ + createMatchedPR("template-a"), // has successful run - should be filtered + createMatchedPR("template-b"), // has failed run - should be kept + createMatchedPR("template-c"), // no previous runs - should be kept + }, + expectedNames: []string{"template-b", "template-c"}, + }, + { + name: "Different event type does not filter anything", + eventType: opscomments.TestAllCommentEventType.String(), + sha: "test-sha", + matchedPRs: []Match{ + createMatchedPR("template-a"), + createMatchedPR("template-b"), + createMatchedPR("template-c"), + createMatchedPR("template-d"), + }, + expectedNames: []string{"template-a", "template-b", "template-c", "template-d"}, + }, + { + name: "Empty SHA does not filter anything", + eventType: opscomments.RetestAllCommentEventType.String(), + sha: "", + matchedPRs: []Match{ + createMatchedPR("template-a"), + createMatchedPR("template-b"), + }, + expectedNames: []string{"template-a", "template-b"}, + }, + { + name: "Different SHA does not find existing runs", + eventType: opscomments.RetestAllCommentEventType.String(), + sha: "different-sha-2", + matchedPRs: []Match{ + createMatchedPR("template-a"), + createMatchedPR("template-b"), + }, + expectedNames: []string{"template-a", "template-b"}, + }, + { + name: "All templates filtered results in empty list", + eventType: opscomments.RetestAllCommentEventType.String(), + sha: "test-sha", + matchedPRs: []Match{createMatchedPR("template-a")}, // only template with successful run + expectedNames: []string{}, + }, + { + name: "Templates without original PR name identification are ignored", + eventType: opscomments.RetestAllCommentEventType.String(), + sha: "test-sha", + matchedPRs: []Match{ + createMatchedPR("template-e"), // has no original PR name - should be kept + }, + expectedNames: []string{"template-e"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + event := &info.Event{ + EventType: tt.eventType, + SHA: tt.sha, + } + + // For non-filtering event types, we simulate the calling pattern where + // filterSuccessfulTemplates is only called for retest and ok-to-test events + if event.EventType != opscomments.RetestAllCommentEventType.String() && + event.EventType != opscomments.OkToTestCommentEventType.String() { + // For other events, the function is not called, so return original list + filtered := tt.matchedPRs + assert.Equal(t, len(tt.matchedPRs), len(filtered)) + return + } + + filtered := filterSuccessfulTemplates(ctx, logger, cs, event, repo, tt.matchedPRs) + + // Check that the correct number of templates remain + assert.Equal(t, len(tt.expectedNames), len(filtered), + "Expected %d templates but got %d", len(tt.expectedNames), len(filtered)) + + // Check that the correct templates remain + var actualNames []string + for _, match := range filtered { + actualNames = append(actualNames, getName(match.PipelineRun)) + } + + // Check that we have the expected templates + for _, expectedName := range tt.expectedNames { + found := false + for _, actualName := range actualNames { + if actualName == expectedName { + found = true + break + } + } + assert.Assert(t, found, "Expected template %s not found in %v", expectedName, actualNames) + } + + // Check that we don't have unexpected templates + for _, actualName := range actualNames { + found := false + for _, expectedName := range tt.expectedNames { + if actualName == expectedName { + found = true + break + } + } + assert.Assert(t, found, "Unexpected template %s found in %v", actualName, actualNames) + } + }) + } +} diff --git a/pkg/pipelineascode/pipelineascode.go b/pkg/pipelineascode/pipelineascode.go index 451c0403f2..e9e9af1f90 100644 --- a/pkg/pipelineascode/pipelineascode.go +++ b/pkg/pipelineascode/pipelineascode.go @@ -56,13 +56,21 @@ func NewPacs(event *info.Event, vcx provider.Interface, run *params.Run, pacInfo } func (p *PacRun) Run(ctx context.Context) error { - matchedPRs, repo, err := p.matchRepoPR(ctx) - if repo != nil && p.event.TriggerTarget == triggertype.PullRequestClosed { - if err := p.cancelAllInProgressBelongingToClosedPullRequest(ctx, repo); err != nil { - return fmt.Errorf("error cancelling in progress pipelineRuns belonging to pull request %d: %w", p.event.PullRequestNumber, err) + // For PullRequestClosed events, skip matching logic and go straight to cancellation + if p.event.TriggerTarget == triggertype.PullRequestClosed { + repo, err := p.verifyRepoAndUser(ctx) + if err != nil { + return err + } + if repo != nil { + if err := p.cancelAllInProgressBelongingToClosedPullRequest(ctx, repo); err != nil { + return fmt.Errorf("error cancelling in progress pipelineRuns belonging to pull request %d: %w", p.event.PullRequestNumber, err) + } } return nil } + + matchedPRs, repo, err := p.matchRepoPR(ctx) if err != nil { createStatusErr := p.vcx.CreateStatus(ctx, p.event, provider.StatusOpts{ Status: CompletedStatus, diff --git a/test/gitea_params_test.go b/test/gitea_params_test.go index 368914c275..ab390235b8 100644 --- a/test/gitea_params_test.go +++ b/test/gitea_params_test.go @@ -314,7 +314,15 @@ func TestGiteaParamsOnRepoCR(t *testing.T) { _, f := tgitea.TestPR(t, topts) defer f() - repo, err := topts.ParamsRun.Clients.PipelineAsCode.PipelinesascodeV1alpha1().Repositories(topts.TargetNS).Get(context.Background(), topts.TargetNS, metav1.GetOptions{}) + // Wait for Repository status to be updated + waitOpts := twait.Opts{ + RepoName: topts.TargetNS, + Namespace: topts.TargetNS, + MinNumberStatus: 1, + PollTimeout: twait.DefaultTimeout, + TargetSHA: "", + } + repo, err := twait.UntilRepositoryUpdated(context.Background(), topts.ParamsRun.Clients, waitOpts) assert.NilError(t, err) assert.Assert(t, len(repo.Status) != 0) assert.NilError(t, diff --git a/test/gitea_test.go b/test/gitea_test.go index b269cdeb06..7c89536ad1 100644 --- a/test/gitea_test.go +++ b/test/gitea_test.go @@ -454,7 +454,7 @@ func TestGiteaConfigMaxKeepRun(t *testing.T) { } _, f := tgitea.TestPR(t, topts) defer f() - tgitea.PostCommentOnPullRequest(t, topts, "/retest") + tgitea.PostCommentOnPullRequest(t, topts, "/test") tgitea.WaitForStatus(t, topts, "heads/"+topts.TargetRefName, "", false) waitOpts := twait.Opts{ @@ -496,8 +496,8 @@ func TestGiteaConfigCancelInProgress(t *testing.T) { time.Sleep(3 * time.Second) // “Evil does not sleep. It waits.” - Galadriel - // wait a bit that the pipelinerun had created - tgitea.PostCommentOnPullRequest(t, topts, "/retest") + // wait a bit that the pipelinerun had created, then trigger a new run to test cancel-in-progress + tgitea.PostCommentOnPullRequest(t, topts, "/test") time.Sleep(2 * time.Second) // “Evil does not sleep. It waits.” - Galadriel @@ -539,11 +539,11 @@ func TestGiteaConfigCancelInProgress(t *testing.T) { } assert.Equal(t, cancelledPr, 1, "only one pr should have been canceled") - // Test that cancelling works with /retest - tgitea.PostCommentOnPullRequest(t, topts, "/retest") + // Test that cancelling works with /retest - use specific PipelineRun name to bypass success check + tgitea.PostCommentOnPullRequest(t, topts, "/retest pr-cancel-in-progress") topts.ParamsRun.Clients.Log.Info("Waiting 10 seconds before a new retest") - time.Sleep(10 * time.Second) // “Evil does not sleep. It waits.” - Galadriel - tgitea.PostCommentOnPullRequest(t, topts, "/retest") + time.Sleep(10 * time.Second) // "Evil does not sleep. It waits." - Galadriel + tgitea.PostCommentOnPullRequest(t, topts, "/retest pr-cancel-in-progress") tgitea.WaitForStatus(t, topts, "heads/"+targetRef, "", false) for _, pr := range prs.Items { diff --git a/test/github_config_maxkeepruns_test.go b/test/github_config_maxkeepruns_test.go index 4238129964..a7d0a3d6db 100644 --- a/test/github_config_maxkeepruns_test.go +++ b/test/github_config_maxkeepruns_test.go @@ -26,9 +26,9 @@ func TestGithubMaxKeepRuns(t *testing.T) { g.RunPullRequest(ctx, t) defer g.TearDown(ctx, t) - g.Cnx.Clients.Log.Infof("Creating /retest in PullRequest") + g.Cnx.Clients.Log.Infof("Creating /test in PullRequest to create a second run") _, _, err := g.Provider.Client().Issues.CreateComment(ctx, g.Options.Organization, g.Options.Repo, g.PRNumber, - &ghlib.IssueComment{Body: ghlib.Ptr("/retest")}) + &ghlib.IssueComment{Body: ghlib.Ptr("/test")}) assert.NilError(t, err) g.Cnx.Clients.Log.Infof("Wait for the second repository update to be updated") diff --git a/test/github_incoming_test.go b/test/github_incoming_test.go index 4c1bc6b2b0..fdcf41cc3b 100644 --- a/test/github_incoming_test.go +++ b/test/github_incoming_test.go @@ -24,6 +24,11 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +const ( + incomingSecretName = "pac-incoming-secret" + incomingSecreteValue = "shhhh-secrete" +) + // TestGithubAppIncoming tests that a Pipelinerun with the incoming event // gets created despite the presence of multiple Pipelineruns in the .tekton directory with // eventType as incoming. @@ -52,11 +57,26 @@ func TestGithubSecondIncoming(t *testing.T) { func TestGithubWebhookIncoming(t *testing.T) { randomedString := names.SimpleNameGenerator.RestrictLengthWithRandomSuffix("pac-e2e-ns") - entries, err := payload.GetEntries(map[string]string{ - ".tekton/pipelinerun-incoming.yaml": "testdata/pipelinerun-incoming.yaml", ".tekton/pr.yaml": "testdata/pipelinerun.yaml", + // Create entries with different event types to test that only incoming PipelineRun gets triggered + incomingEntries, err := payload.GetEntries(map[string]string{ + ".tekton/pipelinerun-incoming.yaml": "testdata/pipelinerun-incoming.yaml", }, randomedString, randomedString, triggertype.Incoming.String(), map[string]string{}) assert.NilError(t, err) + prEntries, err := payload.GetEntries(map[string]string{ + ".tekton/pr.yaml": "testdata/pipelinerun.yaml", + }, randomedString, randomedString, triggertype.PullRequest.String(), map[string]string{}) + assert.NilError(t, err) + + // Merge the entries - incoming PipelineRun triggers on "incoming", PR PipelineRun triggers on "pull_request" + entries := make(map[string]string) + for k, v := range incomingEntries { + entries[k] = v + } + for k, v := range prEntries { + entries[k] = v + } + verifyIncomingWebhook(t, randomedString, "pipelinerun-incoming", entries, true, false) } diff --git a/test/github_pullrequest_test.go b/test/github_pullrequest_test.go index 0cdd3a5481..357b73e030 100644 --- a/test/github_pullrequest_test.go +++ b/test/github_pullrequest_test.go @@ -323,9 +323,9 @@ func TestGithubSecondCancelInProgress(t *testing.T) { assert.NilError(t, err) time.Sleep(10 * time.Second) - g.Cnx.Clients.Log.Infof("Creating /retest on PullRequest") + g.Cnx.Clients.Log.Infof("Creating /test on PullRequest to create a second run") _, _, err = g.Provider.Client().Issues.CreateComment(ctx, g.Options.Organization, g.Options.Repo, g.PRNumber, - &github.IssueComment{Body: github.Ptr("/retest")}) + &github.IssueComment{Body: github.Ptr("/test")}) assert.NilError(t, err) g.Cnx.Clients.Log.Infof("Waiting for the two pipelinerun to be created") @@ -529,7 +529,7 @@ func TestGithubCancelInProgressSettingFromConfigMapOnPR(t *testing.T) { _, _, err = g.Provider.Client().Issues.CreateComment(ctx, g.Options.Organization, g.Options.Repo, g.PRNumber, - &github.IssueComment{Body: github.Ptr("/retest")}) + &github.IssueComment{Body: github.Ptr("/test")}) assert.NilError(t, err) g.Cnx.Clients.Log.Infof("Waiting for the two pipelinerun to be created") diff --git a/test/gitlab_incoming_webhook_test.go b/test/gitlab_incoming_webhook_test.go index d4a89e044e..54517dec14 100644 --- a/test/gitlab_incoming_webhook_test.go +++ b/test/gitlab_incoming_webhook_test.go @@ -24,10 +24,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -var ( - incomingSecreteValue = "shhhh-secrete" - incomingSecretName = "incoming-webhook-secret" -) +// Constants moved to test/github_incoming_test.go to avoid redeclaration func TestGitlabIncomingWebhookLegacy(t *testing.T) { testGitlabIncomingWebhook(t, true) diff --git a/test/gitlab_merge_request_test.go b/test/gitlab_merge_request_test.go index 48b00d95bd..0086688387 100644 --- a/test/gitlab_merge_request_test.go +++ b/test/gitlab_merge_request_test.go @@ -104,15 +104,15 @@ func TestGitlabMergeRequest(t *testing.T) { assert.Equal(t, "Merge Request", prsNew.Items[i].Annotations[keys.EventType]) } - runcnx.Clients.Log.Infof("Sending /retest comment on MergeRequest %s/-/merge_requests/%d", projectinfo.WebURL, mrID) + runcnx.Clients.Log.Infof("Sending /test comment on MergeRequest %s/-/merge_requests/%d", projectinfo.WebURL, mrID) _, _, err = glprovider.Client().Notes.CreateMergeRequestNote(opts.ProjectID, mrID, &clientGitlab.CreateMergeRequestNoteOptions{ - Body: clientGitlab.Ptr("/retest"), + Body: clientGitlab.Ptr("/test"), }) assert.NilError(t, err) sopt = twait.SuccessOpt{ Title: commitTitle, - OnEvent: opscomments.RetestAllCommentEventType.String(), + OnEvent: opscomments.TestAllCommentEventType.String(), TargetNS: targetNS, NumberofPRMatch: 5, // this is the max we get in repos status SHA: "", @@ -128,7 +128,7 @@ func TestGitlabMergeRequest(t *testing.T) { successCommentsPost++ } } - // we get 2 PRS initially, 2 prs from the push update and 2 prs from the /retest == 6 + // we get 2 PRS initially, 2 prs from the push update and 2 prs from the /test == 6 assert.Equal(t, 6, successCommentsPost) } @@ -577,7 +577,7 @@ func TestGitlabDisableCommentsOnMR(t *testing.T) { // no comments will be posted related to pipelineruns assert.Equal(t, 0, successCommentsPost) - // Update the repo setting to nil, and comment /retest to restart the pipelinerun + // Update the repo setting to nil, and comment /test to restart the pipelinerun // and now comments will be added on the MR waitOpts := twait.Opts{ RepoName: targetNS, @@ -589,15 +589,15 @@ func TestGitlabDisableCommentsOnMR(t *testing.T) { err = repository.UpdateRepo(ctx, waitOpts.Namespace, waitOpts.RepoName, runcnx.Clients) assert.NilError(t, err) - runcnx.Clients.Log.Infof("Sending /retest comment on MergeRequest %s/-/merge_requests/%d", projectinfo.WebURL, mrID) + runcnx.Clients.Log.Infof("Sending /test comment on MergeRequest %s/-/merge_requests/%d", projectinfo.WebURL, mrID) _, _, err = glprovider.Client().Notes.CreateMergeRequestNote(opts.ProjectID, mrID, &clientGitlab.CreateMergeRequestNoteOptions{ - Body: clientGitlab.Ptr("/retest"), + Body: clientGitlab.Ptr("/test"), }) assert.NilError(t, err) sopt = twait.SuccessOpt{ Title: commitTitle, - OnEvent: opscomments.RetestAllCommentEventType.String(), + OnEvent: opscomments.TestAllCommentEventType.String(), TargetNS: targetNS, NumberofPRMatch: 2, // this is the max we get in repos status SHA: "",