Skip to content

feat(release): cut v0.15.0 audit release#289

Merged
tomymaritano merged 1 commit into
mainfrom
hotfix/release-trigger-and-cleanup
Jun 9, 2026
Merged

feat(release): cut v0.15.0 audit release#289
tomymaritano merged 1 commit into
mainfrom
hotfix/release-trigger-and-cleanup

Conversation

@tomymaritano

Copy link
Copy Markdown
Collaborator

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

  1. Manually re-trigger Release workflow on main
  2. semantic-release picks up this commit + the existing release notes generator → cuts v0.15.0
  3. Creates GitHub Release draft + tag
  4. Tag push fires Build workflow → mac/win/linux artefacts
  5. Builds complete → release un-drafts → electron-updater serves it

Related

🤖 Generated with Claude Code

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>
@vercel

vercel Bot commented Jun 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
readide Error Error Jun 9, 2026 4:51am

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@tomymaritano, we couldn't start this review because you've reached your PR review rate limit.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c55de4b8-c325-49d3-ac34-0cd18431e6da

📥 Commits

Reviewing files that changed from the base of the PR and between ae8368e and 7ab3caa.

📒 Files selected for processing (1)
  • release.config.js
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch hotfix/release-trigger-and-cleanup

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread release.config.js
Comment on lines +39 to +40
// @semantic-release/git plugin below does via the `assets` list. So we
// drop the exec step entirely.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

@tomymaritano tomymaritano merged commit 9b36ed3 into main Jun 9, 2026
14 of 16 checks passed
@tomymaritano tomymaritano deleted the hotfix/release-trigger-and-cleanup branch June 9, 2026 04:52
github-actions Bot pushed a commit that referenced this pull request Jun 9, 2026
…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>
github-actions Bot pushed a commit that referenced this pull request Jun 9, 2026
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant