Skip to content

Commit 907b812

Browse files
committed
ci: Add auto-approve workflow for owner PRs without review
Adds a daily scheduled workflow (08:00 UTC, also manual trigger) that auto-approves open PRs from repo OWNER/MEMBER after 3 days without review. Countdown labels give reviewers clear visibility: Day 0 -> merge-in-3-days-without-review Day 1 -> merge-in-2-days-without-review Day 2 -> merge-in-1-day-without-review Day 3 -> approved + merged-without-review (auto-merge takes over) PRs that already have an approving review are skipped.
1 parent 4648f8e commit 907b812

1 file changed

Lines changed: 115 additions & 0 deletions

File tree

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Auto-approve owner PRs that receive no review within 3 days.
2+
#
3+
# Countdown labels give reviewers clear visibility:
4+
# Day 0 → merge-in-3-days-without-review
5+
# Day 1 → merge-in-2-days-without-review
6+
# Day 2 → merge-in-1-day-without-review
7+
# Day 3 → approved + merged-without-review (auto-merge takes over)
8+
#
9+
# Only PRs authored by a repo OWNER or MEMBER are processed.
10+
# PRs that already have at least one approval are skipped.
11+
name: Auto-approve owner PRs
12+
13+
on:
14+
schedule:
15+
- cron: "0 8 * * *" # daily at 08:00 UTC
16+
workflow_dispatch: # allow manual trigger
17+
18+
permissions:
19+
contents: write
20+
pull-requests: write
21+
22+
jobs:
23+
countdown:
24+
runs-on: ubuntu-latest
25+
steps:
26+
# ── 1. Ensure countdown labels exist ──────────────────────────
27+
- name: Create countdown labels (idempotent)
28+
env:
29+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30+
run: |
31+
declare -A LABELS=(
32+
["merge-in-3-days-without-review"]="c2e0c6"
33+
["merge-in-2-days-without-review"]="fbca04"
34+
["merge-in-1-day-without-review"]="e99695"
35+
["merged-without-review"]="d93f0b"
36+
)
37+
for label in "${!LABELS[@]}"; do
38+
gh label create "$label" \
39+
--color "${LABELS[$label]}" \
40+
--description "Auto-approve countdown" \
41+
--force 2>/dev/null || true
42+
done
43+
44+
# ── 2. Process open PRs by owner/member ───────────────────────
45+
- name: Run countdown on stale owner PRs
46+
env:
47+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
48+
REPO: ${{ github.repository }}
49+
run: |
50+
COUNTDOWN_LABELS=(
51+
"merge-in-3-days-without-review"
52+
"merge-in-2-days-without-review"
53+
"merge-in-1-day-without-review"
54+
"merged-without-review"
55+
)
56+
57+
remove_countdown_labels() {
58+
local pr=$1
59+
for lbl in "${COUNTDOWN_LABELS[@]}"; do
60+
gh pr edit "$pr" --remove-label "$lbl" 2>/dev/null || true
61+
done
62+
}
63+
64+
# Fetch open PRs authored by OWNER or MEMBER
65+
prs=$(gh api "repos/${REPO}/pulls?state=open&per_page=100" \
66+
--jq '.[] | select(.author_association == "OWNER" or .author_association == "MEMBER" or .draft == false) | select(.draft == false) | {number: .number, created_at: .created_at, user: .user.login, author_association: .author_association}')
67+
68+
# Filter to only OWNER/MEMBER (the jq above might pass non-owner non-draft)
69+
prs=$(echo "$prs" | jq -s '[.[] | select(.author_association == "OWNER" or .author_association == "MEMBER")]' | jq -c '.[]')
70+
71+
if [ -z "$prs" ]; then
72+
echo "No open PRs by owner/member found."
73+
exit 0
74+
fi
75+
76+
echo "$prs" | while IFS= read -r pr; do
77+
PR_NUMBER=$(echo "$pr" | jq -r '.number')
78+
CREATED_AT=$(echo "$pr" | jq -r '.created_at')
79+
AUTHOR=$(echo "$pr" | jq -r '.user')
80+
ASSOC=$(echo "$pr" | jq -r '.author_association')
81+
82+
# Skip if PR already has an approving review
83+
APPROVALS=$(gh api "repos/${REPO}/pulls/${PR_NUMBER}/reviews" \
84+
--jq '[.[] | select(.state == "APPROVED")] | length')
85+
if [ "$APPROVALS" -gt 0 ]; then
86+
echo "PR #${PR_NUMBER} already approved — skipping"
87+
continue
88+
fi
89+
90+
# Calculate age in whole days
91+
CREATED_TS=$(date -d "$CREATED_AT" +%s)
92+
NOW_TS=$(date +%s)
93+
AGE_DAYS=$(( (NOW_TS - CREATED_TS) / 86400 ))
94+
95+
echo "PR #${PR_NUMBER} by ${AUTHOR} (${ASSOC}) — ${AGE_DAYS} day(s) old"
96+
97+
remove_countdown_labels "$PR_NUMBER"
98+
99+
if [ "$AGE_DAYS" -ge 3 ]; then
100+
echo " → Auto-approving PR #${PR_NUMBER}"
101+
gh pr edit "$PR_NUMBER" --add-label "merged-without-review"
102+
gh pr review "$PR_NUMBER" --approve \
103+
--body "Auto-approved: no review received within 3 days of opening."
104+
gh pr merge --auto --squash "$PR_NUMBER" || true
105+
elif [ "$AGE_DAYS" -ge 2 ]; then
106+
echo " → Label: merge-in-1-day-without-review"
107+
gh pr edit "$PR_NUMBER" --add-label "merge-in-1-day-without-review"
108+
elif [ "$AGE_DAYS" -ge 1 ]; then
109+
echo " → Label: merge-in-2-days-without-review"
110+
gh pr edit "$PR_NUMBER" --add-label "merge-in-2-days-without-review"
111+
else
112+
echo " → Label: merge-in-3-days-without-review"
113+
gh pr edit "$PR_NUMBER" --add-label "merge-in-3-days-without-review"
114+
fi
115+
done

0 commit comments

Comments
 (0)