fix(ci): make release publish step idempotent#20
Conversation
release.yml runs on every push to main. changesets/action only opens a "Version Packages" PR when there are pending changesets — on infra-only merges (e.g. CI tweaks like #17 and #19), the action falls through to the publish step. The previous `pnpm release` script invoked `npm publish` directly, which errors out with "You cannot publish over the previously published versions" and fails the release job for every non-changeset merge. Add a `publish-if-new.mjs` guard that: - reads the version from packages/whisper/package.json - queries `npm view <name>@<version>` to check the registry - skips with a clean message if already published - runs `npm publish --access public --provenance` otherwise Trusted publishing + provenance flags preserved verbatim — no change to the publish path itself, just a registry-aware gate around it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
WalkthroughThe release process is modified to use an idempotent publish guard. The Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@scripts/publish-if-new.mjs`:
- Around line 47-52: After calling spawnSync to run 'npm publish' in
scripts/publish-if-new.mjs (the block using spawnSync with cwd
resolve(.../packages/whisper) and assigning result), detect when the publish
fails (non-zero result.status) and perform a single read-after-write check by
invoking spawnSync('npm', ['view', `${name}@${version}`], ...) or equivalent to
query the registry for that exact package@version; if that check indicates the
version exists (success exit code / non-empty output) then treat the operation
as successful and exit 0, otherwise propagate the original publish failure exit
code. Ensure you reference the same cwd/stdio strategy and keep the extra npm
view call only on publish failure to avoid changing normal flow.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3b1ab817-1754-4e39-8cd2-25cef2ec8c81
📒 Files selected for processing (2)
package.jsonscripts/publish-if-new.mjs
|
Verified CodeRabbit's read-after-write suggestion against the current code — declining for this PR. Why it's not needed:
|
Summary
The Release workflow has been failing on every infra-only merge to main (PR #17, PR #19) with:
```
npm error You cannot publish over the previously published versions: 0.2.7.
```
Why: `changesets/action` runs the `publish` script (`pnpm release`) whenever there are no pending changesets. The previous script ended with a direct `npm publish` — not idempotent — so any merge that didn't include a `.changeset/*.md` file would fail at publish time, even though there was nothing new to ship.
Fix: a small `scripts/publish-if-new.mjs` guard that checks `npm view @wardbox/whisper@` and only runs `npm publish` when the version isn't already on the registry.
Reference failing run: https://github.com/wardbox/whisper/actions/runs/25018663341
Test plan
🤖 Generated with Claude Code
Problem
The Release workflow fails on infra-only merges when
changesets/actionruns thepublishscript with no pending changesets. Previously, thenpm publishcommand would fail with "You cannot publish over the previously published versions" errors.Solution
Introduces an idempotent publish guard script (
scripts/publish-if-new.mjs) that:packages/whisper/package.jsonnpm view @wardbox/whisper@<version>--access public --provenanceflags only if the version is not yet on the registryThe
scripts.releaseinpackage.jsonnow invokes this guard script instead of runningnpm publishdirectly.Files Changed
package.json: Updatedreleasescript to callnode scripts/publish-if-new.mjsscripts/publish-if-new.mjs: New 52-line Node script implementing idempotent publish logic