|
| 1 | +# Drop this into a repo at .github/workflows/announce-pr.yml to make it a town-crier producer. |
| 2 | +# |
| 3 | +# Setup (once per repo or org): |
| 4 | +# - Variable TOWN_CRIER_URL = https://<app>.fly.dev |
| 5 | +# - Secret TOWN_CRIER_TOKEN = the bearer token minted for "github-action" |
| 6 | +# |
| 7 | +# Produces BOTH sides of a request's lifecycle, so the bus never drifts from GitHub: |
| 8 | +# - announce: when "Agent Review Requested" lands on a PR, tell the crier once. |
| 9 | +# - resolve: when that PR closes/merges, retire its thread — otherwise a landed PR |
| 10 | +# sits "open" on the bus forever (there is no GitHub->bus merge sync). |
| 11 | +# Joined harnesses pick up open requests from the bus — this workflow does NOT poll or review. |
| 12 | +# |
| 13 | +# Failure policy (two distinct modes, so a real problem is never silently masked): |
| 14 | +# - MISSING provisioning (no TOWN_CRIER_URL/TOKEN) is a config error -> fail LOUD (red). |
| 15 | +# - A bus HICCUP (cold start / transient 5xx / timeout) -> ::warning:: + stay GREEN (fail-open; |
| 16 | +# a coordination-layer blip must never red a contributor's PR checks). |
| 17 | +# Neither job uses the GITHUB_TOKEN (they auth to the bus with TOWN_CRIER_TOKEN), so permissions |
| 18 | +# are dropped to nothing. |
| 19 | +name: town-crier producer (announce + resolve) |
| 20 | + |
| 21 | +permissions: {} |
| 22 | + |
| 23 | +on: |
| 24 | + pull_request: |
| 25 | + types: [labeled, closed] |
| 26 | + |
| 27 | +jobs: |
| 28 | + announce: |
| 29 | + if: github.event.action == 'labeled' && github.event.label.name == 'Agent Review Requested' |
| 30 | + runs-on: ubuntu-latest |
| 31 | + steps: |
| 32 | + - name: Announce to the crier |
| 33 | + env: |
| 34 | + CRIER_URL: ${{ vars.TOWN_CRIER_URL }} |
| 35 | + CRIER_TOKEN: ${{ secrets.TOWN_CRIER_TOKEN }} |
| 36 | + PR_URL: ${{ github.event.pull_request.html_url }} |
| 37 | + REPO: ${{ github.repository }} |
| 38 | + TITLE: ${{ github.event.pull_request.title }} |
| 39 | + REQUESTER: ${{ github.event.pull_request.user.login }} |
| 40 | + run: | |
| 41 | + # Missing provisioning is a config error — fail LOUD so it can't pass silently. |
| 42 | + if [ -z "$CRIER_URL" ] || [ -z "$CRIER_TOKEN" ]; then |
| 43 | + echo "::error::town-crier not provisioned — set the TOWN_CRIER_URL variable + TOWN_CRIER_TOKEN secret" |
| 44 | + exit 1 |
| 45 | + fi |
| 46 | + # jq builds the JSON so a PR title with quotes can't break the payload. |
| 47 | + # A bus hiccup is not the PR's fault — degrade to a warning, keep the check green. |
| 48 | + curl -fsS --max-time 10 -X POST "$CRIER_URL/announce" \ |
| 49 | + -H "Authorization: Bearer $CRIER_TOKEN" \ |
| 50 | + -H "Content-Type: application/json" \ |
| 51 | + -d "$(jq -n \ |
| 52 | + --arg pr "$PR_URL" \ |
| 53 | + --arg repo "$REPO" \ |
| 54 | + --arg title "$TITLE" \ |
| 55 | + --arg requester "$REQUESTER" \ |
| 56 | + '{pr_url:$pr, repo:$repo, title:$title, requester:$requester}')" \ |
| 57 | + || echo "::warning::town-crier announce failed (transient bus issue?) — not blocking the PR" |
| 58 | +
|
| 59 | + resolve: |
| 60 | + if: github.event.action == 'closed' && contains(github.event.pull_request.labels.*.name, 'Agent Review Requested') |
| 61 | + runs-on: ubuntu-latest |
| 62 | + steps: |
| 63 | + - name: Resolve on the crier |
| 64 | + env: |
| 65 | + CRIER_URL: ${{ vars.TOWN_CRIER_URL }} |
| 66 | + CRIER_TOKEN: ${{ secrets.TOWN_CRIER_TOKEN }} |
| 67 | + PR_URL: ${{ github.event.pull_request.html_url }} |
| 68 | + MERGED: ${{ github.event.pull_request.merged }} |
| 69 | + run: | |
| 70 | + if [ -z "$CRIER_URL" ] || [ -z "$CRIER_TOKEN" ]; then |
| 71 | + echo "::error::town-crier not provisioned — set the TOWN_CRIER_URL variable + TOWN_CRIER_TOKEN secret" |
| 72 | + exit 1 |
| 73 | + fi |
| 74 | + NOTE=$([ "$MERGED" = "true" ] && echo "merged" || echo "closed without merge") |
| 75 | + curl -fsS --max-time 10 -X POST "$CRIER_URL/resolve" \ |
| 76 | + -H "Authorization: Bearer $CRIER_TOKEN" \ |
| 77 | + -H "Content-Type: application/json" \ |
| 78 | + -d "$(jq -n --arg pr "$PR_URL" --arg note "$NOTE" '{pr_url:$pr, note:$note}')" \ |
| 79 | + || echo "::warning::town-crier resolve failed (transient bus issue?) — not blocking the PR" |
0 commit comments