fix(release): let the recovery dispatch resolve actions and finish the release (#386)
fix(release): let the recovery dispatch resolve actions and finish the release
Two defects in the same path, both found by actually running it. The macOS
rebuild of v0.26.0 failed before it signed anything:
Can't find 'action.yml', 'action.yaml' or 'Dockerfile' under
'.../.github/actions/macos-signing-setup'.
Did you forget to run actions/checkout before running your local action?
## 1. The self-healing design did not cover its own actions
Step 1 checks out the *tag's* source on purpose, so an old tag can be
rebuilt by a fixed workflow. But `uses: ./...` resolves against the
workspace, not against the ref the workflow was loaded from. Dispatching
main's release.yml at v0.26.0 therefore ran a workflow that calls
`macos-signing-setup` against a tree from before that action existed.
`.github/actions` is now checked out separately from `github.sha`, which is
the ref that supplied release.yml under both triggers, into
`.workflow-actions/`. Both local actions resolve from there, so the workflow
and the actions it calls can no longer drift apart. `setup-protoc` moves too:
it happens to exist in v0.26.0, so it worked by luck, and leaving it on the
old path would leave the same trap set for the next action added.
## 2. A dispatched release could never stop being a pre-release
`promote-release` ran only for `release` events. The recovery path this
workflow documents in its own header ends at "artifacts uploaded", so a
release rescued by dispatch stays a pre-release forever.
That also stalls Homebrew silently. `update_homebrew_formula.yml` resolves
the version through `repos/{}/releases/latest`, which excludes pre-releases,
so it fires on the successful run and then updates the tap to the *previous*
version. Nothing fails; the formula simply never advances.
Promotion now also runs for a dispatch that names a `release_tag`, resolves
the tag from whichever trigger supplied it, and exits cleanly when the tag is
already a full release, since re-running a dispatch is a normal thing to do
while recovering.
## The guard that makes that safe
A dispatch can build one family. Promoting on the strength of that alone
would publish a release missing every target the run never touched, and
Homebrew would then resolve a version whose artifacts are not all there.
So `setup` now also emits the asset list from the UNFILTERED matrix, and
promotion refuses unless every one of those is present on the tag, naming
what is missing. The check is against the whole expected set, not against
what this particular run produced.
## Verification
`actionlint` reports nothing new; the single SC2086 it flags is pre-existing
on `main`. The behaviour itself is only observable on a real dispatch, which
is what found these two in the first place, so the next run against v0.26.0
is the proof.
Refs the failed recovery run 32686049629 J
Jeongkyu Shin committed
56e98ba6c2dd57adb7413ba6c4c62459831bb2be
Parent: 31ed8e4
Committed by GitHub <noreply@github.com>
on 8/24/2026, 3:40:32 AM