From c323ad323040ed77e0d49c1fb9445a8a9dcf08ca Mon Sep 17 00:00:00 2001 From: wSedlacek Date: Sat, 7 Nov 2026 00:32:49 -0800 Subject: [PATCH] fix(github): keep review-required until required reviewers approve GitHub's REVIEW_REQUIRED already encodes approval count and CODEOWNERS rules, but any APPROVED latest review was promoted to approved. Only fall back to latest reviews when GitHub reports no verdict. Co-authored-by: Cursor --- .../src/server/gitHubPullRequestJson.test.ts | 14 ++++++++++++++ .../src/server/gitHubPullRequestJson.ts | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/source-control-github/src/server/gitHubPullRequestJson.test.ts b/packages/source-control-github/src/server/gitHubPullRequestJson.test.ts index f06c847471d0e..2ee073a2a330b 100644 --- a/packages/source-control-github/src/server/gitHubPullRequestJson.test.ts +++ b/packages/source-control-github/src/server/gitHubPullRequestJson.test.ts @@ -294,6 +294,20 @@ describe("pull request list decoding", () => { ]); }); + it("keeps review required when an approval falls short of the branch's required count", () => { + const batch = expectSuccess( + decodePullRequestListJson( + listJson([ + { + reviewDecision: "REVIEW_REQUIRED", + latestReviews: [{ author: user("octocat"), state: "APPROVED" }], + }, + ]), + ), + ); + expect(batch.items.map((entry) => entry.reviewDecision)).toEqual(["review-required"]); + }); + it("skips malformed entries but still counts them, so paging does not stop early", () => { const batch = expectSuccess( decodePullRequestListJson(listJson([{}, { number: "not-a-number" }])), diff --git a/packages/source-control-github/src/server/gitHubPullRequestJson.ts b/packages/source-control-github/src/server/gitHubPullRequestJson.ts index a4c509e944488..f92c35f7afa21 100644 --- a/packages/source-control-github/src/server/gitHubPullRequestJson.ts +++ b/packages/source-control-github/src/server/gitHubPullRequestJson.ts @@ -509,7 +509,7 @@ export function toPullRequestActionSummary( }; } -/** GitHub's reviewDecision ignores reviews outside branch rules, including app approvals. */ +/** Prefer GitHub's reviewDecision; only use latest reviews when it is absent (e.g. bot approvals). */ function toReviewDecisionWithReviews( value: string | null | undefined, reviews: ReadonlyArray | undefined, @@ -518,7 +518,7 @@ function toReviewDecisionWithReviews( if (summarized === "approved" || summarized === "changes-requested") return summarized; const states = new Set((reviews ?? []).map((review) => review.state?.trim().toUpperCase() ?? "")); if (states.has("CHANGES_REQUESTED")) return "changes-requested"; - if (states.has("APPROVED")) return "approved"; + if (summarized === null && states.has("APPROVED")) return "approved"; return summarized; }