FlureeLabs

Releasing

Cutting a release is two phases: a release PR that bumps the version, then a tag pushed after the PR merges. The tag triggers cargo-dist, which builds binaries and publishes the GitHub Release. Release notes are auto-generated by GitHub from merged PR titles since the previous tag.

The flow

# 1. Branch off main and bump the workspace version.
git checkout main && git pull
git checkout -b release/v4.0.2
$EDITOR Cargo.toml                      # update [workspace.package].version
cargo update --workspace                # refresh Cargo.lock
git commit -am "release v4.0.2"
git push -u origin release/v4.0.2
gh pr create --title "release v4.0.2"

# 2. After the PR is reviewed and merged to main, tag the merge commit.
git checkout main && git pull
git tag v4.0.2
git push origin v4.0.2                  # ← triggers .github/workflows/release.yml

Watch the Actions tab. cargo-dist builds platform binaries, creates the GitHub Release with auto-generated notes, publishes the Homebrew formula, and pushes the multi-arch Docker image.

Why the two-phase split

cargo-dist's release workflow triggers on any pushed vX.Y.Z tag regardless of which branch the tag points at. Holding the tag step until after merge ensures every release goes through PR review.

How release notes are generated

.github/workflows/release.yml calls gh release create --generate-notes. GitHub builds the release body automatically from PRs merged since the previous tag, categorized per .github/release.yml:

LabelSection
breaking-change, semver:majorBreaking Changes
feature, enhancement, featFeatures
bug, fixBug Fixes
performance, perfPerformance
documentation, docsDocumentation
(anything else)Other Changes

Apply one of these labels to each PR before merging. Unlabeled PRs still appear under "Other Changes" with their full title and author credit, so categorization is nice-to-have, not required.

PR titles already follow the feat: / fix: / docs: convention from CLAUDE.md, which makes the unlabeled "Other Changes" list readable on its own.

Rolling back

During Phase 1, before pushing:

git checkout main
git branch -D release/vX.Y.Z

After the release PR is opened but before merge:

Close the PR and delete the branch on GitHub. Nothing has shipped.

After the tag is pushed but cargo-dist still running:

git push origin :refs/tags/vX.Y.Z       # delete the remote tag
git tag -d vX.Y.Z                       # delete the local tag

Cancel the in-progress Release workflow run from the Actions tab.

After cargo-dist created the GitHub Release:

Delete the GitHub Release from the UI, then delete the tag (commands above). The merge commit on main stays in place — re-tag it once the issue is fixed, or supersede it with another release PR.

Configuration files

  • .github/release.yml — categorization for GitHub's auto-generated release notes.
  • dist-workspace.toml — cargo-dist's distribution targets and installers.
  • .github/workflows/release.yml — autogenerated by cargo-dist (with allow-dirty = ["ci"] set so our --generate-notes edit survives dist init).