Skip to content

Commit a50f9cd

Browse files
feat(release): start a release by hand, not only by pushing a tag
Pushing a vX.Y.Z tag was the only way in, which left no way to re-run a release whose tag had already published before the job died — the second push is a no-op, so the only recourse was deleting and moving a tag people may already have. Add workflow_dispatch with a tag input. It is the same job under the same gates: check-version.sh --tag still fails the run when the tag disagrees with version.go, the Makefile or the Formula, so the bump must be committed either way. The one thing a manual run must not get wrong is which commit it builds. A dispatch starts on the branch chosen in the UI, so when the tag already exists the job checks that tag out and builds from it — otherwise it would publish today's main under a tag naming an older commit. A tag that does not exist yet is created on the selected branch. The input is validated against the vX.Y.Z shape before it reaches git and is passed by env rather than interpolated into the script.
1 parent 6865624 commit a50f9cd

2 files changed

Lines changed: 77 additions & 2 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,23 @@ on:
44
push:
55
tags:
66
- "v*"
7+
# The same release, started by hand from the Actions tab. Pushing a tag stays
8+
# the normal path (RELEASE.md step 2); this is for the two cases where there is
9+
# no push to react to: re-running a release whose tag is already published but
10+
# whose job failed partway, and cutting one from the UI without a local
11+
# checkout. It changes nothing about what a release IS — the version still has
12+
# to be committed, because check-version.sh below fails the run when the tag
13+
# disagrees with version.go, the Makefile or the Formula.
14+
workflow_dispatch:
15+
inputs:
16+
tag:
17+
description: >-
18+
Release tag, e.g. v0.25.0. The bump must already be committed
19+
(scripts/prepare-release.sh writes version.go, the Makefile and the
20+
Formula). If this tag already exists the release is rebuilt from it;
21+
if not, it is created on the branch selected above.
22+
required: true
23+
type: string
724

825
permissions:
926
contents: write
@@ -27,6 +44,33 @@ jobs:
2744
with:
2845
fetch-depth: 0
2946

47+
# A manual run starts on the BRANCH picked in the Actions tab, not on a
48+
# tag. When the tag already exists — re-running a release that published
49+
# its tag and then failed — build from that tag: otherwise this job would
50+
# publish whatever main happens to be now under a tag pointing at an older
51+
# commit, and the assets would not be the release they claim to be. When
52+
# the tag is new, stay on the selected ref; the Create GitHub Release step
53+
# creates the tag here. fetch-depth: 0 above is what makes the tag local.
54+
- name: Resolve the release tag (manual runs)
55+
if: github.event_name == 'workflow_dispatch'
56+
env:
57+
TAG: ${{ inputs.tag }}
58+
run: |
59+
set -euo pipefail
60+
# Validated before it reaches git, and passed by env rather than
61+
# interpolated into this script.
62+
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
63+
echo "::error::'${TAG}' is not a vX.Y.Z release tag (expected e.g. v0.25.0)"
64+
exit 1
65+
fi
66+
if git rev-parse -q --verify "refs/tags/${TAG}^{commit}" >/dev/null; then
67+
echo "tag ${TAG} already exists — building from it, not from ${GITHUB_REF_NAME}"
68+
git checkout --detach "refs/tags/${TAG}"
69+
else
70+
echo "tag ${TAG} is new — it will be created on ${GITHUB_REF_NAME} at this commit"
71+
fi
72+
git log -1 --format='building %h %s'
73+
3074
- name: Set up Go
3175
uses: actions/setup-go@v7
3276
with:
@@ -42,9 +86,19 @@ jobs:
4286

4387
- name: Extract version
4488
id: ver
89+
env:
90+
# Empty on a tag push, the dispatch input on a manual run. By env, not
91+
# interpolated into the script body.
92+
DISPATCH_TAG: ${{ inputs.tag }}
4593
run: |
4694
set -euo pipefail
47-
TAG="${GITHUB_REF_NAME}"
95+
# On a manual run GITHUB_REF_NAME is the branch that was selected, so
96+
# the tag has to come from the input instead.
97+
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
98+
TAG="${DISPATCH_TAG}"
99+
else
100+
TAG="${GITHUB_REF_NAME}"
101+
fi
48102
VERSION="${TAG#v}"
49103
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
50104
echo "::error::tag ${TAG} is not a vX.Y.Z release tag" >&2

‎RELEASE.md‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,24 @@ git push origin v0.20.0 # this is what starts the release
101101
Pushing the tag is the point of no return for the automation. Everything before it is
102102
reversible with `git tag -d` and `git reset`.
103103

104+
### Starting it by hand instead
105+
106+
The same workflow can be started from **Actions → Release → Run workflow**, which asks for
107+
the tag (`v0.20.0`) and the branch to run from. Use it when there is no push for the
108+
automation to react to:
109+
110+
- **Re-running a release that failed partway.** The tag is already published, so
111+
`git push origin v0.20.0` does nothing a second time. A manual run notices the tag
112+
already exists and builds **from that tag**, not from whatever `main` has become since —
113+
so the assets still match the commit the tag names. (If you need to move the tag itself,
114+
that is the rollback in step 6, not this.)
115+
- **Cutting a release without a local checkout.**
116+
117+
It is the same job with the same gates: the bump must already be committed, because
118+
`check-version.sh --tag` still fails the run when the tag disagrees with `version.go`, the
119+
Makefile or the Formula. A tag that does not exist yet is created on the branch you
120+
selected.
121+
104122
---
105123

106124
## 3. What CI does (watch it, do not skip ahead)
@@ -233,7 +251,10 @@ git tag -d v0.20.0
233251
git reset --hard origin/main
234252
```
235253

236-
**After the tag is pushed but CI failed** — no release exists, so just fix and re-tag:
254+
**After the tag is pushed but CI failed** — no release exists. If the tree is fine and the
255+
run died on something transient (a registry timeout, a runner hiccup), just start it again
256+
from **Actions → Release → Run workflow** with the same tag; it rebuilds from that tag.
257+
If the tree itself is at fault, fix and re-tag:
237258

238259
```bash
239260
git push --delete origin v0.20.0

0 commit comments

Comments
 (0)