|
| 1 | +# Releasing |
| 2 | + |
| 3 | +Manual release flow for claude-code-chat-browser. A release is a git tag plus a GitHub Release with notes. No CI publish workflow, and no wheel, npm package, or other artifact. |
| 4 | + |
| 5 | +`v0.1.0` (2026-06-18) and `v0.2.0` (2026-07-30) are the shipped tags so far. The steps below apply to the next cut. |
| 6 | + |
| 7 | +## Version source |
| 8 | + |
| 9 | +The release version is `__version__` in `app.py` line 3. There is no `pyproject.toml` version field. |
| 10 | + |
| 11 | +`SECURITY.md` line 5 names the latest shipped release in its supported-versions blurb, so update it when a tag ships, not on the `.dev0` bumps in between. `README.md` points readers at that page. |
| 12 | + |
| 13 | +Between tagged releases, `master` may use a `.dev0` suffix (for example `0.3.0.dev0` while the next release is in flight). The shipped tag drops `.dev0`. |
| 14 | + |
| 15 | +## Pre-release checklist |
| 16 | + |
| 17 | +1. Confirm `master` is green in GitHub Actions (`.github/workflows/ci.yml`). |
| 18 | +2. Decide the semver bump using [docs/deprecation-policy.md](docs/deprecation-policy.md#versioning) (pre-1.0: patch for safe fixes, minor for additive work and deprecations). |
| 19 | +3. If the release removes or renames a documented API field, confirm the [two-release deprecation window](docs/deprecation-policy.md#removal-criteria) is satisfied. |
| 20 | + |
| 21 | +## Release checklist |
| 22 | + |
| 23 | +Do the changelog in one PR and the version bump in a second PR, or combine them on a `release/vX.Y.Z` branch. For `v0.2.0` we used two PRs: changelog first (`docs/changelog-0-2-0`), then the bump (`release/v0.2.0`). |
| 24 | + |
| 25 | +1. Edit [CHANGELOG.md](CHANGELOG.md) ([Keep a Changelog](https://keepachangelog.com/en/1.1.0/)): |
| 26 | + - Move everything under `## [Unreleased]` into a new `## [X.Y.Z] - YYYY-MM-DD` section with `### Added`, `### Changed`, `### Deprecated`, `### Fixed`, `### Removed`, or `### Security` as needed. |
| 27 | + - Leave `## [Unreleased]` empty. |
| 28 | + - Update the footer compare links: `[Unreleased]` → `vX.Y.Z...HEAD`, add `[X.Y.Z]` → `vPREVIOUS...vX.Y.Z`. |
| 29 | +2. On a branch from current `master`, set `app.py` line 3 to the release version without `.dev0` (for example `"0.2.0"`). |
| 30 | +3. Update [SECURITY.md](SECURITY.md) line 5 so the version inside its "(currently ...)" parenthetical is the one you are shipping. Keep the surrounding formatting and leave the table at lines 7-10 unchanged. |
| 31 | +4. From the repo root, grep for stale version strings (`.dev0` suffixes, the old SECURITY.md parenthetical, or the previous shipped release): |
| 32 | + ```sh |
| 33 | + PREVIOUS=0.2.0 |
| 34 | + PREVIOUS_ESC=$(echo "$PREVIOUS" | sed 's/[.]/\\&/g') |
| 35 | + git grep -nE "\.dev0|\(currently |${PREVIOUS_ESC}" |
| 36 | + ``` |
| 37 | + Point `PREVIOUS` at the release you are replacing (no `v` prefix). Fix any hits that should name the new version (for example `docs/deprecation-policy.md`). |
| 38 | +5. Open a PR, get review, merge to `master`. |
| 39 | +6. Tag the merge commit (lightweight tag, same as `v0.1.0` and `v0.2.0`): |
| 40 | + ```sh |
| 41 | + git checkout master |
| 42 | + git pull |
| 43 | + git tag vX.Y.Z |
| 44 | + git push origin vX.Y.Z |
| 45 | + ``` |
| 46 | + Tag format: `vMAJOR.MINOR.PATCH` (for example `v0.2.0`). |
| 47 | +7. Publish the GitHub Release after pushing the tag. From the repo root, extract the body from `CHANGELOG.md`: |
| 48 | + ```sh |
| 49 | + cd "$(git rev-parse --show-toplevel)" |
| 50 | + VERSION=0.2.0 # no leading v; not the literal X.Y.Z placeholder |
| 51 | + VERSION="${VERSION#v}" |
| 52 | + case "$VERSION" in |
| 53 | + *[!0-9.]*|'') echo "error: VERSION must look like 0.2.0" >&2; exit 1 ;; |
| 54 | + *..*|.*|*.) echo "error: VERSION must look like 0.2.0" >&2; exit 1 ;; |
| 55 | + *.*.*.*) echo "error: VERSION must look like 0.2.0" >&2; exit 1 ;; |
| 56 | + *.*.*) ;; |
| 57 | + *) echo "error: VERSION must look like 0.2.0" >&2; exit 1 ;; |
| 58 | + esac |
| 59 | + case "$VERSION" in |
| 60 | + 0[0-9]*.*.*|*.[0][0-9]*.*|*.*.[0][0-9]*) |
| 61 | + echo "error: VERSION components must not have leading zeros" >&2; exit 1 ;; |
| 62 | + esac |
| 63 | + NOTES="$(mktemp)" |
| 64 | + trap 'rm -f "$NOTES"' EXIT |
| 65 | + awk -v ver="$VERSION" ' |
| 66 | + BEGIN { heading = "## [" ver "]" } |
| 67 | + /^## \[/ { |
| 68 | + if (found) exit |
| 69 | + if (index($0, heading) == 1) { found=1 } |
| 70 | + } |
| 71 | + /^\[[^]]+\]:/ { if (found) exit } |
| 72 | + found { print } |
| 73 | + ' CHANGELOG.md >"$NOTES" |
| 74 | + grep -v '^## \[' "$NOTES" | grep -q '[^[:space:]]' || { echo "error: no CHANGELOG.md section for $VERSION" >&2; exit 1; } |
| 75 | + printf '\n\n**Full changelog:** https://github.com/cppalliance/claude-code-chat-browser/blob/v%s/CHANGELOG.md\n' "$VERSION" >>"$NOTES" |
| 76 | + gh release create "v${VERSION}" --title "v${VERSION}" --verify-tag --notes-file "$NOTES" |
| 77 | + ``` |
| 78 | + The `printf` adds the same "Full changelog" footer that `v0.1.0` and `v0.2.0` carry. On macOS, Linux, and Git Bash, `mktemp` works. Or paste the `[X.Y.Z]` section in the GitHub UI and add that footer line by hand. |
| 79 | + |
| 80 | +## After release |
| 81 | + |
| 82 | +1. On `master`, bump `app.py` `__version__` to the next development suffix when you start the next cycle (for example `0.3.0.dev0` after shipping `0.2.0`). Put that commit in `CHANGELOG.md` under `[Unreleased]` only when there is user-visible work; a bare dev bump can ride with the next feature PR. |
| 83 | +2. New work goes under `## [Unreleased]` until the next release. |
| 84 | + |
| 85 | +## References |
| 86 | + |
| 87 | +| Topic | Location | |
| 88 | +|-------|----------| |
| 89 | +| Changelog format | [CHANGELOG.md](CHANGELOG.md) | |
| 90 | +| Version bump | `app.py` line 3 | |
| 91 | +| Supported versions blurb | `SECURITY.md` line 5 | |
| 92 | +| Deprecation / semver | [docs/deprecation-policy.md](docs/deprecation-policy.md) | |
| 93 | +| Security reporting | [SECURITY.md](SECURITY.md) | |
| 94 | +| CI gates | [`.github/workflows/ci.yml`](.github/workflows/ci.yml), [CONTRIBUTING.md](CONTRIBUTING.md) | |
0 commit comments