From 9b3c5df7894fe8f5af8bfdfc85a508645d2cf6fa Mon Sep 17 00:00:00 2001 From: "Michael E. Karpeles (Mek)" Date: Wed, 15 Jul 2026 17:14:54 -0600 Subject: [PATCH 1/2] feat(agentic): scaffold Code Review Action trigger, NOP for now Wires up both trigger paths for #13163 -- requesting @openlibrary-bot as a PR reviewer, and @-mentioning it in a PR comment -- staff-gated on both. No review logic yet; posts a placeholder comment confirming the trigger fired so the untested event wiring (review_requested, staff-only issue_comment on a PR) can be verified independently of the review-generation work, which is still blocked on research. Plain actions/github-script, no claude-code-action -- avoids the permission-bypass and ref-resolution-lag issues found in #13161 until real review logic actually needs an LLM. --- .github/workflows/code_review_action.yml | 61 ++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 .github/workflows/code_review_action.yml diff --git a/.github/workflows/code_review_action.yml b/.github/workflows/code_review_action.yml new file mode 100644 index 00000000000..9f03d3148f0 --- /dev/null +++ b/.github/workflows/code_review_action.yml @@ -0,0 +1,61 @@ +name: Code Review Action + +on: + pull_request: + types: [review_requested] + issue_comment: + types: [created] + +permissions: + contents: read + pull-requests: write + issues: write + +concurrency: + group: code-review-${{ github.event.pull_request.number || github.event.issue.number }} + cancel-in-progress: false + +jobs: + respond: + runs-on: ubuntu-latest + # Placeholder scaffold for #13163 -- trigger wiring only, no review logic yet. + # Both paths are staff-gated: requesting @openlibrary-bot as a reviewer, or + # @-mentioning it in a PR comment. Staff list mirrors pr_autoresponder.yml / + # issue_enrichment.md's blessed list. openlibrary-bot's own account type is + # "User", not "Bot" (see #13161/#13165) -- excluded explicitly by login, + # not by type/is_bot, which we've already found unreliable for this account. + if: > + ( + github.event_name == 'pull_request' && + github.event.requested_reviewer.login == 'openlibrary-bot' && + contains(fromJSON('["mekarpeles","cdrini","jimchamp","hornc","scottbarnes","seabelis","RayBB","lokesh"]'), github.event.sender.login) + ) || ( + github.event_name == 'issue_comment' && + github.event.issue.pull_request != null && + contains(github.event.comment.body, '@openlibrary-bot') && + github.event.comment.user.login != 'openlibrary-bot' && + contains(fromJSON('["mekarpeles","cdrini","jimchamp","hornc","scottbarnes","seabelis","RayBB","lokesh"]'), github.event.comment.user.login) + ) + steps: + - name: Acknowledge trigger (placeholder -- no review logic yet) + uses: actions/github-script@v9 + with: + script: | + const prNumber = context.payload.pull_request + ? context.payload.pull_request.number + : context.payload.issue.number; + const trigger = context.eventName === 'pull_request' + ? 'a reviewer request' + : 'an @-mention'; + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: [ + `👀 Code review was requested via ${trigger}, but the automated reviewer isn't built yet — tracked in #13163.`, + '', + 'This comment only confirms the trigger fired correctly. No review was performed.', + '', + '', + ].join('\n'), + }); From 0945410e8e97088e570bb1dc354d00b7483f6100 Mon Sep 17 00:00:00 2001 From: "Michael E. Karpeles (Mek)" Date: Wed, 15 Jul 2026 22:00:34 -0600 Subject: [PATCH 2/2] feat(agentic): split into auto-assign + review trigger, handle drafts and self-authored PRs Splits the scaffold into two workflows: - auto_assign_reviewer.yml: requests openlibrary-bot as reviewer on any non-draft PR that doesn't already have one, opened or moved out of draft. Skips PRs openlibrary-bot itself authored. - code_review_action.yml: fires on review_requested (manual or auto-assigned), on opened/ready_for_review when openlibrary-bot is the PR's own author, and on staff-only @-mentions. Still a NOP placeholder -- no review logic yet. Draft PRs never trigger a review on any path, including a defensive in-job check for the paths whose event payload has no draft field. GitHub rejects requesting a PR's own author as a reviewer (422), so self-authored PRs can't go through the normal request-reviewer path -- code_review_action.yml's own opened/ready_for_review trigger is the direct substitute for that case. --- .github/workflows/auto_assign_reviewer.yml | 54 +++++++++++++ .github/workflows/code_review_action.yml | 92 +++++++++++++++++----- 2 files changed, 128 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/auto_assign_reviewer.yml diff --git a/.github/workflows/auto_assign_reviewer.yml b/.github/workflows/auto_assign_reviewer.yml new file mode 100644 index 00000000000..37b1693d0cf --- /dev/null +++ b/.github/workflows/auto_assign_reviewer.yml @@ -0,0 +1,54 @@ +name: Auto-assign Code Review + +on: + pull_request: + types: [opened, ready_for_review] + +permissions: + contents: read + pull-requests: write + +concurrency: + group: auto-assign-review-${{ github.event.pull_request.number }} + cancel-in-progress: false + +jobs: + assign: + runs-on: ubuntu-latest + # Self-authored PRs (opened by openlibrary-bot itself) are excluded here -- + # GitHub rejects requesting a PR's own author as a reviewer (422). Those are + # handled directly by code_review_action.yml's own opened/ready_for_review + # trigger instead, bypassing the reviewer-request mechanism entirely. + if: > + !github.event.pull_request.draft && + github.event.pull_request.user.login != 'openlibrary-bot' + steps: + - name: Request openlibrary-bot as reviewer if not already present + uses: actions/github-script@v9 + with: + script: | + const owner = context.repo.owner; + const repo = context.repo.repo; + const prNumber = context.payload.pull_request.number; + + const { data: requested } = await github.rest.pulls.listRequestedReviewers({ + owner, repo, pull_number: prNumber, + }); + if (requested.users.some((u) => u.login === 'openlibrary-bot')) { + core.info(`PR #${prNumber} already has openlibrary-bot requested -- skipping.`); + return; + } + + const reviews = await github.paginate(github.rest.pulls.listReviews, { + owner, repo, pull_number: prNumber, per_page: 100, + }); + if (reviews.some((r) => r.user.login === 'openlibrary-bot')) { + core.info(`PR #${prNumber} already has an openlibrary-bot review -- skipping.`); + return; + } + + await github.rest.pulls.requestReviewers({ + owner, repo, pull_number: prNumber, + reviewers: ['openlibrary-bot'], + }); + core.info(`Requested openlibrary-bot as reviewer on PR #${prNumber}.`); diff --git a/.github/workflows/code_review_action.yml b/.github/workflows/code_review_action.yml index 9f03d3148f0..a667b223569 100644 --- a/.github/workflows/code_review_action.yml +++ b/.github/workflows/code_review_action.yml @@ -2,9 +2,15 @@ name: Code Review Action on: pull_request: - types: [review_requested] + types: [review_requested, opened, ready_for_review] issue_comment: types: [created] + workflow_dispatch: + inputs: + pr_number: + description: "Debug: manually run the code review trigger on a specific existing PR" + required: true + type: string permissions: contents: read @@ -12,23 +18,40 @@ permissions: issues: write concurrency: - group: code-review-${{ github.event.pull_request.number || github.event.issue.number }} + group: code-review-${{ github.event.pull_request.number || github.event.issue.number || inputs.pr_number }} cancel-in-progress: false jobs: respond: runs-on: ubuntu-latest # Placeholder scaffold for #13163 -- trigger wiring only, no review logic yet. - # Both paths are staff-gated: requesting @openlibrary-bot as a reviewer, or - # @-mentioning it in a PR comment. Staff list mirrors pr_autoresponder.yml / - # issue_enrichment.md's blessed list. openlibrary-bot's own account type is - # "User", not "Bot" (see #13161/#13165) -- excluded explicitly by login, - # not by type/is_bot, which we've already found unreliable for this account. + # + # Three trigger paths: + # 1. review_requested with openlibrary-bot as the reviewer -- covers both a + # human manually requesting it, and auto_assign_reviewer.yml's automated + # request. No staff-login check here: requesting *any* reviewer already + # requires write/triage access on GitHub's side, so this isn't an open door. + # 2. opened / ready_for_review where the PR's own author is openlibrary-bot -- + # GitHub rejects requesting a PR's own author as a reviewer (422), so a + # self-authored PR can never reach this workflow via path 1. This is the + # direct substitute for "add openlibrary-bot as a reviewer on its own PR", + # which is not literally possible. + # 3. issue_comment @-mention on a PR -- open to any commenter, including + # external contributors with only read access, so this path keeps an + # explicit staff allowlist (mirrors pr_autoresponder.yml / issue_enrichment.md). + # + # Draft PRs never trigger a review, on any path -- enforced again defensively + # inside the job itself (see Step 1), since issue_comment's payload has no + # PR draft field to check at the `if:` level. if: > + github.event_name == 'workflow_dispatch' || ( github.event_name == 'pull_request' && - github.event.requested_reviewer.login == 'openlibrary-bot' && - contains(fromJSON('["mekarpeles","cdrini","jimchamp","hornc","scottbarnes","seabelis","RayBB","lokesh"]'), github.event.sender.login) + !github.event.pull_request.draft && + ( + github.event.requested_reviewer.login == 'openlibrary-bot' || + github.event.pull_request.user.login == 'openlibrary-bot' + ) ) || ( github.event_name == 'issue_comment' && github.event.issue.pull_request != null && @@ -41,16 +64,49 @@ jobs: uses: actions/github-script@v9 with: script: | - const prNumber = context.payload.pull_request - ? context.payload.pull_request.number - : context.payload.issue.number; - const trigger = context.eventName === 'pull_request' - ? 'a reviewer request' - : 'an @-mention'; + const owner = context.repo.owner; + const repo = context.repo.repo; + const prNumber = context.eventName === 'workflow_dispatch' + ? Number(context.payload.inputs.pr_number) + : (context.payload.pull_request + ? context.payload.pull_request.number + : context.payload.issue.number); + + // Defensive draft check -- issue_comment's payload has no PR draft + // field, and this also re-confirms the pull_request-path checks + // above in case GitHub's payload state lagged the actual PR state. + const { data: pr } = await github.rest.pulls.get({ + owner, repo, pull_number: prNumber, + }); + if (pr.draft) { + core.info(`PR #${prNumber} is a draft -- skipping.`); + return; + } + + // Idempotency: this workflow can be reached by multiple overlapping + // paths (e.g. opened -> auto-assign -> review_requested), so guard + // against posting more than one placeholder. + const comments = await github.paginate(github.rest.issues.listComments, { + owner, repo, issue_number: prNumber, per_page: 100, + }); + if (comments.some((c) => (c.body || '').includes(''))) { + core.info(`PR #${prNumber} already has a placeholder comment -- skipping.`); + return; + } + + let trigger; + if (context.eventName === 'workflow_dispatch') { + trigger = 'a manual debug dispatch'; + } else if (context.eventName === 'issue_comment') { + trigger = 'an @-mention'; + } else if (pr.user.login === 'openlibrary-bot') { + trigger = 'its own PR being opened (self-authored, cannot request itself as reviewer)'; + } else { + trigger = 'a reviewer request'; + } + await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: prNumber, + owner, repo, issue_number: prNumber, body: [ `👀 Code review was requested via ${trigger}, but the automated reviewer isn't built yet — tracked in #13163.`, '',