fix: address Phase 2 review findings from #1819 #488
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: PR Body Check | |
| on: | |
| pull_request: | |
| # `synchronize` is REQUIRED: the golden-fixture gate below is diff-dependent | |
| # (it inspects the PR's changed files). Without `synchronize` the workflow | |
| # would not re-run when a load-bearing fixture is pushed AFTER the PR opens, | |
| # leaving a stale green — the exact wrong-trigger trap the enforcer-wiring | |
| # gate (task 011) fences. The `synchronize` addition is likewise asserted by | |
| # that gate for check-golden-fixture-note (diffDependent: true). | |
| types: [opened, edited, synchronize, ready_for_review, reopened] | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| jobs: | |
| validate-pr-body: | |
| if: | | |
| (github.event.pull_request.head.repo.full_name == github.repository || github.event_name != 'pull_request') && | |
| github.event.pull_request.user.login != 'renovate[bot]' && | |
| github.event.pull_request.user.login != 'dependabot[bot]' && | |
| !startsWith(github.event.pull_request.title, '[Graphite MQ]') | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup GitHub CLI | |
| env: | |
| GH_VERSION: '2.65.0' | |
| run: | | |
| if ! command -v gh &>/dev/null; then | |
| curl -fsSL "https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_amd64.tar.gz" \ | |
| | tar xz -C /tmp | |
| echo "/tmp/gh_${GH_VERSION}_linux_amd64/bin" >> "$GITHUB_PATH" | |
| fi | |
| - name: Validate PR body | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| PR="${{ github.event.pull_request.number }}" | |
| BODY="$(gh pr view "$PR" --json body -q .body)" | |
| # Determine required sections from template or defaults | |
| if [[ -f ".exarchos/pr-template.md" ]]; then | |
| SECTIONS=() | |
| while IFS= read -r line; do | |
| if [[ "$line" =~ ^##[[:space:]]+(.+)$ ]]; then | |
| trimmed="${BASH_REMATCH[1]}" | |
| trimmed="${trimmed%"${trimmed##*[![:space:]]}"}" | |
| SECTIONS+=("$trimmed") | |
| fi | |
| done < .exarchos/pr-template.md | |
| else | |
| SECTIONS=("Summary" "Changes" "Test Plan") | |
| fi | |
| # Safeguard: if template exists but yielded no sections, fall back to defaults | |
| if [[ ${#SECTIONS[@]} -eq 0 ]]; then | |
| echo "Warning: .exarchos/pr-template.md has no ## headings, using defaults" | |
| SECTIONS=("Summary" "Changes" "Test Plan") | |
| fi | |
| # Escape regex metacharacters in section names | |
| escape_ere() { printf '%s' "$1" | sed 's/[.[*^$()+?{|\\]/\\&/g'; } | |
| MISSING=() | |
| for section in "${SECTIONS[@]}"; do | |
| escaped="$(escape_ere "$section")" | |
| if ! printf '%s\n' "$BODY" | grep -qiE "^##[[:space:]]+${escaped}[[:space:]]*$"; then | |
| MISSING+=("$section") | |
| fi | |
| done | |
| if [[ ${#MISSING[@]} -gt 0 ]]; then | |
| echo "PR body validation failed." | |
| for s in "${MISSING[@]}"; do | |
| echo " Missing: ## $s" | |
| done | |
| echo "" | |
| echo "Required sections: ${SECTIONS[*]}" | |
| exit 1 | |
| fi | |
| echo "PR body validation passed." | |
| # Golden-fixture PR-body marker (DR-15, task 011). Diff-dependent gate: | |
| # if this PR changes a file under | |
| # tests/core/fixtures/load-bearing/**, the PR body MUST | |
| # carry a `GOLDEN-FIXTURE-UPDATE: <reason>` line. Hosted here (not in the | |
| # path-filtered ci.yml jobs) because it needs the PR body; the | |
| # `synchronize` trigger above is what lets it re-run when a fixture is | |
| # pushed after the PR opens. Zero-dependency node script — no install. | |
| - name: Golden-fixture marker check (DR-15) | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| PR="${{ github.event.pull_request.number }}" | |
| gh pr view "$PR" --json body -q .body > "$RUNNER_TEMP/pr-body.txt" | |
| # Use the paginated "list PR files" API, not `gh pr diff` — the .diff | |
| # endpoint caps at 300 files and 406s on large PRs (e.g. the debloat | |
| # wave itself), which would fail this gate closed on scale. The files | |
| # API paginates (100/page) and returns the same newline-separated list. | |
| gh api --paginate "repos/${{ github.repository }}/pulls/$PR/files" \ | |
| --jq '.[].filename' > "$RUNNER_TEMP/pr-changed.txt" | |
| node tools/audit/gates/check-golden-fixture-note.mjs \ | |
| --body-file "$RUNNER_TEMP/pr-body.txt" \ | |
| --changed-files-file "$RUNNER_TEMP/pr-changed.txt" |