Skip to content

Commit d47446f

Browse files
committed
ci(release): switch to tag-triggered publish with version guard
Trigger publish on v* tag pushes instead of GitHub Releases so the version bump and the release are the same action (npm version). Verify the tag matches package.json before publishing, and create the GitHub Release from the workflow. Document the flow in the README.
1 parent 0115684 commit d47446f

2 files changed

Lines changed: 70 additions & 3 deletions

File tree

.github/workflows/publish.yml

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
name: Publish to npm
22

33
on:
4-
release:
5-
types: [published]
4+
push:
5+
tags: ['v*']
66

77
jobs:
88
publish:
99
runs-on: ubuntu-latest
1010
permissions:
11-
contents: read
11+
contents: write
1212
id-token: write
1313
steps:
1414
- uses: actions/checkout@v4
@@ -19,8 +19,22 @@ jobs:
1919
registry-url: https://registry.npmjs.org
2020
cache: npm
2121

22+
- name: Verify tag matches package.json version
23+
run: |
24+
TAG_VERSION="${GITHUB_REF_NAME#v}"
25+
PKG_VERSION="$(node -p "require('./package.json').version")"
26+
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
27+
echo "Tag $GITHUB_REF_NAME does not match package.json version $PKG_VERSION" >&2
28+
exit 1
29+
fi
30+
2231
- run: npm ci
2332
- run: npm run build
2433
- run: npm publish --access public --provenance
2534
env:
2635
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
36+
37+
- name: Create GitHub Release
38+
env:
39+
GH_TOKEN: ${{ github.token }}
40+
run: gh release create "$GITHUB_REF_NAME" --generate-notes

README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,56 @@ npm install
111111
npm run build
112112
npm run verify
113113
```
114+
115+
## Releasing
116+
117+
Releases are cut from `main` and published to npm by a GitHub Actions workflow
118+
(`.github/workflows/publish.yml`) that triggers on any pushed tag matching
119+
`v*`. The tag and the version bump are produced by the same `npm version`
120+
command, so it's not possible to tag a release without also bumping
121+
`package.json`.
122+
123+
**Prerequisites (one-time):**
124+
125+
* Repo secret `NPM_TOKEN` set to an npm automation token with publish access
126+
to the `@joinflux` scope.
127+
* Local `main` clean and up to date with `origin/main`.
128+
129+
**To release:**
130+
131+
```bash
132+
# pick the bump that fits the change
133+
npm version patch # 0.1.0 → 0.1.1 — bug fixes, docs
134+
npm version minor # 0.1.0 → 0.2.0 — new API, additive
135+
npm version major # 0.1.0 → 1.0.0 — breaking change
136+
137+
git push --follow-tags
138+
```
139+
140+
`npm version` bumps `package.json` and `package-lock.json`, commits the change
141+
with the version as the message, and creates a matching `vX.Y.Z` tag.
142+
`git push --follow-tags` pushes the commit and the tag in one step.
143+
144+
**What the workflow does** on seeing the tag:
145+
146+
1. Verifies the tag (e.g. `v0.2.0`) matches `package.json.version`. If not,
147+
it fails fast — this catches tags created by hand without a version bump.
148+
2. Runs `npm ci` and `npm run build`.
149+
3. Runs `npm publish --access public --provenance` using `NPM_TOKEN`. The
150+
`--provenance` flag attaches a signed attestation linking the published
151+
tarball back to this repo and this commit.
152+
4. Creates a GitHub Release for the tag with auto-generated release notes
153+
from the commits since the previous tag.
154+
155+
**If something goes wrong:**
156+
157+
* *Tag pushed but workflow failed before publish* — fix the problem, delete
158+
the tag (`git tag -d vX.Y.Z && git push --delete origin vX.Y.Z`), and
159+
re-run `npm version` with the same version using `--allow-same-version`
160+
after resetting, or cut the next patch version. Don't try to reuse a
161+
version once it's been published to npm — npm rejects republishing the
162+
same version even after `npm unpublish`.
163+
* *Published to npm but Release step failed* — run `gh release create vX.Y.Z
164+
--generate-notes` locally to create the release after the fact.
165+
* *Wrong version published* — bump again (`npm version patch`) and release
166+
the fix forward; never rewrite history on `main`.

0 commit comments

Comments
 (0)