diff --git a/.claude/rules/release.md b/.claude/rules/release.md index f885d1f..82dcf83 100644 --- a/.claude/rules/release.md +++ b/.claude/rules/release.md @@ -11,7 +11,7 @@ paths: `docs/RELEASING.md` is canonical. release-please (`release-please.yml`, config `release-please-config.json`, state `.release-please-manifest.json`) is the only release mechanism; the `standard-version` scripts were removed on 2026-10-23. -- Conventional Commits on `main` drive the version: `fix:` patch, `feat:` minor, `feat!:` or a `BREAKING CHANGE:` footer major; `docs:`, `chore:`, `test:`, `ci:`, `refactor:` do not bump and stay out of the changelog. Squash-merge PRs with a Conventional Commit title. A `Release-As: x.y.z` footer forces a version. +- Conventional Commits on `main` drive the version: `fix:` patch, `feat:` minor, `feat!:` or a `BREAKING CHANGE:` footer major; `docs:`, `chore:`, `test:`, `ci:`, `refactor:` do not bump and stay out of the changelog. Squash-merge PRs with a Conventional Commit title: since 2026-10-24 the repository allows only squash merges, titled from the PR with a blank body, because release-please turns a body paragraph that starts with `feat(`, `fix:` and the like into a second changelog entry (the duplicated 1.1.3 and 1.2.0 entries came from merge commits). A `Release-As: x.y.z` footer forces a version; branch-commit footers do not survive the squash, so a `Release-As:` or `BREAKING CHANGE:` footer goes into the squash body at merge time (`gh pr merge --squash --body '...'`), or the title carries `!`. - release-please keeps one open Release PR from branch `release-please--branches--main--components--optia`. **Merging it is the human release gate.** It stamps `package.json`, `app/package.json` and `app/manifest.json` (the `extra-files`), rewrites `CHANGELOG.md`, tags `vX.Y.Z` and publishes a GitHub Release. The `attach-zip` job in the same run builds `app/dist` at the tag, deletes the manifest `key` (the store rejects it) and uploads `optia-X.Y.Z.zip`. Releases created with the default `GITHUB_TOKEN` do not fire `on: release`, which is why the zip is attached in that run. - `release-zip.yml` is the manual fallback (`workflow_dispatch` with a tag) to rebuild and re-attach the zip. - The Chrome Web Store upload is manual: Paul downloads the zip and uploads it in the Developer Dashboard under paul@pmds.info (item `gnlidlpidaoalbbmekofjednjkhhmehn`). The store requires `manifest.json` at the archive root and a version greater than the published one. `/store-upload-check [tag]` verifies the package first. diff --git a/docs/RELEASING.md b/docs/RELEASING.md index b488fc4..cfa55d2 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -19,10 +19,10 @@ Releases are automated with [release-please](https://github.com/googleapis/relea | `feat!:` / `BREAKING CHANGE:` footer | major | | `docs:`, `chore:`, `test:`, `ci:`, `refactor:` | none (hidden from changelog) | -To force a specific version, add a `Release-As: 1.0.0` footer to any commit on `main`. +To force a specific version, add a `Release-As: 1.0.0` footer to any commit on `main`. Footers on branch commits do not survive a squash merge (the squash body is blank), so type the footer into the squash commit when merging: `gh pr merge --squash --body 'Release-As: 1.0.0'`, or edit the message in the merge dialog. The same goes for a `BREAKING CHANGE:` footer; `feat!:` in the PR title needs nothing extra. ## Cautions -- **Squash-merge PRs with a Conventional Commit title** — release-please reads the commits that land on `main`, and a squash commit's message is the PR title. +- **Squash-merge PRs with a Conventional Commit title** — release-please reads the commits that land on `main`, and a squash commit's message is the PR title. Since 2026-10-24 the repository allows only squash merges, with the PR title as the commit title and a blank body: release-please splits any body paragraph that starts with a type such as `feat(` into a second changelog entry, which is how 1.1.3 and 1.2.0 listed each change twice from their merge commits. - The manifest `key` field pins the extension ID (`lgkgkmjldppeidgafolhfpepmabnnbhe`); it ships in the zip so the store keeps the same ID across uploads. Do not remove or regenerate it. - The Chrome Web Store requires each upload's `manifest.json` version to be **greater** than the currently published one — another reason versions only move through the Release PR.