Skip to content

Commit b835d2f

Browse files
author
t
committed
ci: dispatch pr-checks on the release branch so GITHUB_TOKEN pushes still get validated
1 parent 42f1d8f commit b835d2f

2 files changed

Lines changed: 84 additions & 5 deletions

File tree

‎.github/workflows/pr-checks.yml‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ on:
66
# result before it lands. Guards against semantic merge races where two
77
# individually-green PRs break main in combination (#113 + #145 → #229).
88
merge_group:
9+
# Release-branch heads are created and pushed by GITHUB_TOKEN (release-please
10+
# and the lock-sync job), and GitHub's recursion guard means those pushes
11+
# trigger no workflow runs. workflow_dispatch is the documented carve-out that
12+
# GITHUB_TOKEN CAN trigger, so the release flow dispatches this workflow at
13+
# the release branch to attach check runs to its head. Read-only workflow
14+
# (contents: read), so the dispatch surface adds no privilege.
15+
workflow_dispatch:
916
push:
1017
branches:
1118
- main

‎.github/workflows/release.yml‎

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,26 +53,64 @@ jobs:
5353
# release-please cannot update Cargo.lock, so without this job every release
5454
# merge ships a tag whose lockfile disagrees with its manifests (a --locked
5555
# build from the tag fails, and pr-checks builds --locked). Sync the lock on
56-
# the release branch so the tagged tree is internally consistent. Runs only
57-
# while a release PR is open (the pr output is unset on the merge push that
58-
# creates the release).
56+
# the release branch so the tagged tree is internally consistent.
57+
#
58+
# Runs on every push-triggered release run, not only when release-please
59+
# reports the PR: the `pr` output is set only on runs that CREATE or UPDATE
60+
# the release PR, so gating on it would leave an already-open release PR
61+
# (opened before this job existed, or untouched by a non-releasable push)
62+
# permanently without the sync and without check runs. The resolve step
63+
# discovers any open release-please PR itself and no-ops when there is none.
5964
sync-release-lock:
6065
name: Sync Cargo.lock on the release PR
6166
needs: release-please
62-
if: ${{ needs.release-please.outputs.pr }}
67+
if: ${{ !cancelled() && github.repository == 'Gitlawb/node' && github.event_name != 'workflow_dispatch' }}
6368
runs-on: ubuntu-latest
6469
permissions:
6570
contents: write
71+
pull-requests: read
72+
# actions: write lets the final step dispatch pr-checks on the release
73+
# branch. Note this grant is repo-wide dispatch rights (GitHub cannot
74+
# scope it to one workflow); acceptable here because reaching this job's
75+
# steps already requires write to main. Needed because every push to the
76+
# release branch (release-please's and the lock sync below) is made with
77+
# GITHUB_TOKEN, which triggers no workflow runs, so without an explicit
78+
# dispatch the release PR's head carries no check runs and the --locked
79+
# gate never validates it.
80+
actions: write
6681
steps:
82+
# Prefer the fresh `pr` output when this run just created/updated the
83+
# release PR; otherwise fall back to querying for an open release-please
84+
# branch (prefix match: the branch carries `--components--` suffixes).
85+
- name: Resolve the open release PR branch
86+
id: resolve
87+
env:
88+
GH_TOKEN: ${{ github.token }}
89+
BRANCH_FROM_OUTPUT: ${{ needs.release-please.outputs.pr && fromJSON(needs.release-please.outputs.pr).headBranchName || '' }}
90+
run: |
91+
branch="$BRANCH_FROM_OUTPUT"
92+
if [ -z "$branch" ]; then
93+
branch=$(gh pr list --repo "$GITHUB_REPOSITORY" --state open \
94+
--json headRefName \
95+
--jq '[.[].headRefName | select(startswith("release-please--"))][0] // empty')
96+
fi
97+
if [ -z "$branch" ]; then
98+
echo "no open release PR; nothing to sync"
99+
fi
100+
echo "branch=$branch" >> "$GITHUB_OUTPUT"
101+
67102
- name: Checkout release branch
103+
if: ${{ steps.resolve.outputs.branch != '' }}
68104
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
69105
with:
70-
ref: ${{ fromJSON(needs.release-please.outputs.pr).headBranchName }}
106+
ref: ${{ steps.resolve.outputs.branch }}
71107

72108
- name: Sync workspace crate versions into Cargo.lock
109+
if: ${{ steps.resolve.outputs.branch != '' }}
73110
run: cargo update --workspace
74111

75112
- name: Commit and push when the lock changed
113+
if: ${{ steps.resolve.outputs.branch != '' }}
76114
run: |
77115
if git diff --quiet Cargo.lock; then
78116
echo "Cargo.lock already in sync"
@@ -84,6 +122,40 @@ jobs:
84122
git commit -m "chore: sync Cargo.lock with the release version bump"
85123
git push
86124
125+
# Every push to the release branch is made with GITHUB_TOKEN (release-
126+
# please's own pushes and the lock sync above), and events created by
127+
# GITHUB_TOKEN start no workflow runs. workflow_dispatch is the documented
128+
# exception GITHUB_TOKEN may trigger, so dispatch pr-checks at the release
129+
# branch to attach check runs to its current head. Unconditional (also on
130+
# the already-in-sync path) because the branch's ORIGINAL head has the
131+
# same no-runs problem. Loud on failure by design: a silent fallback
132+
# would recreate the checkless-head problem, and a job rerun is safe
133+
# (sync no-ops, dispatch retries). Loop-safe: pr-checks is read-only and
134+
# dispatches nothing. Runs after the push ack, so the dispatched ref tip
135+
# is the sync commit. Merge-queue note: this validates the branch tip;
136+
# the enforced merge queue's merge_group run still re-validates the true
137+
# merged result before landing.
138+
- name: Dispatch PR checks on the release branch
139+
if: ${{ steps.resolve.outputs.branch != '' }}
140+
env:
141+
GH_TOKEN: ${{ github.token }}
142+
BRANCH: ${{ steps.resolve.outputs.branch }}
143+
run: |
144+
# A release branch cut before pr-checks gained its workflow_dispatch
145+
# trigger 422s ("does not have a workflow_dispatch trigger" reported
146+
# against the dispatched ref's copy of the file). That is the one
147+
# tolerated failure: it self-heals when release-please next rewrites
148+
# the branch from current main. Anything else fails the job loudly.
149+
out=$(gh api "repos/${GITHUB_REPOSITORY}/actions/workflows/pr-checks.yml/dispatches" \
150+
-f "ref=$BRANCH" 2>&1) && exit 0
151+
if echo "$out" | grep -qi "does not have a workflow_dispatch trigger"; then
152+
echo "release branch predates the dispatch trigger; checks attach after release-please next rebases it"
153+
echo "$out"
154+
exit 0
155+
fi
156+
echo "$out"
157+
exit 1
158+
87159
# Each architecture builds NATIVELY (amd64 on ubuntu-latest, arm64 on
88160
# ubuntu-24.04-arm) and pushes by digest; docker-manifest below stitches the
89161
# digests into the tagged multi-arch image. No QEMU: emulating the arm64

0 commit comments

Comments
 (0)