Files
nexus-quant-terminal/.github/workflows/daily-pr-review.yml
T
Claude 3653078d02 ci: make email approve/reject parsing robust to quoted replies
Phone mail apps can glue the quoted header onto the reply
("ApproveOn 29 Sep 2026, at 10:48 AM, ... wrote:"), so the first word was
read as "approveon" and the approval on #3 was ignored. Parse in Python:
strip the quoted email ("On <date> ... wrote:" and '>' lines), then match
approve/lgtm/reject by prefix. Reasons keep their full text, and the
GITHUB_OUTPUT delimiter is random.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FpiqUMAyo4RL5DdQHMWbwE
2026-09-29 05:50:20 +00:00

113 lines
4.3 KiB
YAML

name: Daily PR Review
# Approve or reject the daily Claude PRs by commenting (or replying to the
# GitHub notification email):
# approve -> PR is merged into main (quoted email text is ignored)
# reject: <reason> -> PR is closed, labelled "rejected", reason kept
# Only the repository owner's comments are acted on.
on:
pull_request:
types: [opened, reopened]
issue_comment:
types: [created]
permissions:
contents: write
pull-requests: write
issues: write
concurrency:
group: daily-pr-review-${{ github.event.pull_request.number || github.event.issue.number }}
jobs:
notify:
if: >-
github.event_name == 'pull_request' &&
startsWith(github.event.pull_request.head.ref, 'claude/daily-job-scheduling')
runs-on: ubuntu-latest
steps:
- name: Ask owner for a decision
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
PR: ${{ github.event.pull_request.number }}
OWNER: ${{ github.repository_owner }}
run: |
gh pr comment "$PR" --repo "$REPO" --body "@$OWNER a new daily NEXUS Terminal update is ready for review.
Reply to this email (or comment here) with one of:
- \`approve\` to merge it into \`main\`
- \`reject: <reason>\` to close it; tomorrow's run will read your reason"
review:
if: >-
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
github.event.comment.user.login == github.repository_owner
runs-on: ubuntu-latest
steps:
- name: Parse decision
id: parse
env:
BODY: ${{ github.event.comment.body }}
shell: python
run: |
import os, re, uuid
body = os.environ["BODY"].replace("\r", "")
# Drop quoted email text. Mail apps (esp. on phones) may glue the quote
# header straight onto the reply, e.g. "ApproveOn 29 Sep 2026, at 10:48 AM, ... wrote:".
body = re.split(r"On\s+(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun|\d{1,2})\b.{0,200}?wrote:",
body, maxsplit=1, flags=re.S)[0]
body = "\n".join(l for l in body.split("\n")
if not l.lstrip().startswith(">")).strip()
head = body.lstrip("/*_` ").lower()
decision, reason = "none", ""
if head.startswith("reject"):
decision = "reject"
reason = re.sub(r"^[/*_`\s]*reject(?:ed)?[\s:.,-]*", "", body, flags=re.I).strip()
elif head.startswith(("approve", "lgtm")):
decision = "approve"
with open(os.environ["GITHUB_OUTPUT"], "a") as out:
out.write(f"decision={decision}\n")
eof = f"EOF_{uuid.uuid4().hex}"
out.write(f"reason<<{eof}\n{reason or '(no reason given)'}\n{eof}\n")
print("decision:", decision)
- name: Apply decision
if: steps.parse.outputs.decision != 'none'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
PR: ${{ github.event.issue.number }}
DECISION: ${{ steps.parse.outputs.decision }}
REASON: ${{ steps.parse.outputs.reason }}
run: |
set -euo pipefail
read -r HEAD_REF STATE < <(gh pr view "$PR" --repo "$REPO" \
--json headRefName,state --jq '"\(.headRefName) \(.state)"')
if [[ "$HEAD_REF" != claude/daily-job-scheduling* || "$STATE" != "OPEN" ]]; then
echo "Not an open daily PR; ignoring."
exit 0
fi
if [[ "$DECISION" == approve ]]; then
if gh pr merge "$PR" --repo "$REPO" --merge; then
gh pr comment "$PR" --repo "$REPO" --body "Approved and merged into \`main\`."
else
gh pr comment "$PR" --repo "$REPO" --body "Approval received, but the merge failed (conflict or failing checks). The next daily run will fix it, or merge it by hand."
exit 1
fi
else
gh label create rejected --repo "$REPO" --color B60205 \
--description "Daily PR rejected by owner" --force
gh pr edit "$PR" --repo "$REPO" --add-label rejected
gh pr close "$PR" --repo "$REPO" --comment "Rejected. Reason:
> ${REASON//$'\n'/$'\n'> }
The next daily run will take this into account."
fi