Skip to content

feat: add automated versioning and release process - #113

Merged
GoodbyePlanet merged 1 commit into
mainfrom
feat/release-automation
Sep 7, 2026
Merged

GoodbyePlanet merged 1 commit into
mainfrom
feat/release-automation

Conversation

@GoodbyePlanet

Copy link
Copy Markdown
Owner

Closes #111

The repo had zero tags, zero GitHub releases and no changelog, so the serverInfo.version clients read from importlib.metadata mapped to no commit anyone could check out. This adds the release process.

What a release looks like now

release-please watches main, opens a chore(main): release X.Y.Z PR that bumps pyproject.toml and writes CHANGELOG.md from Conventional Commit messages. Merging that PR tags the commit vX.Y.Z and cuts a GitHub Release. Nothing ships until a human merges it.

A release produces a GitHub Release with source and changelog only — no PyPI, no image. Pushing ghcr.io/goodbyeplanet/semcode:X.Y.Z is the one with real user-facing value and is left as a follow-up, per the issue.

File Purpose
.github/workflows/release.yml release-please-action@v4 on push to main, contents:write + pull-requests:write, concurrency-guarded
release-please-config.json release-type: python, package semcode, explicit changelog-sections
.release-please-manifest.json seeded {".": "1.1.0"} so the first automated bump is 1.2.0, not 0.1.0
CHANGELOG.md hand-reconstructed 0.1.0 / 1.0.0 / 1.1.0
.github/dependabot.yml commit prefix chore(deps) → deps
README.md, .claude/CLAUDE.md the contract

Decisions taken

Dependabot prefix changed to deps. The issue asked whether chore(deps): should warrant a release. It should — weeks of Dependabot merges otherwise produce no release boundary. But changelog-sections only controls changelog display, not version bumping, and a chore-typed commit won't reliably surface. Switching the prefix makes "deps → patch bump, listed under Dependencies" deterministic. Existing chore(deps) commits are all pre-tag, so nothing is lost.

Changelog reconstructed from the full history, not seeded with a stub. Version boundaries came from pyproject.toml itself: 0.1.0 at init (2026-04-23), 1.0.0 at the rename to semcode (d2d2c50), 1.1.0 at d8c0f1c. All 70 referenced SHAs resolve. Entries from 1.2.0 onward are generated; the reconstructed ones are documented as frozen.

Squash-merge titles: no settings change needed. The issue flagged this, but it only bites under squash-merging. This repo merge-commits, so the branch's real commits stay on main and release-please reads those; Merge pull request #NNN subjects have no Conventional Commit type and are skipped. The inverse applies instead — every branch commit becomes a changelog line, so keep branch commits release-worthy or squash locally. Also: don't repeat 780b670 feat: Merge conflicts — a hand-labelled merge commit like that would count as a minor bump.

Tags — needs a push

Created locally, not pushed, since pushing tags is irreversible:

git push origin v0.1.0 v1.0.0 v1.1.0
  • v0.1.0 → d085d6d
  • v1.0.0 → d2d2c50
  • v1.1.0 → 0f9af33 (current main, not d8c0f1c)

v1.1.0 sits on current main because five commits — including the full-text-index perf work and the recall fix — shipped under that version number after the bump. It also gives release-please its commit boundary, so the first generated changelog covers only new work rather than rescanning all 181 commits. The three tags together make every compare/ link in CHANGELOG.md resolve.

Verification

uvx ruff format --check . clean, uvx ruff check . clean, 330 tests pass. JSON and YAML parse; every changelog SHA resolves. The release workflow itself can't be exercised until this is on main.

🤖 Generated with Claude Code

The repo had no tags, no GitHub releases and no changelog, so the
`serverInfo.version` clients see mapped to no checkout-able commit.

Add release-please (`release-type: python`) on push to `main`. It opens a
release PR that bumps `pyproject.toml` and writes `CHANGELOG.md` from
Conventional Commit messages; merging it tags the commit and cuts a
GitHub Release. The manifest is seeded at 1.1.0 so the first automated
bump continues from today's version instead of restarting at 0.1.0.

A release produces a GitHub Release with source and changelog only.
Pushing `ghcr.io/goodbyeplanet/semcode:X.Y.Z` is left as a follow-up.

Dependabot now uses the `deps` prefix rather than `chore(deps)`, so a
week of dependency updates still cuts a patch release marking which
dependency set was tested together. `changelog-sections` alone controls
changelog display, not version bumping, so the prefix is what makes this
deterministic.

`CHANGELOG.md` is reconstructed by hand for 0.1.0, 1.0.0 and 1.1.0 from
the full history, since nothing before this commit was ever released.
Version boundaries come from `pyproject.toml`: 0.1.0 at init, 1.0.0 at
the rename to semcode (d2d2c50), 1.1.0 at d8c0f1c.

Document the contract in README.md and .claude/CLAUDE.md: commits must be
Conventional Commits, `pyproject.toml` stays the single source of truth,
and the version is never edited by hand.

Refs #111

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@GoodbyePlanet
GoodbyePlanet merged commit d4d56f1 into main Sep 7, 2026
2 checks passed
@GoodbyePlanet
GoodbyePlanet deleted the feat/release-automation branch September 7, 2026 08:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a versioning and release process (no tags, no releases, no changelog today)

1 participant