Skip to content

Commit 45dbc2d

Browse files
ci(town-crier): producer workflow (announce + resolve on close) (#36)
* ci(town-crier): producer workflow (announce + resolve on close) * ci(town-crier): least-privilege permissions + fail-open producer (review feedback) * ci(town-crier): config-error fails loud, bus-hiccup fails open (review feedback)
1 parent d476223 commit 45dbc2d

1 file changed

Lines changed: 79 additions & 0 deletions

File tree

.github/workflows/announce-pr.yml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
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

Comments
 (0)