mirror of
https://github.com/Mihirkansara/nexus-quant-terminal.git
synced 2026-11-02 09:36:11 +00:00
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
113 lines
4.3 KiB
YAML
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
|