This is an automated email from the ASF dual-hosted git repository.
damccorm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git
The following commit(s) were added to refs/heads/master by this push:
new 3c41bd28c9a [PR Bot] Best-effort assign reviewers via GitHub API
(#40313)
3c41bd28c9a is described below
commit 3c41bd28c9a8a27350058242c7cd77e287a52a81
Author: Danny McCormick <[email protected]>
AuthorDate: Mon Sep 28 15:28:45 2026 +0000
[PR Bot] Best-effort assign reviewers via GitHub API (#40313)
---
scripts/ci/pr-bot/findPrsNeedingAttention.ts | 4 +++
scripts/ci/pr-bot/processNewPrs.ts | 5 +++
scripts/ci/pr-bot/shared/githubUtils.ts | 25 ++++++++++++++
scripts/ci/pr-bot/shared/userCommand.ts | 5 +++
scripts/ci/pr-bot/test/githubUtilsTest.ts | 51 +++++++++++++++++++++++++++-
5 files changed, 89 insertions(+), 1 deletion(-)
diff --git a/scripts/ci/pr-bot/findPrsNeedingAttention.ts
b/scripts/ci/pr-bot/findPrsNeedingAttention.ts
index 46233b4ce31..46514671be0 100644
--- a/scripts/ci/pr-bot/findPrsNeedingAttention.ts
+++ b/scripts/ci/pr-bot/findPrsNeedingAttention.ts
@@ -133,6 +133,10 @@ async function assignToNewReviewers(
labels: pull.labels,
})
);
+ await github.requestPrReviewers(
+ pull.number,
+ Object.values(prState.reviewersAssignedForLabels)
+ );
await stateClient.writePrState(pull.number, prState);
let labelsToUpdate = Object.keys(reviewerStateToUpdate);
diff --git a/scripts/ci/pr-bot/processNewPrs.ts
b/scripts/ci/pr-bot/processNewPrs.ts
index 90957451acc..fbcd78a0db8 100644
--- a/scripts/ci/pr-bot/processNewPrs.ts
+++ b/scripts/ci/pr-bot/processNewPrs.ts
@@ -300,6 +300,7 @@ async function processPull(
pull.number,
commentStrings.assignCommitter(chosenCommitter)
);
+ await github.requestPrReviewers(pull.number, [chosenCommitter]);
await github.nextActionReviewers(pull.number, pull.labels);
prState.nextAction = REVIEWERS_ACTION;
@@ -359,6 +360,10 @@ async function processPull(
labels: pull.labels,
})
);
+ await github.requestPrReviewers(
+ pull.number,
+ Object.values(prState.reviewersAssignedForLabels)
+ );
github.nextActionReviewers(pull.number, pull.labels);
prState.nextAction = "Reviewers";
diff --git a/scripts/ci/pr-bot/shared/githubUtils.ts
b/scripts/ci/pr-bot/shared/githubUtils.ts
index 696f5f9c739..ce05aa3b44b 100644
--- a/scripts/ci/pr-bot/shared/githubUtils.ts
+++ b/scripts/ci/pr-bot/shared/githubUtils.ts
@@ -42,6 +42,31 @@ export async function addPrComment(pullNumber: number, body:
string) {
});
}
+export async function requestPrReviewers(
+ pullNumber: number,
+ reviewers: string[],
+ githubClient?: any
+) {
+ if (!reviewers || reviewers.length === 0) {
+ return;
+ }
+ const client = githubClient || getGitHubClient();
+ for (const reviewer of reviewers) {
+ try {
+ await client.rest.pulls.requestReviewers({
+ owner: REPO_OWNER,
+ repo: REPO,
+ pull_number: pullNumber,
+ reviewers: [reviewer],
+ });
+ } catch (err) {
+ console.log(
+ `Unable to request review from ${reviewer} on PR ${pullNumber} (best
effort): ${err}`
+ );
+ }
+ }
+}
+
export async function nextActionReviewers(
pullNumber: number,
existingLabels: Label[]
diff --git a/scripts/ci/pr-bot/shared/userCommand.ts
b/scripts/ci/pr-bot/shared/userCommand.ts
index e1bb6067903..8c09013553e 100644
--- a/scripts/ci/pr-bot/shared/userCommand.ts
+++ b/scripts/ci/pr-bot/shared/userCommand.ts
@@ -109,6 +109,7 @@ async function assignToNextReviewer(
labels: existingLabels,
})
);
+ await github.requestPrReviewers(pullNumber, [chosenReviewer]);
// Set next action to reviewer
await github.nextActionReviewers(pullNumber, existingLabels);
@@ -233,6 +234,10 @@ async function assignReviewerSet(
labels: existingLabels,
})
);
+ await github.requestPrReviewers(
+ pullNumber,
+ Object.values(prState.reviewersAssignedForLabels)
+ );
github.nextActionReviewers(pullNumber, existingLabels);
prState.nextAction = "Reviewers";
diff --git a/scripts/ci/pr-bot/test/githubUtilsTest.ts
b/scripts/ci/pr-bot/test/githubUtilsTest.ts
index b6da236247a..bf6b460a51c 100644
--- a/scripts/ci/pr-bot/test/githubUtilsTest.ts
+++ b/scripts/ci/pr-bot/test/githubUtilsTest.ts
@@ -17,7 +17,7 @@
*/
var assert = require("assert");
-const { hasLabel } = require("../shared/githubUtils");
+const { hasLabel, requestPrReviewers } = require("../shared/githubUtils");
describe("githubUtils", function () {
describe("hasLabel()", function () {
@@ -58,6 +58,55 @@ describe("githubUtils", function () {
assert.equal(hasLabel(null, "awaiting triage"), false);
});
});
+
+ describe("requestPrReviewers()", function () {
+ it("should request review for each reviewer via the GitHub client", async
function () {
+ const requested: string[][] = [];
+ const mockClient = {
+ rest: {
+ pulls: {
+ requestReviewers: async ({
+ reviewers,
+ }: {
+ reviewers: string[];
+ }) => {
+ requested.push(reviewers);
+ },
+ },
+ },
+ };
+ await requestPrReviewers(123, ["reviewer1", "reviewer2"], mockClient);
+ assert.deepEqual(requested, [["reviewer1"], ["reviewer2"]]);
+ });
+
+ it("should continue best-effort if requesting a reviewer fails", async
function () {
+ const requested: string[][] = [];
+ const mockClient = {
+ rest: {
+ pulls: {
+ requestReviewers: async ({
+ reviewers,
+ }: {
+ reviewers: string[];
+ }) => {
+ if (reviewers[0] === "nonCollaborator") {
+ throw new Error(
+ "Reviews may only be requested from collaborators."
+ );
+ }
+ requested.push(reviewers);
+ },
+ },
+ },
+ };
+ await requestPrReviewers(
+ 123,
+ ["nonCollaborator", "collaboratorReviewer"],
+ mockClient
+ );
+ assert.deepEqual(requested, [["collaboratorReviewer"]]);
+ });
+ });
});
export {};