Skip to content

feat: add PR review status evaluator (all 3 phases) #10

feat: add PR review status evaluator (all 3 phases)

feat: add PR review status evaluator (all 3 phases) #10

# This workflow computes and logs the current review status of a PR (what
# stage it's in, who's expected to review, who it's still waiting on) using
# .github/scripts/review-status-evaluator.js. It is read-only: it never
# comments on or otherwise mutates the PR, so it only needs read permissions
# and can safely run on pull_request (not pull_request_target).
#
# Security note: this workflow deliberately checks out the PR's *base* ref
# (i.e. the trusted branch the PR targets, typically main) rather than the
# PR's own head/merge ref when loading the evaluator script. A malicious
# fork PR could otherwise modify review-status-evaluator.js or its shared
# dependencies, and actions/github-script would execute that modified code
# with the authenticated `github` client. Checking out the base ref means
# the workflow always runs the script as it exists on the trusted branch,
# regardless of what the PR itself changes.
name: PR Review Status Evaluator
on:
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled, ready_for_review]
pull_request_review:
types: [submitted, dismissed]
permissions:
contents: read
pull-requests: read
concurrency:
group: pr-review-status-evaluator-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
evaluate-status:
runs-on: ubuntu-latest
steps:
- name: Harden the runner
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
with:
egress-policy: audit
- name: Checkout trusted evaluator scripts (PR base ref, not head)
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.pull_request.base.sha }}
persist-credentials: false
fetch-depth: 1
- name: Evaluate PR review status
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { evaluateReviewStatus, formatStatusForLog } = require('./.github/scripts/review-status-evaluator.js');
const status = await evaluateReviewStatus(github, context);
if (!status) {
core.info('No review status computed (no PR number resolved).');
return;
}
core.info(formatStatusForLog(status));
core.setOutput('current_stage', status.currentStage);
core.setOutput('expected_reviewers', status.expectedReviewers.join(','));
core.setOutput('waiting_on', status.waitingOn.join(','));
core.setOutput('next_action', status.nextAction);
core.setOutput('summary', status.summary);
await core.summary
.addHeading('PR Review Status')
.addTable([
[{ data: 'Field', header: true }, { data: 'Value', header: true }],
['Current stage', status.currentStage],
['Expected reviewers', status.expectedReviewers.join(', ') || 'none'],
['Waiting on', status.waitingOn.join(', ') || 'none'],
['Next action', status.nextAction],
])
.write();