Add workflow to notify maintainer (me) when pr needs reivew
Some checks are pending
📚 Inserts Awesome Privacy into README / build (push) Waiting to run

This commit is contained in:
Alicia Sykes 2026-02-27 23:33:04 +00:00
parent 259314537a
commit f95a41c08c
2 changed files with 177 additions and 0 deletions

View file

@ -4,9 +4,12 @@ on:
workflow_run:
workflows: ["PR Check"]
types: [completed]
pull_request_review:
types: [submitted]
permissions:
actions: read
checks: read
contents: read
pull-requests: write
@ -132,3 +135,87 @@ jobs:
});
console.log('Updated bot comment.');
}
review-notify:
name: Notify maintainer
runs-on: ubuntu-latest
if: github.event_name == 'pull_request_review'
steps:
- uses: actions/checkout@v4
- name: Fetch review and CI context
id: context
uses: actions/github-script@v7
with:
github-token: ${{ secrets.BOT_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const pr = context.payload.pull_request;
const { owner, repo } = context.repo;
// Fetch reviews — extract user login and state
const { data: reviews } = await github.rest.pulls.listReviews({
owner, repo, pull_number: pr.number, per_page: 100,
});
const reviewData = reviews.map(r => ({
user: r.user.login,
state: r.state,
}));
// Fetch check runs for the PR head SHA
const { data: { check_runs } } = await github.rest.checks.listForRef({
owner, repo, ref: pr.head.sha, per_page: 100,
});
const checkData = check_runs.map(cr => ({
status: cr.status,
conclusion: cr.conclusion,
}));
// Check if we already posted the notification
const marker = '<!-- pr-review-ready -->';
const { data: comments } = await github.rest.issues.listComments({
owner, repo, issue_number: pr.number, per_page: 100,
});
const alreadyNotified = comments.some(c => c.body.includes(marker));
// Write data for Python
fs.mkdirSync('pr-meta', { recursive: true });
fs.writeFileSync('pr-meta/reviews.json', JSON.stringify(reviewData));
fs.writeFileSync('pr-meta/check-runs.json', JSON.stringify(checkData));
fs.writeFileSync('pr-meta/already-notified.txt', String(alreadyNotified));
core.setOutput('pr_number', pr.number);
- name: Check review readiness
run: python lib/checks/check-review-ready.py
- name: Post notification
uses: actions/github-script@v7
with:
github-token: ${{ secrets.BOT_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const actionFile = 'pr-meta/action.txt';
if (!fs.existsSync(actionFile)) return;
const action = fs.readFileSync(actionFile, 'utf8').trim();
if (action !== 'notify') {
console.log('Not ready for review — skipping.');
return;
}
const body = [
'<!-- pr-review-ready -->',
'This PR is now ready to be merged, pending maintainer review. All checks are passing and it has been peer-reviewed.',
'',
'@Lissy93 - Please evaluate, and either merge or leave feedback.',
].join('\n');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: parseInt('${{ steps.context.outputs.pr_number }}'),
body,
});
console.log('Posted maintainer notification.');

View file

@ -0,0 +1,90 @@
"""Decides whether a PR is ready for maintainer review.
Conditions: 2+ approvals from external contributors AND all CI checks passing.
Reads:
pr-meta/reviews.json array of {user, state} from GitHub API
pr-meta/check-runs.json array of {status, conclusion} from GitHub API
pr-meta/already-notified.txt "true" if notification comment already exists
Writes:
pr-meta/action.txt "notify" or "skip"
"""
import json
import os
WORK_DIR = "pr-meta"
MAINTAINER = "Lissy93"
REQUIRED_APPROVALS = 2
PASSING_CONCLUSIONS = {"success", "skipped", "neutral"}
def read_json(filename):
"""Load a JSON file from the work directory, or empty list on error."""
try:
with open(os.path.join(WORK_DIR, filename)) as f:
return json.load(f)
except Exception:
return []
def count_external_approvals(reviews):
"""Count unique non-maintainer users who approved."""
approvers = {
r["user"]
for r in reviews
if r.get("state") == "APPROVED"
and r.get("user", "").lower() != MAINTAINER.lower()
}
return len(approvers)
def all_checks_passing(check_runs):
"""Return True if every check run completed successfully."""
if not check_runs:
return False
return all(
cr.get("status") == "completed"
and cr.get("conclusion") in PASSING_CONCLUSIONS
for cr in check_runs
)
def already_notified():
"""Return True if the notification comment already exists on the PR."""
try:
with open(os.path.join(WORK_DIR, "already-notified.txt")) as f:
return f.read().strip().lower() == "true"
except Exception:
return False
def write_action(action):
os.makedirs(WORK_DIR, exist_ok=True)
with open(os.path.join(WORK_DIR, "action.txt"), "w") as f:
f.write(action)
def main():
if already_notified():
write_action("skip")
return
reviews = read_json("reviews.json")
approvals = count_external_approvals(reviews)
if approvals < REQUIRED_APPROVALS:
write_action("skip")
return
check_runs = read_json("check-runs.json")
if not all_checks_passing(check_runs):
write_action("skip")
return
write_action("notify")
if __name__ == "__main__":
main()