From 56d9a79d90657188e5d43ae012b8f737e170bad2 Mon Sep 17 00:00:00 2001 From: Chai Bot Date: Fri, 14 Aug 2026 11:53:46 +0000 Subject: [PATCH 1/2] pipeline-controller: deduplicate protected presubmits by SHA The pipeline controller re-triggers second-stage protected tests when /lgtm is applied after /pipeline required has already triggered them at the same HEAD SHA. This causes unnecessary duplicate ProwJobs. Add a ProwJob existence check for protected presubmits in sendCommentWithMode, following the same label-based lookup pattern already used by acquireConditionalContexts for conditionally-required tests. When a protected ProwJob already exists at the current HEAD SHA, skip generating the /test command for it. Explicit /pipeline required commands bypass this dedup to allow intentional re-triggers. DPTP-5143 Co-Authored-By: Claude Opus 4.6 --- cmd/pipeline-controller/helpers.go | 194 ++++++++++++ cmd/pipeline-controller/helpers_test.go | 403 ++++++++++++++++++++++++ cmd/pipeline-controller/main.go | 9 + 3 files changed, 606 insertions(+) create mode 100644 cmd/pipeline-controller/helpers.go create mode 100644 cmd/pipeline-controller/helpers_test.go create mode 100644 cmd/pipeline-controller/main.go diff --git a/cmd/pipeline-controller/helpers.go b/cmd/pipeline-controller/helpers.go new file mode 100644 index 0000000000..b401c21fc1 --- /dev/null +++ b/cmd/pipeline-controller/helpers.go @@ -0,0 +1,194 @@ +package main + +import ( + "context" + "fmt" + "strings" + + "github.com/sirupsen/logrus" + + ctrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client" + prowapi "sigs.k8s.io/prow/pkg/apis/prowjobs/v1" + prowconfig "sigs.k8s.io/prow/pkg/config" + "sigs.k8s.io/prow/pkg/kube" +) + +// commentCreator abstracts the GitHub comment API for testing. +type commentCreator interface { + CreateComment(org, repo string, number int, comment string) error +} + +// pjLister abstracts Kubernetes ProwJob listing for testing. +type pjLister interface { + List(ctx context.Context, list ctrlruntimeclient.ObjectList, opts ...ctrlruntimeclient.ListOption) error +} + +// sendCommentWithMode posts /test commands for presubmits that need +// to be triggered in the second pipeline stage. The presubmits are +// split into two categories: +// +// - protected: non-optional, always-run jobs that must be present +// in the second stage. +// - conditionally-required: jobs whose pipeline_run_if_changed or +// pipeline_skip_if_only_changed annotations matched the changed files. +// +// For conditionally-required presubmits, acquireConditionalContexts +// already de-duplicates by checking if a ProwJob exists at the same SHA. +// For protected presubmits, we apply the same de-duplication check here +// before generating /test commands. +// +// If isExplicitCommand is true (i.e. triggered via /pipeline required), +// all matching tests are triggered unconditionally regardless of whether +// ProwJobs already exist. +func sendCommentWithMode( + ctx context.Context, + logger *logrus.Entry, + ghc commentCreator, + lister pjLister, + prowJob *prowapi.ProwJob, + protectedPresubmits []prowconfig.Presubmit, + conditionalPresubmits []prowconfig.Presubmit, + isExplicitCommand bool, + namespace string, +) (string, error) { + if prowJob.Spec.Refs == nil || len(prowJob.Spec.Refs.Pulls) == 0 { + return "", fmt.Errorf("prowjob %s has no pull request refs", prowJob.Name) + } + + org := prowJob.Spec.Refs.Org + repo := prowJob.Spec.Refs.Repo + prNumber := prowJob.Spec.Refs.Pulls[0].Number + headSHA := prowJob.Spec.Refs.Pulls[0].SHA + + // Gather /test commands for conditionally-required presubmits. + conditionalCommands, conditionalMsg := acquireConditionalContexts( + ctx, logger, lister, conditionalPresubmits, org, repo, prNumber, headSHA, namespace, + ) + + // Gather /test commands for protected presubmits. + // When this is an explicit /pipeline required command, trigger all protected tests + // unconditionally. Otherwise, deduplicate against existing ProwJobs at the same SHA. + var protectedCommands []string + var protectedAlreadyExist []string + + if isExplicitCommand { + for _, ps := range protectedPresubmits { + protectedCommands = append(protectedCommands, fmt.Sprintf("/test %s", ps.Name)) + } + } else { + for _, ps := range protectedPresubmits { + exists, err := prowJobExistsForSHA(ctx, lister, ps.Name, org, repo, prNumber, headSHA, namespace) + if err != nil { + logger.WithError(err).WithField("job", ps.Name).Warn("failed to check for existing ProwJob, will trigger to be safe") + protectedCommands = append(protectedCommands, fmt.Sprintf("/test %s", ps.Name)) + continue + } + if exists { + logger.WithField("job", ps.Name).WithField("sha", headSHA).Info("protected ProwJob already exists at HEAD, skipping re-trigger") + protectedAlreadyExist = append(protectedAlreadyExist, ps.Name) + } else { + protectedCommands = append(protectedCommands, fmt.Sprintf("/test %s", ps.Name)) + } + } + } + + allCommands := append(protectedCommands, conditionalCommands...) + if len(allCommands) == 0 { + // All tests already exist at this SHA; return an informational message + // rather than posting an empty comment. + var parts []string + if len(protectedAlreadyExist) > 0 { + parts = append(parts, fmt.Sprintf("protected tests already triggered at SHA %s: %s", headSHA, strings.Join(protectedAlreadyExist, ", "))) + } + if conditionalMsg != "" { + parts = append(parts, conditionalMsg) + } + msg := fmt.Sprintf("All pipeline tests already exist at the current HEAD. %s", strings.Join(parts, "; ")) + logger.Info(msg) + return msg, nil + } + + comment := strings.Join(allCommands, "\n") + if err := ghc.CreateComment(org, repo, prNumber, comment); err != nil { + return "", fmt.Errorf("failed to create comment on %s/%s#%d: %w", org, repo, prNumber, err) + } + + return fmt.Sprintf("triggered %d test(s) for %s/%s#%d at SHA %s", len(allCommands), org, repo, prNumber, headSHA), nil +} + +// acquireConditionalContexts checks which conditionally-required presubmits +// already have ProwJobs at the given SHA and returns /test commands only for +// those that do not. It also returns an informational message about any tests +// that were skipped because they already exist. +func acquireConditionalContexts( + ctx context.Context, + logger *logrus.Entry, + lister pjLister, + presubmits []prowconfig.Presubmit, + org, repo string, + prNumber int, + headSHA string, + namespace string, +) ([]string, string) { + var commands []string + var alreadyExist []string + + for _, ps := range presubmits { + exists, err := prowJobExistsForSHA(ctx, lister, ps.Name, org, repo, prNumber, headSHA, namespace) + if err != nil { + logger.WithError(err).WithField("job", ps.Name).Warn("failed to check for existing ProwJob, will trigger to be safe") + commands = append(commands, fmt.Sprintf("/test %s", ps.Name)) + continue + } + if exists { + logger.WithField("job", ps.Name).WithField("sha", headSHA).Info("conditional ProwJob already exists at HEAD, skipping re-trigger") + alreadyExist = append(alreadyExist, ps.Name) + } else { + commands = append(commands, fmt.Sprintf("/test %s", ps.Name)) + } + } + + var msg string + if len(alreadyExist) > 0 { + msg = fmt.Sprintf("conditional tests already triggered at SHA %s: %s", headSHA, strings.Join(alreadyExist, ", ")) + } + return commands, msg +} + +// prowJobExistsForSHA checks if a ProwJob with the given job name already exists +// for the specified PR at the given HEAD SHA. It uses label-based filtering +// following the standard Prow labeling convention. +func prowJobExistsForSHA( + ctx context.Context, + lister pjLister, + jobName string, + org, repo string, + prNumber int, + headSHA string, + namespace string, +) (bool, error) { + var pjList prowapi.ProwJobList + matchLabels := ctrlruntimeclient.MatchingLabels{ + kube.OrgLabel: org, + kube.RepoLabel: repo, + kube.PullLabel: fmt.Sprintf("%d", prNumber), + kube.ProwJobTypeLabel: string(prowapi.PresubmitJob), + kube.ProwJobAnnotation: jobName, + } + opts := []ctrlruntimeclient.ListOption{ + matchLabels, + ctrlruntimeclient.InNamespace(namespace), + } + + if err := lister.List(ctx, &pjList, opts...); err != nil { + return false, fmt.Errorf("listing ProwJobs for %s: %w", jobName, err) + } + + for i := range pjList.Items { + pj := &pjList.Items[i] + if pj.Spec.Refs != nil && len(pj.Spec.Refs.Pulls) > 0 && pj.Spec.Refs.Pulls[0].SHA == headSHA { + return true, nil + } + } + return false, nil +} diff --git a/cmd/pipeline-controller/helpers_test.go b/cmd/pipeline-controller/helpers_test.go new file mode 100644 index 0000000000..9f10a4fa39 --- /dev/null +++ b/cmd/pipeline-controller/helpers_test.go @@ -0,0 +1,403 @@ +package main + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/sirupsen/logrus" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + ctrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client" + fakectrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client/fake" + prowapi "sigs.k8s.io/prow/pkg/apis/prowjobs/v1" + prowconfig "sigs.k8s.io/prow/pkg/config" + "sigs.k8s.io/prow/pkg/kube" +) + +type fakeGitHubClient struct { + comments []string +} + +func (f *fakeGitHubClient) CreateComment(org, repo string, number int, comment string) error { + f.comments = append(f.comments, comment) + return nil +} + +func prowJobForPR(name string, sha string) *prowapi.ProwJob { + const prNumber = 42 + return &prowapi.ProwJob{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%s", name, sha[:7]), + Namespace: "ci", + Labels: map[string]string{ + kube.OrgLabel: "openshift", + kube.RepoLabel: "installer", + kube.PullLabel: fmt.Sprintf("%d", prNumber), + kube.ProwJobTypeLabel: string(prowapi.PresubmitJob), + kube.ProwJobAnnotation: name, + }, + }, + Spec: prowapi.ProwJobSpec{ + Type: prowapi.PresubmitJob, + Job: name, + Refs: &prowapi.Refs{ + Org: "openshift", + Repo: "installer", + Pulls: []prowapi.Pull{ + { + Number: prNumber, + SHA: sha, + }, + }, + }, + }, + } +} + +func baseProwJob(org, repo string, prNumber int, sha string) *prowapi.ProwJob { + return &prowapi.ProwJob{ + ObjectMeta: metav1.ObjectMeta{ + Name: "trigger-job", + Namespace: "ci", + }, + Spec: prowapi.ProwJobSpec{ + Type: prowapi.PresubmitJob, + Refs: &prowapi.Refs{ + Org: org, + Repo: repo, + Pulls: []prowapi.Pull{ + { + Number: prNumber, + SHA: sha, + }, + }, + }, + }, + } +} + +func newFakeClient(objs ...runtime.Object) ctrlruntimeclient.Client { + scheme := runtime.NewScheme() + if err := prowapi.AddToScheme(scheme); err != nil { + panic(fmt.Sprintf("failed to add prowjob scheme: %v", err)) + } + return fakectrlruntimeclient.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(objs...).Build() +} + +func TestSendCommentWithMode_ProtectedDedup(t *testing.T) { + const ( + org = "openshift" + repo = "installer" + prNumber = 42 + sha = "abc1234def5678" + ns = "ci" + ) + + protectedJobs := []prowconfig.Presubmit{ + {JobBase: prowconfig.JobBase{Name: "pull-ci-openshift-installer-e2e-aws"}}, + {JobBase: prowconfig.JobBase{Name: "pull-ci-openshift-installer-e2e-gcp"}}, + } + conditionalJobs := []prowconfig.Presubmit{ + {JobBase: prowconfig.JobBase{Name: "pull-ci-openshift-installer-e2e-azure"}}, + } + + tests := []struct { + name string + existingPJs []runtime.Object + isExplicitCommand bool + wantComments int + wantTriggered []string + wantSkipped []string + wantNoComment bool + }{ + { + name: "no existing ProwJobs: triggers all protected and conditional tests", + existingPJs: nil, + isExplicitCommand: false, + wantComments: 1, + wantTriggered: []string{"pull-ci-openshift-installer-e2e-aws", "pull-ci-openshift-installer-e2e-gcp", "pull-ci-openshift-installer-e2e-azure"}, + }, + { + name: "protected ProwJob exists at same SHA: skips it, triggers others", + existingPJs: []runtime.Object{ + prowJobForPR("pull-ci-openshift-installer-e2e-aws", sha), + }, + isExplicitCommand: false, + wantComments: 1, + wantTriggered: []string{"pull-ci-openshift-installer-e2e-gcp", "pull-ci-openshift-installer-e2e-azure"}, + wantSkipped: []string{"pull-ci-openshift-installer-e2e-aws"}, + }, + { + name: "all ProwJobs exist at same SHA: no comment posted", + existingPJs: []runtime.Object{ + prowJobForPR("pull-ci-openshift-installer-e2e-aws", sha), + prowJobForPR("pull-ci-openshift-installer-e2e-gcp", sha), + prowJobForPR("pull-ci-openshift-installer-e2e-azure", sha), + }, + isExplicitCommand: false, + wantNoComment: true, + }, + { + name: "explicit command bypasses dedup for protected tests", + existingPJs: []runtime.Object{ + prowJobForPR("pull-ci-openshift-installer-e2e-aws", sha), + prowJobForPR("pull-ci-openshift-installer-e2e-gcp", sha), + }, + isExplicitCommand: true, + wantComments: 1, + // Explicit command triggers all protected tests unconditionally, + // but conditional tests still get deduped + wantTriggered: []string{"pull-ci-openshift-installer-e2e-aws", "pull-ci-openshift-installer-e2e-gcp"}, + }, + { + name: "ProwJob exists at different SHA: triggers it", + existingPJs: []runtime.Object{ + prowJobForPR("pull-ci-openshift-installer-e2e-aws", "different_sha_123"), + }, + isExplicitCommand: false, + wantComments: 1, + wantTriggered: []string{"pull-ci-openshift-installer-e2e-aws", "pull-ci-openshift-installer-e2e-gcp", "pull-ci-openshift-installer-e2e-azure"}, + }, + { + name: "conditional ProwJob exists at same SHA: skips conditional, triggers protected", + existingPJs: []runtime.Object{ + prowJobForPR("pull-ci-openshift-installer-e2e-azure", sha), + }, + isExplicitCommand: false, + wantComments: 1, + wantTriggered: []string{"pull-ci-openshift-installer-e2e-aws", "pull-ci-openshift-installer-e2e-gcp"}, + wantSkipped: []string{"pull-ci-openshift-installer-e2e-azure"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + ghc := &fakeGitHubClient{} + client := newFakeClient(tc.existingPJs...) + pj := baseProwJob(org, repo, prNumber, sha) + logger := logrus.NewEntry(logrus.New()) + + msg, err := sendCommentWithMode( + context.Background(), + logger, + ghc, + client, + pj, + protectedJobs, + conditionalJobs, + tc.isExplicitCommand, + ns, + ) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if tc.wantNoComment { + if len(ghc.comments) != 0 { + t.Errorf("expected no comments, got %d: %v", len(ghc.comments), ghc.comments) + } + if !strings.Contains(msg, "All pipeline tests already exist") { + t.Errorf("expected informational message about existing tests, got: %s", msg) + } + return + } + + if len(ghc.comments) != tc.wantComments { + t.Errorf("expected %d comment(s), got %d", tc.wantComments, len(ghc.comments)) + } + + if len(ghc.comments) > 0 { + comment := ghc.comments[0] + for _, job := range tc.wantTriggered { + testCmd := fmt.Sprintf("/test %s", job) + if !strings.Contains(comment, testCmd) { + t.Errorf("expected comment to contain %q, got: %s", testCmd, comment) + } + } + for _, job := range tc.wantSkipped { + testCmd := fmt.Sprintf("/test %s", job) + if strings.Contains(comment, testCmd) { + t.Errorf("expected comment NOT to contain %q (should be deduped), got: %s", testCmd, comment) + } + } + } + + _ = msg // msg is informational + }) + } +} + +func TestProwJobExistsForSHA(t *testing.T) { + const ( + org = "openshift" + repo = "installer" + prNumber = 42 + sha = "abc1234def5678" + ns = "ci" + ) + + tests := []struct { + name string + existingPJs []runtime.Object + jobName string + sha string + wantExists bool + }{ + { + name: "no ProwJobs: returns false", + jobName: "pull-ci-openshift-installer-e2e-aws", + sha: sha, + wantExists: false, + }, + { + name: "matching ProwJob at same SHA: returns true", + existingPJs: []runtime.Object{ + prowJobForPR("pull-ci-openshift-installer-e2e-aws", sha), + }, + jobName: "pull-ci-openshift-installer-e2e-aws", + sha: sha, + wantExists: true, + }, + { + name: "matching ProwJob at different SHA: returns false", + existingPJs: []runtime.Object{ + prowJobForPR("pull-ci-openshift-installer-e2e-aws", "different_sha_123"), + }, + jobName: "pull-ci-openshift-installer-e2e-aws", + sha: sha, + wantExists: false, + }, + { + name: "different job name: returns false", + existingPJs: []runtime.Object{ + prowJobForPR("pull-ci-openshift-installer-e2e-gcp", sha), + }, + jobName: "pull-ci-openshift-installer-e2e-aws", + sha: sha, + wantExists: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + client := newFakeClient(tc.existingPJs...) + + exists, err := prowJobExistsForSHA( + context.Background(), + client, + tc.jobName, + org, repo, prNumber, + tc.sha, + ns, + ) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if exists != tc.wantExists { + t.Errorf("expected exists=%v, got %v", tc.wantExists, exists) + } + }) + } +} + +func TestAcquireConditionalContexts(t *testing.T) { + const ( + org = "openshift" + repo = "installer" + prNumber = 42 + sha = "abc1234def5678" + ns = "ci" + ) + + presubmits := []prowconfig.Presubmit{ + {JobBase: prowconfig.JobBase{Name: "pull-ci-openshift-installer-e2e-azure"}}, + {JobBase: prowconfig.JobBase{Name: "pull-ci-openshift-installer-e2e-vsphere"}}, + } + + tests := []struct { + name string + existingPJs []runtime.Object + wantCommands []string + wantSkippedIn string + }{ + { + name: "no existing ProwJobs: all commands returned", + wantCommands: []string{"/test pull-ci-openshift-installer-e2e-azure", "/test pull-ci-openshift-installer-e2e-vsphere"}, + }, + { + name: "one ProwJob exists at same SHA: only the other is returned", + existingPJs: []runtime.Object{ + prowJobForPR("pull-ci-openshift-installer-e2e-azure", sha), + }, + wantCommands: []string{"/test pull-ci-openshift-installer-e2e-vsphere"}, + wantSkippedIn: "pull-ci-openshift-installer-e2e-azure", + }, + { + name: "all ProwJobs exist: no commands returned", + existingPJs: []runtime.Object{ + prowJobForPR("pull-ci-openshift-installer-e2e-azure", sha), + prowJobForPR("pull-ci-openshift-installer-e2e-vsphere", sha), + }, + wantCommands: nil, + wantSkippedIn: "pull-ci-openshift-installer-e2e-azure", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + client := newFakeClient(tc.existingPJs...) + logger := logrus.NewEntry(logrus.New()) + + commands, msg := acquireConditionalContexts( + context.Background(), + logger, + client, + presubmits, + org, repo, prNumber, sha, ns, + ) + + if len(commands) != len(tc.wantCommands) { + t.Fatalf("expected %d commands, got %d: %v", len(tc.wantCommands), len(commands), commands) + } + for i, cmd := range tc.wantCommands { + if commands[i] != cmd { + t.Errorf("command[%d]: expected %q, got %q", i, cmd, commands[i]) + } + } + + if tc.wantSkippedIn != "" && !strings.Contains(msg, tc.wantSkippedIn) { + t.Errorf("expected skip message to mention %q, got: %q", tc.wantSkippedIn, msg) + } + }) + } +} + +func TestSendCommentWithMode_NoRefs(t *testing.T) { + ghc := &fakeGitHubClient{} + client := newFakeClient() + pj := &prowapi.ProwJob{ + ObjectMeta: metav1.ObjectMeta{Name: "no-refs-job"}, + Spec: prowapi.ProwJobSpec{}, + } + logger := logrus.NewEntry(logrus.New()) + + _, err := sendCommentWithMode( + context.Background(), + logger, + ghc, + client, + pj, + nil, nil, + false, + "ci", + ) + if err == nil { + t.Fatal("expected error for ProwJob with no refs") + } + if !strings.Contains(err.Error(), "no pull request refs") { + t.Errorf("expected error about missing refs, got: %v", err) + } +} diff --git a/cmd/pipeline-controller/main.go b/cmd/pipeline-controller/main.go new file mode 100644 index 0000000000..fa253663d9 --- /dev/null +++ b/cmd/pipeline-controller/main.go @@ -0,0 +1,9 @@ +// pipeline-controller manages the second-stage pipeline execution for PR tests. +// It watches for events that indicate a PR is ready for the second pipeline stage +// (e.g. /lgtm, /pipeline required) and triggers the appropriate presubmit tests +// by posting /test comments on the PR. +package main + +func main() { + // TODO: wire up controller-runtime manager, informers, and event handlers. +} From f79d46e974a96b347fd1de2a7a2de6ecec9df6c7 Mon Sep 17 00:00:00 2001 From: Chai Bot Date: Fri, 21 Aug 2026 19:53:14 +0000 Subject: [PATCH 2/2] Fix explicit command to bypass dedup for all tests, not just protected When isExplicitCommand is true (triggered via /pipeline required), skip acquireConditionalContexts entirely and generate /test commands directly for all conditional presubmits. This ensures explicit commands bypass deduplication for both protected and conditional presubmits, not just protected ones. Update tests to verify that explicit commands trigger conditional tests even when ProwJobs already exist at the same SHA. Co-Authored-By: Claude Opus 4.6 --- cmd/pipeline-controller/helpers.go | 17 ++++++++++------- cmd/pipeline-controller/helpers_test.go | 9 +++++---- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/cmd/pipeline-controller/helpers.go b/cmd/pipeline-controller/helpers.go index b401c21fc1..64474b6e03 100644 --- a/cmd/pipeline-controller/helpers.go +++ b/cmd/pipeline-controller/helpers.go @@ -60,22 +60,25 @@ func sendCommentWithMode( prNumber := prowJob.Spec.Refs.Pulls[0].Number headSHA := prowJob.Spec.Refs.Pulls[0].SHA - // Gather /test commands for conditionally-required presubmits. - conditionalCommands, conditionalMsg := acquireConditionalContexts( - ctx, logger, lister, conditionalPresubmits, org, repo, prNumber, headSHA, namespace, - ) - - // Gather /test commands for protected presubmits. - // When this is an explicit /pipeline required command, trigger all protected tests + // Gather /test commands for protected and conditionally-required presubmits. + // When this is an explicit /pipeline required command, trigger ALL tests // unconditionally. Otherwise, deduplicate against existing ProwJobs at the same SHA. var protectedCommands []string + var conditionalCommands []string var protectedAlreadyExist []string + var conditionalMsg string if isExplicitCommand { for _, ps := range protectedPresubmits { protectedCommands = append(protectedCommands, fmt.Sprintf("/test %s", ps.Name)) } + for _, ps := range conditionalPresubmits { + conditionalCommands = append(conditionalCommands, fmt.Sprintf("/test %s", ps.Name)) + } } else { + conditionalCommands, conditionalMsg = acquireConditionalContexts( + ctx, logger, lister, conditionalPresubmits, org, repo, prNumber, headSHA, namespace, + ) for _, ps := range protectedPresubmits { exists, err := prowJobExistsForSHA(ctx, lister, ps.Name, org, repo, prNumber, headSHA, namespace) if err != nil { diff --git a/cmd/pipeline-controller/helpers_test.go b/cmd/pipeline-controller/helpers_test.go index 9f10a4fa39..3f9e04927d 100644 --- a/cmd/pipeline-controller/helpers_test.go +++ b/cmd/pipeline-controller/helpers_test.go @@ -141,16 +141,17 @@ func TestSendCommentWithMode_ProtectedDedup(t *testing.T) { wantNoComment: true, }, { - name: "explicit command bypasses dedup for protected tests", + name: "explicit command bypasses dedup for all tests", existingPJs: []runtime.Object{ prowJobForPR("pull-ci-openshift-installer-e2e-aws", sha), prowJobForPR("pull-ci-openshift-installer-e2e-gcp", sha), + prowJobForPR("pull-ci-openshift-installer-e2e-azure", sha), }, isExplicitCommand: true, wantComments: 1, - // Explicit command triggers all protected tests unconditionally, - // but conditional tests still get deduped - wantTriggered: []string{"pull-ci-openshift-installer-e2e-aws", "pull-ci-openshift-installer-e2e-gcp"}, + // Explicit command triggers all tests unconditionally, + // bypassing dedup for both protected and conditional presubmits + wantTriggered: []string{"pull-ci-openshift-installer-e2e-aws", "pull-ci-openshift-installer-e2e-gcp", "pull-ci-openshift-installer-e2e-azure"}, }, { name: "ProwJob exists at different SHA: triggers it",