Repository navigation
feat: add Paper default human avatars (#2086) #3026
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: ADR Numbering Guard | |
| # An ADR number is a name two documents can claim at once, and every mechanical | |
| # check we own is blind to it. #1295 and #1268 both added | |
| # `docs/adr/ADR-025-*.md` under different slugs: different filenames, so no | |
| # textual conflict, `merge-tree` clean, all checks green — and main carried two | |
| # ADR-025s from the moment the second merged. It had already happened at | |
| # ADR-018, where the duplicate lived long enough that #963's author followed | |
| # the wrong one and shipped a wake-policy regression. | |
| # | |
| # Both were found by a human reading a directory listing. This makes the third | |
| # one go red. | |
| on: | |
| # The PR arms below cannot fire on base movement, and a PR's green is frozen | |
| # at its last event. So a pair that were each green when last run can still | |
| # merge into a duplicate. This arm cannot prevent that — nothing triggered by | |
| # PR events can — but it makes main say so within a minute instead of waiting | |
| # for someone to read a directory listing, which is how both known duplicates | |
| # were actually found. | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| branches: [ main ] | |
| # `edited` catches base-branch retargeting, same reasoning as | |
| # package-version-guard.yml: a stacked PR retargeted to main after its | |
| # parent merges otherwise enters this population with no event firing. | |
| types: [opened, synchronize, reopened, ready_for_review, edited] | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| concurrency: | |
| # github.ref, not the PR number: on a push event there is no PR to key on and | |
| # every main build would share one group and cancel its predecessor. | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # Detection, not prevention. If a duplicate reaches main, this reds main — | |
| # which is loud, and deliberately so: a duplicated ADR number silently | |
| # mis-routes every citation of it, and #963 shipped a wake-policy regression | |
| # because an author followed the wrong member of the ADR-018 pair. | |
| adr-numbering-main: | |
| name: main carries no duplicate ADR number | |
| if: github.event_name == 'push' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - run: node scripts/verify-adr-numbering.js | |
| adr-numbering: | |
| name: ADR numbers are unique | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| # The PR HEAD, not the merge ref. `refs/pull/N/merge` is recomputed | |
| # lazily and can be badly stale: #1295's merge ref still contained the | |
| # duplicate ADR-018 an hour after #1463 renumbered it away on main. A | |
| # guard reading that tree fails the PR for a collision somebody else | |
| # already fixed — worse than not running, because it teaches authors | |
| # that this check is noise. We assemble the post-merge state below | |
| # instead, from main as it is right now. | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| fetch-depth: 0 | |
| - name: No two ADRs claim the same number | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| # No --depth: a shallow base makes the fork point unreachable and | |
| # every comparison below meaningless. Same trap as | |
| # package-version-guard.yml (#1113), and no `|| true` for the same | |
| # reason — a base we cannot fetch must stop the guard, not pass it. | |
| git fetch --no-tags origin main | |
| if ! base=$(git merge-base FETCH_HEAD HEAD); then | |
| echo "::error::No merge base between origin/main and this PR head. Not passing on a baseline this guard cannot see." | |
| exit 1 | |
| fi | |
| # Effective tree = main's ADRs right now, with this PR's own ADR | |
| # additions, edits and deletions applied on top. That is what main | |
| # will hold after the merge, and unlike the merge ref it is fresh as | |
| # of this run. | |
| eff=$(mktemp -d) | |
| mkdir -p "$eff/docs/adr" | |
| git archive FETCH_HEAD docs/adr | tar -x -C "$eff" | |
| # --no-renames so a rename shows up as delete + add; rename detection | |
| # would hide exactly the "renumbered but the H1 still says the old | |
| # number" case this guard checks for. | |
| git diff --no-renames --name-status "$base" HEAD -- docs/adr \ | |
| | while IFS=$'\t' read -r status file; do | |
| case "$status" in | |
| D) rm -f "$eff/$file" ;; | |
| *) mkdir -p "$eff/$(dirname "$file")" | |
| git show "HEAD:$file" > "$eff/$file" ;; | |
| esac | |
| done | |
| # The checker itself has to be resolved the same way as the ADRs, and | |
| # for the same reason. On a `pull_request` event GitHub takes the | |
| # WORKFLOW from the merge ref but this job checks out the PR HEAD — | |
| # so every PR branched before this guard landed has the workflow file | |
| # and not the script, and `node scripts/...` died with | |
| # MODULE_NOT_FOUND. That reds the PR with no ADR output at all, which | |
| # reads as a broken guard rather than a real collision (#1504). | |
| # Effective content: the PR's version if it changed the script, | |
| # otherwise main's. | |
| bin=$(mktemp -d) | |
| if git cat-file -e "HEAD:scripts/verify-adr-numbering.js" 2>/dev/null; then | |
| git show "HEAD:scripts/verify-adr-numbering.js" > "$bin/verify-adr-numbering.js" | |
| else | |
| git show "FETCH_HEAD:scripts/verify-adr-numbering.js" > "$bin/verify-adr-numbering.js" | |
| fi | |
| node "$bin/verify-adr-numbering.js" --dir "$eff/docs/adr" | |
| # The check above cannot see a collision between two PRs that are both | |
| # still open — neither tree contains the other's file. That is the state | |
| # #1295 and #1268 were in for days, and the state a human happened to | |
| # catch. Deterministic tiebreak so it is unilaterally fixable: the older | |
| # PR keeps the number, the newer renumbers. Both PRs going red would be a | |
| # deadlock neither author could clear alone. | |
| - name: No OPEN PR is already claiming these numbers | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| PR: ${{ github.event.pull_request.number }} | |
| REPO: ${{ github.repository }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| # Every gh call is checked. A silent API failure here would yield an | |
| # empty ADR list, which reads as "this PR claims nothing" and PASSES | |
| # — the guard would be at its most reassuring exactly when it had | |
| # gone blind. | |
| added_adrs() { | |
| local raw | |
| if ! raw=$(gh api "repos/$REPO/pulls/$1/files" --paginate \ | |
| --jq '.[] | select(.status == "added") | .filename'); then | |
| echo "::error::gh api failed reading PR #$1. This guard cannot see the open-PR set; it will not pass on a check it could not run." >&2 | |
| return 1 | |
| fi | |
| printf '%s\n' "$raw" | sed -n 's#^docs/adr/ADR-\([0-9]\{3\}\)-.*\.md$#\1#p' | sort -u | |
| } | |
| mine=$(added_adrs "$PR") | |
| if [ -z "$mine" ]; then | |
| echo "· this PR adds no new ADR file" | |
| exit 0 | |
| fi | |
| echo "this PR claims: $(echo "$mine" | tr '\n' ' ')" | |
| # Older = lower PR number. Only an older PR can outrank this one. | |
| if ! older=$(gh api "repos/$REPO/pulls?state=open&per_page=100" --paginate \ | |
| --jq ".[] | select(.number < $PR) | .number"); then | |
| echo "::error::gh api failed listing open PRs. Not passing on a blind check." | |
| exit 1 | |
| fi | |
| fail=0 | |
| for other in $older; do | |
| theirs=$(added_adrs "$other") | |
| [ -z "$theirs" ] && continue | |
| clash=$(comm -12 <(printf '%s\n' "$mine") <(printf '%s\n' "$theirs")) || true | |
| [ -z "$clash" ] && continue | |
| for n in $clash; do | |
| echo "::error file=docs/adr::ADR-$n is already claimed by the older open PR #$other. Two open PRs adding the same number both merge green and leave main with a duplicate — this is how main got two ADR-025s. #$other keeps $n; renumber here." | |
| done | |
| fail=1 | |
| done | |
| if [ "$fail" = "0" ]; then | |
| echo "✓ no open PR claims these numbers" | |
| fi | |
| exit $fail |