From 7b1a1f0533ee890eabf1cedd6290acee91d546da Mon Sep 17 00:00:00 2001 From: "Sebastian BURGIN-FIX (ext)" Date: Mon, 3 Aug 2026 13:05:06 +0200 Subject: [PATCH] Make the Release workflow tolerate and discourage manual publishes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v1.8.0's Release run went red at the last step: npm error You cannot publish over the previously published versions: 1.8.0. Nothing was broken. The tag was pushed at 04:59:00, the version reached the registry at 04:59:09 while this job was still on `npm ci`, and the job's own `npm publish` was rejected two minutes later as a duplicate. Since release.yml is the only workflow that publishes, the 04:59:09 upload was a local `npm publish`. (1.6.0 is on the registry with no tag and no run at all — the same habit, without even a tag.) The release shipped; only the signal broke, and a red run that means "already fine" is worse than no run. - Fail fast when the tag and package.json version disagree, before spending three minutes on a build that can only publish the wrong thing or nothing. - Treat an already-published version as a no-op with a warning, not a failure, so the run's colour tracks whether the release is good. - Verify the version actually resolves on the registry afterwards. - README: document tag-driven releases and why not to publish by hand. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/release.yml | 42 ++++++++++++++++++++++++++++++++++- README.md | 15 +++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cde5946..c85950a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,6 +21,23 @@ jobs: registry-url: https://npm.pkg.github.com scope: '@codebar-ag' + # Catches the tag/manifest mismatch BEFORE spending three minutes on a + # build: `git tag v1.9.0` without the matching `npm version` bump either + # republishes the previous version or fails at the very last step. + - name: Tag must match package.json version + run: | + tag="${GITHUB_REF_NAME#v}" + manifest="$(node -p "require('./package.json').version")" + + if [ "$tag" != "$manifest" ]; then + echo "::error::Tag v${tag} does not match package.json version ${manifest}." \ + "Bump the manifest (npm version) and re-tag." + exit 1 + fi + + echo "version=${manifest}" >> "$GITHUB_OUTPUT" + id: version + - run: npm ci - name: Typecheck + lint @@ -40,10 +57,33 @@ jobs: - name: Component tests (Playwright) run: npm run test:ci + # v1.8.0's release went red here with "You cannot publish over the + # previously published versions": the version had been published BY HAND + # nine seconds after the tag push, while this job was still on `npm ci`. + # Nothing was actually wrong with the release — it had already shipped — + # but the red run made a healthy release indistinguishable from a broken + # one. Publish from CI only; if the version is somehow already on the + # registry, say so and pass rather than failing on a no-op. - name: Publish to GitHub Packages - run: npm publish + run: | + version="${{ steps.version.outputs.version }}" + + if npm view "@codebar-ag/storybook@${version}" version >/dev/null 2>&1; then + echo "::warning::@codebar-ag/storybook@${version} is already on the registry;" \ + "nothing to publish. It was published outside this workflow —" \ + "release by pushing a v* tag, never by running npm publish locally." + exit 0 + fi + + npm publish env: NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # The project .npmrc references ${GITHUB_TOKEN}, which npm resolves # ahead of setup-node's userconfig — keep both env vars populated. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Verify the published version resolves + run: npm view "@codebar-ag/storybook@${{ steps.version.outputs.version }}" version + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index 225db69..1d21432 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,21 @@ npm run typecheck # vue-tsc npm run lint ``` +## Release + +Publishing happens in CI, on a `v*` tag. Never run `npm publish` by hand — the +registry rejects a republish, so a manual publish turns the tag's Release run +red even though the version shipped fine, and a healthy release stops being +distinguishable from a broken one (this is exactly what happened to v1.8.0). + +```bash +npm version minor # bumps package.json + creates the vX.Y.Z tag +git push --follow-tags # Release workflow builds, tests, publishes +``` + +The workflow refuses to run if the tag and `package.json` version disagree, and +verifies the version resolves on the registry once published. + ## Changelog Release notes, migration notes and upgrade warnings live in