From 8c14ced12cfa4c56d36a67a075a0f952b4cee201 Mon Sep 17 00:00:00 2001 From: Nathan Cairns Date: Mon, 10 Aug 2026 11:10:25 +0200 Subject: [PATCH 1/2] Don't retag people who have already approved the PR --- .../actions/release-pr-bot/manage-release-pr.js | 15 ++++++++++++++- .../release-pr-bot/manage-release-pr.test.js | 16 ++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/.github/actions/release-pr-bot/manage-release-pr.js b/.github/actions/release-pr-bot/manage-release-pr.js index 1bc8591..4ffb9a1 100644 --- a/.github/actions/release-pr-bot/manage-release-pr.js +++ b/.github/actions/release-pr-bot/manage-release-pr.js @@ -136,8 +136,21 @@ async function updateReleasePR({ github, owner, repo, pr, body, reviewers }) { pull_number: pr.number, }) + const { data: submittedReviews } = await github.rest.pulls.listReviews({ + owner, + repo, + pull_number: pr.number, + }) + const currentLogins = new Set(currentReviews.users.map((u) => u.login)) - const newReviewers = reviewers.filter((r) => !currentLogins.has(r)) + const approvers = new Set( + submittedReviews + .filter((review) => review.state === 'APPROVED') + .map((review) => review.user?.login), + ) + const newReviewers = reviewers.filter( + (r) => !currentLogins.has(r) && !approvers.has(r), + ) if (newReviewers.length > 0) { await github.rest.pulls.requestReviewers({ diff --git a/.github/actions/release-pr-bot/manage-release-pr.test.js b/.github/actions/release-pr-bot/manage-release-pr.test.js index 6519d1d..a90b0d1 100644 --- a/.github/actions/release-pr-bot/manage-release-pr.test.js +++ b/.github/actions/release-pr-bot/manage-release-pr.test.js @@ -7,6 +7,7 @@ const makeGithub = ({ mergedPRs = [], openPRs = [], currentReviewers = [], + submittedReviews = [], } = {}) => ({ rest: { repos: { @@ -17,6 +18,7 @@ const makeGithub = ({ create: jest.fn().mockResolvedValue({ data: { number: 99, html_url: 'https://github.com/test/pull/99' } }), update: jest.fn().mockResolvedValue({}), listRequestedReviewers: jest.fn().mockResolvedValue({ data: { users: currentReviewers } }), + listReviews: jest.fn().mockResolvedValue({ data: submittedReviews }), requestReviewers: jest.fn().mockResolvedValue({}), }, }, @@ -92,6 +94,20 @@ describe('manage-release-pr', () => { expect(github.rest.pulls.requestReviewers).not.toHaveBeenCalled() }) + it('does not re-request reviews from people who already approved', async () => { + const github = makeGithub({ + commits: [{ sha: 'abc123' }], + mergedPRs: [unreleasedPR], + openPRs: [{ number: 42 }], + currentReviewers: [], + submittedReviews: [{ user: { login: 'alice' }, state: 'APPROVED' }], + }) + + await run({ github, context: makeContext() }) + + expect(github.rest.pulls.requestReviewers).not.toHaveBeenCalled() + }) + it('excludes bots from reviewers', async () => { const github = makeGithub({ commits: [{ sha: 'abc123' }], From 5e69d40697efb022774401055f29c6e4b78418f6 Mon Sep 17 00:00:00 2001 From: Nathan Cairns Date: Mon, 10 Aug 2026 11:22:49 +0200 Subject: [PATCH 2/2] Simplify for readability --- .../release-pr-bot/manage-release-pr.js | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/.github/actions/release-pr-bot/manage-release-pr.js b/.github/actions/release-pr-bot/manage-release-pr.js index 4ffb9a1..05d7fab 100644 --- a/.github/actions/release-pr-bot/manage-release-pr.js +++ b/.github/actions/release-pr-bot/manage-release-pr.js @@ -129,28 +129,27 @@ async function updateReleasePR({ github, owner, repo, pr, body, reviewers }) { await github.rest.pulls.update({ owner, repo, pull_number: pr.number, body }) - const { data: currentReviews } = - await github.rest.pulls.listRequestedReviewers({ - owner, - repo, - pull_number: pr.number, - }) - - const { data: submittedReviews } = await github.rest.pulls.listReviews({ - owner, - repo, - pull_number: pr.number, - }) - - const currentLogins = new Set(currentReviews.users.map((u) => u.login)) - const approvers = new Set( - submittedReviews + const [{ data: currentReviews }, { data: submittedReviews }] = + await Promise.all([ + github.rest.pulls.listRequestedReviewers({ + owner, + repo, + pull_number: pr.number, + }), + github.rest.pulls.listReviews({ + owner, + repo, + pull_number: pr.number, + }), + ]) + + const excludedLogins = new Set([ + ...currentReviews.users.map((u) => u.login), + ...submittedReviews .filter((review) => review.state === 'APPROVED') .map((review) => review.user?.login), - ) - const newReviewers = reviewers.filter( - (r) => !currentLogins.has(r) && !approvers.has(r), - ) + ]) + const newReviewers = reviewers.filter((r) => !excludedLogins.has(r)) if (newReviewers.length > 0) { await github.rest.pulls.requestReviewers({