From 805b8174f7c6a59f5de1d831dfe071c358bc238d Mon Sep 17 00:00:00 2001 From: Roomote Date: Fri, 11 Sep 2026 02:14:53 +0000 Subject: [PATCH 1/2] fix(ci): review zoomote pull requests with CodeRabbit --- .github/workflows/label-pr-review-state.yml | 7 ++- .../pr-review-state-workflow.test.ts | 43 +++++++++++++++++-- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/.github/workflows/label-pr-review-state.yml b/.github/workflows/label-pr-review-state.yml index d2c24ce3c0..46a9080a07 100644 --- a/.github/workflows/label-pr-review-state.yml +++ b/.github/workflows/label-pr-review-state.yml @@ -87,6 +87,7 @@ jobs: const codeRabbitLogin = 'coderabbitai[bot]'; const codeRabbitLogins = new Set([codeRabbitLogin, 'coderabbitai']); const codeRabbitActiveLabel = 'coderabbit-review-active'; + const codeRabbitEligibleBotLogins = new Set(['zoomote[bot]']); const reviewGateName = 'Zoo Code / PR review gate'; const reconciliationCheckName = 'Zoo Code / reconcile PR review state'; @@ -660,6 +661,8 @@ jobs: review => review.state === 'CHANGES_REQUESTED' ); const automatedAuthor = pr.user?.type === 'Bot'; + const codeRabbitEligibleAuthor = !automatedAuthor || + codeRabbitEligibleBotLogins.has(pr.user?.login.toLowerCase()); const codeRabbitReviewComplete = freshCodeRabbitReview?.state === 'APPROVED'; const codeRabbitChangesRequested = freshCodeRabbitReview?.state === 'CHANGES_REQUESTED'; const maintainerApproval = freshMaintainerReviews @@ -676,7 +679,7 @@ jobs: if (codeRabbitChangesRequested || maintainerChangeRequest) { desiredLabel = 'awaiting-author'; phase = codeRabbitChangesRequested ? 'coderabbit-changes' : 'maintainer-changes'; - } else if (automatedAuthor) { + } else if (!codeRabbitEligibleAuthor) { if (pr.draft) { desiredLabel = null; phase = 'draft'; @@ -728,7 +731,7 @@ jobs: core.info( `PR #${pr.number}: CI passing, reviews=${latest.size}, ` + - `coderabbit=${freshCodeRabbitReview?.state ?? (automatedAuthor ? 'optional' : 'pending')}, ` + + `coderabbit=${freshCodeRabbitReview?.state ?? (codeRabbitEligibleAuthor ? 'pending' : 'optional')}, ` + `maintainer=${maintainerApproval?.state ?? 'pending'} → ${desiredLabel ?? '(none)'}` ); diff --git a/src/services/__tests__/pr-review-state-workflow.test.ts b/src/services/__tests__/pr-review-state-workflow.test.ts index abc77eed2a..b722629dce 100644 --- a/src/services/__tests__/pr-review-state-workflow.test.ts +++ b/src/services/__tests__/pr-review-state-workflow.test.ts @@ -537,11 +537,46 @@ describe("PR review-state workflow", () => { expect(latestGuide(result)).toContain("Review-state labels are managed by this workflow") }) - it("routes bot-authored PRs directly to maintainer review", async () => { + it("starts CodeRabbit for zoomote-authored PRs after required CI passes", async () => { const result = await runWorkflow({ prAuthor: { login: "zoomote[bot]", type: "Bot" }, }) + expect(result.addLabels).toHaveBeenCalledWith(expect.objectContaining({ labels: ["coderabbit-review-active"] })) + expect(result.addLabels).toHaveBeenCalledWith(expect.objectContaining({ labels: ["awaiting-coderabbit"] })) + expect(latestGateStatus(result)?.state).toBe("pending") + expect(latestGateStatus(result)?.description).toContain("Waiting for automated review") + }) + + it("does not start CodeRabbit for draft zoomote-authored PRs", async () => { + const result = await runWorkflow({ + draft: true, + prAuthor: { login: "zoomote[bot]", type: "Bot" }, + }) + + expect(result.addLabels).not.toHaveBeenCalledWith( + expect.objectContaining({ labels: ["coderabbit-review-active"] }), + ) + expect(latestGuide(result)).toContain("Mark the PR ready") + }) + + it("does not start CodeRabbit for zoomote-authored PRs while required CI fails", async () => { + const result = await runWorkflow({ + prAuthor: { login: "zoomote[bot]", type: "Bot" }, + requiredConclusion: "failure", + }) + + expect(result.addLabels).not.toHaveBeenCalledWith( + expect.objectContaining({ labels: ["coderabbit-review-active"] }), + ) + expect(latestGateStatus(result)?.description).toContain("Fix the failing required CI checks") + }) + + it("routes other bot-authored PRs directly to maintainer review", async () => { + const result = await runWorkflow({ + prAuthor: { login: "dependabot[bot]", type: "Bot" }, + }) + expect(result.addLabels).toHaveBeenCalledWith(expect.objectContaining({ labels: ["awaiting-maintainer"] })) expect(result.addLabels).not.toHaveBeenCalledWith( expect.objectContaining({ labels: ["coderabbit-review-active"] }), @@ -550,9 +585,9 @@ describe("PR review-state workflow", () => { expect(latestGateStatus(result)?.description).toContain("Awaiting fresh human maintainer") }) - it("completes bot-authored PR review after human maintainer approval", async () => { + it("completes other bot-authored PR review after human maintainer approval", async () => { const result = await runWorkflow({ - prAuthor: { login: "zoomote[bot]", type: "Bot" }, + prAuthor: { login: "dependabot[bot]", type: "Bot" }, permissions: { maintainer: "write" }, reviews: [ { @@ -569,7 +604,7 @@ describe("PR review-state workflow", () => { it("honors manually requested CodeRabbit changes on bot-authored PRs", async () => { const result = await runWorkflow({ - prAuthor: { login: "zoomote[bot]", type: "Bot" }, + prAuthor: { login: "dependabot[bot]", type: "Bot" }, reviews: [ { login: "coderabbitai[bot]", From 039b1cd02a197a978bac0b16dace396a56933f3e Mon Sep 17 00:00:00 2001 From: Roomote Date: Fri, 11 Sep 2026 04:02:51 +0000 Subject: [PATCH 2/2] test(ci): assert CodeRabbit routing logs --- src/services/__tests__/pr-review-state-workflow.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/services/__tests__/pr-review-state-workflow.test.ts b/src/services/__tests__/pr-review-state-workflow.test.ts index b722629dce..239f22ee5a 100644 --- a/src/services/__tests__/pr-review-state-workflow.test.ts +++ b/src/services/__tests__/pr-review-state-workflow.test.ts @@ -396,6 +396,7 @@ async function runWorkflow(options: HarnessOptions = {}) { createCommitStatus, createLabel, setFailed, + info: core.info, warning: core.warning, getPullRequest, listPullRequests: github.rest.pulls.list, @@ -546,6 +547,7 @@ describe("PR review-state workflow", () => { expect(result.addLabels).toHaveBeenCalledWith(expect.objectContaining({ labels: ["awaiting-coderabbit"] })) expect(latestGateStatus(result)?.state).toBe("pending") expect(latestGateStatus(result)?.description).toContain("Waiting for automated review") + expect(result.info).toHaveBeenCalledWith(expect.stringContaining("coderabbit=pending")) }) it("does not start CodeRabbit for draft zoomote-authored PRs", async () => { @@ -583,6 +585,7 @@ describe("PR review-state workflow", () => { ) expect(latestGateStatus(result)?.state).toBe("success") expect(latestGateStatus(result)?.description).toContain("Awaiting fresh human maintainer") + expect(result.info).toHaveBeenCalledWith(expect.stringContaining("coderabbit=optional")) }) it("completes other bot-authored PR review after human maintainer approval", async () => {