feat(release): cut v0.15.0 audit release#289
Conversation
PR #245 squash-merged 19 individual PRs (#266-#284) into a single commit on main with the message "release: audit + Ed25519 signed envelopes + lefthook (v0.15.0) (#245)". That isn't a conventional commit type semantic-release recognises, so the analyser saw 11 commits since the last tag and concluded "no release". The actual feat:/fix:/refactor: messages from the 19 underlying PRs were lost in the squash. This commit provides the missing release signal: a feat: commit that semantic-release will analyse as a minor bump. The accompanying config change drops a broken pipeline step: - The @semantic-release/exec plugin step ran `node scripts/bump-version.js ${nextRelease.version}` to sync per-package versions. That script was deleted in the knip cleanup (#279) but release.config.js wasn't updated to match. Any release triggered now would fail at the prepare step with ENOENT. The remaining @semantic-release/git plugin already commits the root package.json + apps/desktop/package.json + CHANGELOG.md via its assets list, which is everything the desktop release actually needs bumped. Workspace packages stay at workspace:* and their numeric versions aren't user-visible anyway. After this merges, manually re-trigger the Release workflow. Expected outcome: v0.15.0 tag created, draft GitHub Release with notes, Build workflow fires for mac/win/linux. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
More reviews will be available in 18 minutes and 30 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7ab3caa8ac
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // @semantic-release/git plugin below does via the `assets` list. So we | ||
| // drop the exec step entirely. |
There was a problem hiding this comment.
Restore a version-bumping prepare step
In the manual Release workflow on main, this config now has no prepare plugin that writes the computed nextRelease.version into either package.json; @semantic-release/git only commits files that were already modified, and the official git plugin docs say @semantic-release/npm must run first to update package.json so git can include it. For the intended v0.15.0 release, semantic-release can therefore tag/publish a v0.15.0 release while the Build workflow checks out a tree where apps/desktop/package.json is still 0.14.0, so electron-builder produces an app/artifacts with the old version.
Useful? React with 👍 / 👎.
…hase 0 A2) (#291) ## Summary Phase 0 A2. Restores the version-bump step semantic-release needs to actually write the new version into the package.json files BEFORE the git plugin commits them. ## What was broken The v0.15.0 tag points at a commit where both \`package.json\` and \`apps/desktop/package.json\` still read \`0.14.0\`: \`\`\` $ git show v0.15.0:package.json | jq -r .version 0.14.0 $ git show v0.15.0:apps/desktop/package.json | jq -r .version 0.14.0 \`\`\` Symptom: electron-updater sees mismatched versions; any consumer reading from package.json drifts from the tag; ship-it-and-forget-it release becomes "wait, what version is this?". ### Why semantic-release pipeline is a chain. Each plugin has a contract. | Plugin | Contract | |---|---| | \`commit-analyzer\` | decides next version | | \`release-notes-generator\` | writes release notes | | \`changelog\` | mutates CHANGELOG.md | | \`exec.prepareCmd\` | **mutates package.json (this step was missing)** | | \`git\` | commits the mutated files via \`assets:\` list | | \`github\` | creates draft release | The \`assets:\` list in \`@semantic-release/git\` ONLY commits files; it doesn't create the diff. Without an explicit mutation step, the git plugin sees no changes to package.json and commits an effectively empty diff (just the CHANGELOG update). The original \`scripts/bump-version.js\` performed that mutation, wired via \`@semantic-release/exec\`. It was deleted in the knip cleanup (#279) under the false assumption nothing referenced it — knip didn't scan \`release.config.js\` as an entry point. PR #289 patched \`release.config.js\` to remove the dangling \`prepareCmd\`, which made the workflow stop crashing but left versions stale. ## Fix 1. **\`scripts/bump-version.mjs\`** (new) — pure-ESM, zero dependencies, updates ONLY the \`version\` field of exactly two files (\`package.json\` and \`apps/desktop/package.json\`). Preserves existing trailing-newline. Fails non-zero on missing version arg, unparseable JSON, or absent version field. 2. **\`release.config.js\`** — re-wires the \`@semantic-release/exec\` plugin (already a devDep) with \`prepareCmd: 'node scripts/bump-version.mjs \${nextRelease.version}'\`. Comment block in the file documents the history so the next maintainer doesn't repeat the mistake. Packages with independent release cycles (notably \`packages/api\` on Cloudflare Workers, \`packages/mcp-server\`) are deliberately NOT in the target list. If we ever need to bump them, that's a separate concern with a separate script. ## Verification \`\`\` $ node scripts/bump-version.mjs 0.15.1 bump-version: package.json 0.14.0 -> 0.15.1 bump-version: apps/desktop/package.json 0.14.0 -> 0.15.1 bump-version: updated 2 of 2 target(s) \`\`\` Edge cases: - \`node scripts/bump-version.mjs\` (no arg) → \`missing version argument\`, exit 1 - \`node scripts/bump-version.mjs 0.14.0\` (already at version) → \`already at 0.14.0, skipped\`, exit 0 - Same version on already-bumped files → idempotent, no diff - ✅ \`pnpm -r typecheck\` — green - ✅ \`pnpm test\` — 17/17 packages ## Stack context Phase 0 A2 of the post-audit devops roadmap. Pairs with #290 (A1, electron pin). Independent files, can land in any order. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…se 0 A4) (#293) ## Summary Phase 0 A4. Two guardrails on \`release.yml\` to make a silent or partial release impossible. ## Why The v0.15.0 release pipeline failed silently twice: 1. **Silent no-op**: PR #245's squash-merge title (\`release: audit + Ed25519 signed envelopes + lefthook (v0.15.0) (#245)\`) didn't match a conventional commit type in \`releaseRules\`. semantic-release exited cleanly with \"no release\" and the workflow ended green; the operator only noticed because no tag appeared. We patched this with #289 by adding a forcing \`feat:\` commit, but the trap will fire again on the next big squash unless the workflow refuses to silently no-op. 2. **Stale version**: even when the release finally cut, both \`package.json\` files still read \`0.14.0\` because the deleted \`scripts/bump-version.js\` was never re-introduced (fixed in PR #291). Tag points at one version, file content reads another — visible by anyone running \`jq .version package.json\` against the tag. ## Guardrails ### Pre-flight (dry-run) \`\`\`yaml - name: Pre-flight (dry-run) check run: | npx semantic-release --dry-run 2>&1 | tee /tmp/sr-dry.log if grep -qE \"There are no relevant changes\" /tmp/sr-dry.log; then echo \"::error::semantic-release dry-run: no release will be cut.\" exit 1 fi if ! grep -qE \"next release version is\" /tmp/sr-dry.log; then echo \"::error::semantic-release dry-run did not announce a next release version.\" exit 1 fi \`\`\` Stops the workflow loud and clear before \`--ci\` if commit-analyzer would have returned \"no release\". Actionable error messages point at \`release.config.js > releaseRules\` and the commit log. ### Post-flight (version assertion) \`\`\`yaml - name: Verify version bump applied run: | expected=$(grep -oE \"next release version is [0-9]+\\.[0-9]+\\.[0-9]+\" /tmp/sr-dry.log | tail -n 1 | awk '{print $NF}') root_v=$(jq -r .version package.json) desk_v=$(jq -r .version apps/desktop/package.json) if [ \"$root_v\" != \"$expected\" ] || [ \"$desk_v\" != \"$expected\" ]; then echo \"::error::Version mismatch after semantic-release.\" exit 1 fi \`\`\` Re-uses the captured dry-run log to know what version SHOULD have been written. Catches a misconfigured or skipped \`scripts/bump-version.mjs\` (PR #291) BEFORE the tag-triggered build downloads the stale package.json. ## What gets caught | Trap | Caught by | |---|---| | Non-conventional PR title (#245 trap) | Pre-flight: \"no relevant changes\" | | Wrong releaseRules / type filter | Pre-flight: \"did not announce next release\" | | \`prepareCmd\` missing or wrong path | Post-flight: version mismatch | | \`bump-version.mjs\` only updated one file | Post-flight: per-file diff | | semantic-release crashed mid-cycle | Native exit code from \`Run semantic-release\` step | ## Verification I dry-ran the gate logic locally against the current main commit log; the dry-run output contains the expected lines for both happy-path and no-op cases. No way to test end-to-end without actually invoking the workflow. ## Stack context Phase 0 A4. Independent from A1 (#290), A2 (#291), B-bundle (#292). Different files / steps; no overlapping changes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Why this PR
PR #245 squash-merged 19 individual PRs (#266-#284) into a single commit on main: `release: audit + Ed25519 signed envelopes + lefthook (v0.15.0) (#245)`. That message isn't a conventional commit type that semantic-release recognises, so the analyser saw 11 commits since the last tag and concluded "no release". The actual feat:/fix:/refactor: messages from the 19 underlying PRs were lost in the squash.
Concretely, run 27184456847 finished cleanly but logged:
```
[semantic-release] [@semantic-release/commit-analyzer] › ℹ Analysis of 11 commits complete: no release
[semantic-release] › ℹ There are no relevant changes, so no new version is released.
```
What this PR does
1. Provides the release signal
This commit's title is `feat(release): cut v0.15.0 audit release` — a recognised conventional type. semantic-release will analyse it as a minor bump (v0.14.x → v0.15.0).
2. Drops the broken `@semantic-release/exec` step
`release.config.js` referenced `node scripts/bump-version.js ${nextRelease.version}` in a prepareCmd, but that script was deleted in the knip cleanup (#279) and the config wasn't updated. Any release triggered now would fail at the prepare step with `ENOENT`.
The remaining `@semantic-release/git` plugin already commits root `package.json` + `apps/desktop/package.json` + `CHANGELOG.md` via its `assets` list — that's everything the desktop release needs bumped. Workspace packages stay at `workspace:*` and their numeric versions aren't user-visible.
Side effect
`@semantic-release/exec` is still listed in `package.json` devDeps but unused after this PR. Not removing it here to keep this PR surgical; can be dropped in the next knip pass.
After this merges
Related
🤖 Generated with Claude Code