Releases are driven by Conventional Commits on develop and git-cliff, via three workflows in .github/workflows/ (thin wrappers around the rust-* reusable workflows in pilgrimagesoftware/github-actions).
There's no manual version bumping or changelog editing.
Because of this, squash-merging a feature PR into develop must preserve the original commit's Conventional Commits type and any !/BREAKING CHANGE: marker.
GitHub's default squash message is the PR title, which usually drops both — git-cliff then can't classify the squashed commit, silently produces an empty/no-op changelog section, and under-bumps the version.
Set the squash subject explicitly, e.g. gh pr merge <n> --squash --subject "feat!: <description>", or merge with a merge commit instead when the PR is a single already-well-formed commit.
Trigger Prepare Release manually (Actions tab → Prepare Release → Run workflow). It:
- Runs
git-cliff --bumped-versionagainstdevelopto compute the next version from commits since the last tag (fix:→ patch,feat:→ minor, a!orBREAKING CHANGE:footer → major). - Bumps
Cargo.tomlto that version and prepends the generated section toCHANGELOG.md. - Pushes a
release/<version>branch and opens (or updates, if one is already open) a PR from it intomaster, labeledreleaseand requesting review.
If it fails with "nothing to release," either no feat:/fix:/etc. commits have landed on develop since the last tag, or no tag exists yet for git-cliff to compute a version relative to — see the workflow's error output for which.
Check the generated CHANGELOG.md section and the version bump on the PR.
Fix anything wrong by pushing to the release/<version> branch directly (or re-running Prepare Release, which force-pushes and updates the same PR).
Merge into master once CI passes.
Merging the release PR triggers Tag Release, which tags master as v<version>.
The tag push triggers Release, which:
- Re-runs the test suite against the tagged commit.
- Publishes to crates.io.
- Cuts a GitHub Release with that tag's changelog section as the release notes.
- Merges
masterback intodevelopso the version bump and changelog aren't lost on the next release cycle.
Publishing uses crates.io OIDC trusted publishing (rust-lang/crates-io-auth-action, via release.yaml's trusted-publishing: true input) — no long-lived token in CI.
This only became possible after the crate existed on crates.io (bootstrapped by a one-time publish with the CRATES_API_KEY token for v0.1.0), then configuring fulltime-plugin-api as a trusted publisher on crates.io.
The CRATES_API_KEY repo secret is no longer used by release.yaml and can be removed.
If Release needs to be re-run for an existing tag (e.g. crates.io publish failed after the GitHub Release was already cut), trigger it manually with the tag input set to the existing vX.Y.Z tag rather than pushing a new tag.