ci: publish on a version tag instead of a published release - #43
Merged
Conversation
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: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adopts
npm-publish.ymlfrom node-red-standards 0.6.0 (issue #2).syncwill not deliver this on its own — it reportsdiffers (kept; use --force)for a workflow a repo has customised — which is appropriate for a file whose change means a tag push publishes.Previously this triggered on
release: [published], so a tag push did nothing until a release was created in the GitHub UI. Nowgit push --tagsis the whole release: it publishes to npm and creates the GitHub release with generated notes.There is no second confirmation, and
npm publishis irreversible. Theverifyjob is the entire safety margin.The reason for the change is that the manual step gets forgotten. It did:
node-red-contrib-shellysat 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
verifynpm ci, tag/version check, lint, format:check, test — on the CI matrix (20.x, 22.x)publish-npmneeds: verify, Node 22.x,npm publish(or--tag beta)github-releaseneeds: publish-npm,gh release create --generate-notesNew: the tag must agree with
package.json. npm publishes the manifest version, not the tag name — sogit tag v1.2.4on a commit that still says1.2.3publishes 1.2.3 under a tag that lies about it, and burns 1.2.4 for good, since a version cannot be published twice.verifycompares 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 thebetadist-tag and marks the GitHub release as a pre-release.latestcannot 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*andV*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.2↔package.json).