From 90bfa624c2c4b66053188f6d9382d7f413be258e Mon Sep 17 00:00:00 2001 From: Kynan Ware <47394200+BagToad@users.noreply.github.com> Date: Thu, 5 Mar 2026 15:36:48 -0700 Subject: [PATCH] Exclude current user from suggested reviewers in gh pr create Query the viewer login in SuggestedReviewerActorsForRepo and pre-seed the seen map so the current user is filtered out of collaborator results. You cannot review your own PR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- api/queries_pr_review.go | 10 +++++++++- api/queries_pr_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/api/queries_pr_review.go b/api/queries_pr_review.go index b25b199d1..f6ef2a74e 100644 --- a/api/queries_pr_review.go +++ b/api/queries_pr_review.go @@ -556,6 +556,9 @@ func SuggestedReviewerActors(client *Client, repo ghrepo.Interface, prID string, // Returns the candidates, a MoreResults count, and an error. func SuggestedReviewerActorsForRepo(client *Client, repo ghrepo.Interface, query string) ([]ReviewerCandidate, int, error) { type responseData struct { + Viewer struct { + Login string + } Repository struct { // HACK: There's no repo-level API to check Copilot reviewer eligibility, // so we piggyback on an open PR's suggestedReviewerActors to detect @@ -610,8 +613,13 @@ func SuggestedReviewerActorsForRepo(client *Client, repo ghrepo.Interface, query return nil, 0, err } - // Build candidates using cascading quota logic + // Build candidates using cascading quota logic. + // Pre-seed seen with the current user to exclude them from results + // since you cannot review your own PR. seen := make(map[string]bool) + if result.Viewer.Login != "" { + seen[result.Viewer.Login] = true + } var candidates []ReviewerCandidate const baseQuota = 5 diff --git a/api/queries_pr_test.go b/api/queries_pr_test.go index 4ee312b5d..7b7727f3e 100644 --- a/api/queries_pr_test.go +++ b/api/queries_pr_test.go @@ -390,6 +390,7 @@ func mockReviewerResponseForRepoWithCopilot(collabs, teams, totalCollabs, totalT return fmt.Sprintf(`{ "data": { + "viewer": {"login": "testuser"}, "repository": { %s, "collaborators": {"nodes": [%s]}, @@ -500,6 +501,36 @@ func TestSuggestedReviewerActorsForRepo(t *testing.T) { expectedLogins: []string{"c1", "c2", "c3", "OWNER/team1", "OWNER/team2"}, expectedMore: 10, }, + { + name: "viewer excluded from collaborators", + httpStubs: func(reg *httpmock.Registry) { + // c1 matches the viewer login "testuser" won't be in this fixture, + // but we can craft a response where the viewer login matches a collaborator. + reg.Register( + httpmock.GraphQL(`query SuggestedReviewerActorsForRepo\b`), + httpmock.StringResponse(`{ + "data": { + "viewer": {"login": "c2"}, + "repository": { + "pullRequests": {"nodes": []}, + "collaborators": {"nodes": [ + {"login": "c1", "name": "C1"}, + {"login": "c2", "name": "C2"}, + {"login": "c3", "name": "C3"} + ]}, + "collaboratorsTotalCount": {"totalCount": 3} + }, + "organization": { + "teams": {"nodes": []}, + "teamsTotalCount": {"totalCount": 0} + } + } + }`)) + }, + expectedCount: 2, + expectedLogins: []string{"c1", "c3"}, + expectedMore: 3, + }, } for _, tt := range tests {