Refresh PR Outdated Checks #10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Refresh PR Outdated Checks | |
| # **What it does**: Posts Outdated PR Check commit statuses for every open PR once a day | |
| # (~4am CT), including fork PRs. Catches PRs that go stale when production | |
| # advances without any PR activity. | |
| # **Why we have it**: The per-commit check (outdated-pr-check.yml) only runs when a PR is | |
| # updated. This job handles the case where production moves forward and | |
| # a PR becomes stale without the contributor pushing anything. | |
| # Because this runs once daily, the effective enforcement window is | |
| # 72–96 hours depending on when the PR was last rebased vs. the schedule. | |
| # **Who does it impact**: All contributors with open PRs against production, including forks. | |
| on: | |
| schedule: | |
| - cron: "0 10 * * *" # 4am CST (UTC-6); runs ~5am during CDT (UTC-5) | |
| workflow_dispatch: | |
| jobs: | |
| refresh-outdated: | |
| name: Refresh outdated check for all open PRs | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| # statuses: write is required to post commit statuses to PR head SHAs. | |
| # Fork PR commits are reachable in the base repo via refs/pull/{n}/head, | |
| # so this works for both internal and fork PRs. | |
| statuses: write | |
| steps: | |
| - name: Post outdated status for all open PRs | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| REPO="${{ github.repository }}" | |
| # Get all open PRs targeting production (including forks) | |
| PRS=$(gh pr list \ | |
| --repo "$REPO" \ | |
| --base production \ | |
| --state open \ | |
| --limit 500 \ | |
| --json number,headRefOid) | |
| echo "$PRS" | jq -c '.[]' | while read -r PR; do | |
| PR_NUMBER=$(echo "$PR" | jq -r '.number') | |
| PR_SHA=$(echo "$PR" | jq -r '.headRefOid') | |
| echo "Checking PR #${PR_NUMBER} (${PR_SHA:0:7})" | |
| COMPARE=$(gh api "/repos/${REPO}/compare/production...${PR_SHA}" 2>/dev/null) || { | |
| echo " Skipping PR #${PR_NUMBER}: compare API failed" | |
| continue | |
| } | |
| BEHIND_BY=$(echo "$COMPARE" | jq -r '.behind_by') | |
| if [ "$BEHIND_BY" = "0" ]; then | |
| STATE="success" | |
| DESCRIPTION="Branch is up to date with production" | |
| else | |
| MERGE_BASE_DATE=$(echo "$COMPARE" | jq -r '.merge_base_commit.commit.committer.date') | |
| if [ -z "$MERGE_BASE_DATE" ] || [ "$MERGE_BASE_DATE" = "null" ]; then | |
| echo " Skipping PR #${PR_NUMBER}: missing merge base date" | |
| continue | |
| fi | |
| MERGE_BASE_TS=$(date -d "$MERGE_BASE_DATE" +%s) | |
| NOW=$(date +%s) | |
| AGE=$((NOW - MERGE_BASE_TS)) | |
| if [ "$AGE" -gt 259200 ]; then | |
| DAYS=$((AGE / 86400)) | |
| STATE="failure" | |
| DESCRIPTION="Branch is ${DAYS} days out of date with production. Please rebase or merge. Codeowners can comment /rebase on the PR to fix." | |
| else | |
| STATE="success" | |
| DESCRIPTION="Branch is behind production but within the 72-hour grace period" | |
| fi | |
| fi | |
| gh api \ | |
| --method POST \ | |
| -H "Accept: application/vnd.github+json" \ | |
| "/repos/${REPO}/statuses/${PR_SHA}" \ | |
| -f state="$STATE" \ | |
| -f context="Outdated PR Check" \ | |
| -f description="$DESCRIPTION" \ | |
| || { echo " Failed to post status for PR #${PR_NUMBER} — continuing"; true; } | |
| echo " Posted: $STATE — $DESCRIPTION" | |
| done |