Skip to content

ci: publish on a version tag instead of a published release - #43

Merged
windkh merged 1 commit into
mainfrom
chore/tag-driven-publish
Aug 20, 2026
Merged

ci: publish on a version tag instead of a published release#43
windkh merged 1 commit into
mainfrom
chore/tag-driven-publish

Conversation

@windkh

@windkh windkh commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Adopts npm-publish.yml from node-red-standards 0.6.0 (issue #2). sync will not deliver this on its own — it reports differs (kept; use --force) for a workflow a repo has customised — which is appropriate for a file whose change means a tag push publishes.

⚠️ Behaviour change: pushing a tag now publishes

Previously this triggered on release: [published], so a tag push did nothing until a release was created in the GitHub UI. Now git push --tags is the whole release: it publishes to npm and creates the GitHub release with generated notes.

There is no second confirmation, and npm publish is irreversible. The verify job is the entire safety margin.

The reason for the change is that the manual step gets forgotten. It did: node-red-contrib-shelly sat at 11.12.1 in the repo and 11.12.0 on npm because the tag existed and the release did not.

What the workflow does

Job
verify npm ci, tag/version check, lint, format:check, test — on the CI matrix (20.x, 22.x)
publish-npm needs: verify, Node 22.x, npm publish (or --tag beta)
github-release needs: publish-npm, gh release create --generate-notes

New: the tag must agree with package.json. npm publishes the manifest version, not the tag name — so git tag v1.2.4 on a commit that still says 1.2.3 publishes 1.2.3 under a tag that lies about it, and burns 1.2.4 for good, since a version cannot be published twice. verify compares the two and fails first.

Pre-releases stay off latest. A semver pre-release tag (v1.2.3-beta.1, v2.0.0-rc.1) publishes to the beta dist-tag and marks the GitHub release as a pre-release. latest cannot be walked back by publishing, only by a separate dist-tag change, so a pre-release reaching it would pull every Manage Palette user onto an unproven build.

The gate runs the full CI matrix, not one Node version. A tag may point at a commit CI never saw — a tag can be moved, or cut from a branch that never opened a PR — and a tag is exactly the moment a version-specific failure is most expensive to find.

Both v* and V* are triggers; the six repos use both prefixes.

For this repo specifically

The publish job moves from Node 20 to 22.x, and here that is a real fix rather than tidiness: this package depends on node-red ^5.0.1, and node-red@5 requires Node >=22.9. Pinning 20 for the publish job pointed the wrong way against its own dependency floor.

Verified locally: prettier --check . passes with the new file, and the tag/version check agrees on 2.1.2 (V2.1.2package.json).

Adopts npm-publish.yml from node-red-standards 0.6.0 (issue #2).

BEHAVIOUR CHANGE: pushing a tag now publishes. This triggered on
`release: [published]`, so a tag push did nothing until a release was created by
hand in the GitHub UI. Now `git push --tags` publishes to npm and creates the
release with generated notes. There is no second confirmation and npm publish is
irreversible; the verify job is the entire safety margin.

The manual step is what gets forgotten: node-red-contrib-shelly sat at 11.12.1 in
the repo and 11.12.0 on npm because the tag existed and the release did not.

New: verify fails when the tag disagrees with package.json. npm publishes the
manifest version, not the tag name, so `git tag v1.2.4` on a commit that still
says 1.2.3 publishes 1.2.3 under a tag that lies about it -- and burns 1.2.4 for
good, since a version cannot be published twice.

The gate now runs the full CI matrix rather than a single Node version. A tag can
be moved, or cut from a branch that never opened a PR, so it is exactly the
moment a version-specific failure is most expensive to find.

Pre-releases keep going to the beta dist-tag, now decided by a semver `-` in the
tag name rather than by github.event.release.prerelease, which does not exist
under a tag trigger.

Also moves the publish job to Node 22.x, the pin the standard has had since
0.4.0 and this file predated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comment on lines +60 to +97
needs: verify
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 20.x
# Must satisfy the STRICTEST `engines.node` among repos using this standard,
# not this standard's own >=20 baseline. A repo may raise its floor
# (node-red@5 requires >=22.9), and a 20.x pin then warns or fails on
# `npm ci` -- breaking the release of exactly the repos that are most
# current. Raise this when a repo goes past 22. Deliberately a fixed LTS
# rather than `node-version-file: package.json`: setup-node resolves a
# `>=` range to the newest Node in existence, so a brand-new major could
# block a release on a day nobody chose.
node-version: 22.x
cache: npm
registry-url: https://registry.npmjs.org
- run: npm ci
# A GitHub release flagged "pre-release" goes to the `beta` dist-tag, so users
# on Manage Palette — which tracks `latest` — are not auto-upgraded onto an
# unproven build. A plain `npm publish` would move `latest` to the beta and
# push it to every install; `latest` cannot be walked back to an earlier
# version by publishing, only by a separate dist-tag change.
- run: npm publish ${{ github.event.release.prerelease && '--tag beta' || '' }}
# A semver pre-release (anything after a `-`, e.g. v1.2.3-beta.1) goes to the `beta`
# dist-tag, so users on Manage Palette -- which tracks `latest` -- are not
# auto-upgraded onto an unproven build. A plain `npm publish` would move `latest` to
# the pre-release and push it to every install, and `latest` cannot be walked back
# by publishing, only by a separate dist-tag change.
#
# Every pre-release identifier maps to `beta`, including `-rc` and `-alpha`. Mapping
# each to its own dist-tag would be more precise but adds a name nobody tracks; the
# property that matters is only "not latest".
- name: Publish
run: |
VERSION="${GITHUB_REF_NAME#[vV]}"
case "$VERSION" in
*-*) echo "pre-release ${VERSION} -> dist-tag beta"; npm publish --tag beta ;;
*) echo "release ${VERSION} -> dist-tag latest"; npm publish ;;
esac
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

github-release:
@windkh
windkh merged commit 1e1b2db into main Aug 20, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants