Files
alexm abc0bdf621
Sync README to GitHub / sync (push) Successful in 12s
CI / check (push) Successful in 8m31s
Deploy docs / deploy (push) Successful in 6m44s
Nightly / nightly (push) Successful in 10m33s
Dev (#1)
Reviewed-on: #1
2026-08-07 15:48:11 -04:00

78 lines
4.0 KiB
Markdown

# Releasing
This is the maintainer's guide to versioning and the release automation.
End users do not need it; they want the [README](README.md) and the setup guide.
## Versioning
Releases are dated, not semantic. The version is `YY.MM.PATCH`:
- `YY` is the two-digit year. 2026 is `26`.
- `MM` is the month with no leading zero. August is `8`, not `08`.
The version has to parse as SemVer (Cargo insists), and SemVer rejects leading zeros in a numeric field, so `26.08.0` is invalid and `26.8.0` is the form to use.
- `PATCH` starts at `0` in a new month and counts up for any further releases that month.
So the sequence across a few releases reads `26.8.0`, `26.8.1`, `26.9.0`.
These sort correctly both as dates and as SemVer, because each field is compared as a number.
The number is a date, not a compatibility contract.
Any release can change behavior; the [CHANGELOG](CHANGELOG.md) is where that is written down.
This is separate from `rust-version` in `Cargo.toml`, which is the oldest Rust that compiles the crate (currently `1.85`, the edition-2024 floor).
The pixi manifest pins a specific recent toolchain for reproducible builds. The two numbers answer different questions and are allowed to differ.
## Cutting a stable release
The version lives in two files, `Cargo.toml` and `pixi.toml`.
bump-my-version keeps them in step and computes the next number from today's date; it is configured in `.bumpversion.toml` and installed in the `release` pixi environment.
1. Record what changed: move the `Unreleased` notes in `CHANGELOG.md` under a heading for the new version, and commit that.
A clean working tree is required, so this commit comes first.
2. Preview the number the bump would produce:
```sh
pixi run bump-show
```
3. Cut it:
```sh
pixi run bump
```
This rewrites the version in both manifests, makes a `Release <version>` commit, and tags it.
The number follows the calendar: the first release in a month is `.0`, and a later one that month is `.1`.
To see every edit before it happens, run `pixi run --environment release bump-my-version bump patch --dry-run --verbose`.
4. Push the commit and its tag:
```sh
git push --follow-tags
```
The pushed tag triggers `.gitea/workflows/release.yml`, which rebuilds from the tagged commit, checks that the tag matches the `Cargo.toml` version (the bump has just made them agree), and publishes a Gitea release with the packaged binary and its checksum attached.
A `v` prefix on the tag is tolerated if you ever tag by hand.
## The workflows
All three live in `.gitea/workflows/` and build through pixi, the same way the site deploy does, so the runner needs pixi rather than a hand-installed Rust toolchain.
Each workflow installs pixi if it is not already on the runner.
- `ci.yml` runs on every push to `main` and every pull request.
It runs `pixi run check`: formatting, clippy, the full test suite, and a docs build.
This is the gate.
- `nightly.yml` runs on every push to `main`, so the nightly build tracks the branch.
It also carries an optional daily `cron`.
It builds the binary and publishes it as a single rolling prerelease tagged `nightly`, replacing the previous one so the tag always points at the current tip.
- `release.yml` runs on a version tag.
It builds, regenerates the third-party license notices, packages the full bundle, and publishes a normal (non-prerelease) release named after the tag.
## Publishing the API docs
`.gitea/workflows/docs.yml` builds the rustdoc and publishes it in two channels: `release/`, built from a version tag, and `nightly/`, built from `main`.
The site root redirects to the latest release, falling back to nightly until the first release exists.
Each page carries a small switcher to flip between the two channels.
It runs on the `pixi-build-rust` runner, so the doc build reuses the baked toolchain and the crate cache rather than compiling cold.
That runner builds inside a container, so give its job containers access to the docs directory by adding it to the runner's `config.yaml` alongside the cache volumes.