Skip to content

Releases

Nobody edits a version number by hand here. semantic-release reads the commit log, decides what the next version is, tags it, writes the release notes and triggers the image build.

Which makes commit messages an input to a program, not a note to yourself.

Conventional Commits. The prefix decides the bump:

Prefix Effect
fix: Patch, 0.8.0 to 0.8.1
feat: Minor, 0.8.0 to 0.9.0
BREAKING CHANGE: in the body Major
chore:, docs:, refactor:, … No release on its own

The subject line is what appears in the release notes, read by people who were not there. Write it for them.

The release workflow is manual, run from the Actions tab. It is not fired by pushing to main, so a series of commits can land and be released together when they make a coherent whole.

What it does, in order:

  1. semantic-release works out the version from the commits since the last tag.
  2. It writes the release notes and pushes a chore(release): x.y.z commit carrying the new version in package.json.
  3. The image workflow builds from main, which by then includes that commit, and publishes ghcr.io/cedhuf/llooma tagged :latest, :x.y.z and with the commit SHA.

Images are published per release rather than per push. A multi-arch build takes around twenty minutes, and :latest is only meaningful if the version it carries is the one that was tagged.

The image workflow can also be run on its own, to publish from main without cutting a release.

Some releases drop one-shot migrations, the carry-overs that read an older storage layout once and then are gone. A release that does this must name the version to pin in its notes, so anyone on an older build can upgrade through it first.

This is the one thing in the release process that cannot be automated away, because it is a promise to people whose data is at stake. See the note in Installation.

Built from docs/ and published to GitHub Pages by its own workflow, on push. It is a separate pnpm workspace:

Terminal window
cd docs
pnpm install
pnpm run dev

The base in astro.config.mjs has to match the repository name: Pages serves the site from a sub-path and every internal link is built from it.

The HTTP API reference is generated from docs/openapi.yaml, and CI fails if a route exists that the spec does not describe. See Working on Llooma.