name: Prepare Release
on:
workflow_dispatch:
inputs:
version_bump:
description: Version bump type
required: true
default: patch
type: choice
options:
- patch
- minor
- major
custom_version:
description: Custom version (optional, overrides version_bump if provided)
required: false
type: string
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
jobs:
prepare-release:
name: Prepare Release PR
runs-on: ubuntu-latest
steps:
- name: Refuse to release anything but main
if: github.ref != 'refs/heads/main'
run: |
echo "::error::Releases start from main, not $GITHUB_REF_NAME"
exit 1
- uses: actions/checkout@v4
- name: Install Rust (nightly-2026-10-07)
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2026-10-07
- name: Bump the version
id: bump
env:
VERSION_BUMP: ${{ inputs.version_bump }}
CUSTOM_VERSION: ${{ inputs.custom_version }}
run: |
package_version() {
cargo metadata --no-deps --format-version 1 \
| jq -r '.packages[] | select(.name == "bbtree") | .version'
}
current=$(package_version)
if [ -n "$CUSTOM_VERSION" ]; then
next=$CUSTOM_VERSION
elif [[ "$current" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
IFS=. read -r major minor patch <<< "$current"
case "$VERSION_BUMP" in
major) next="$((major + 1)).0.0" ;;
minor) next="$major.$((minor + 1)).0" ;;
patch) next="$major.$minor.$((patch + 1))" ;;
esac
else
echo "::error::Can't bump $current, which isn't MAJOR.MINOR.PATCH; give a custom version"
exit 1
fi
sed -i "s/^version = \"$current\"$/version = \"$next\"/" Cargo.toml
if [ "$(package_version)" != "$next" ]; then
echo "::error::Cargo.toml says version $(package_version), not $next"
exit 1
fi
# The root's lockfile, and those of the workspaces that depend on
# the library by path.
for lockfile in $(git ls-files '*Cargo.lock'); do
cargo update --package bbtree --manifest-path "$(dirname "$lockfile")/Cargo.toml"
done
echo "version=$next" >> "$GITHUB_OUTPUT"
- name: Create Pull Request
id: pull-request
uses: peter-evans/create-pull-request@v8
with:
token: ${{ secrets.PAT_TOKEN }}
branch: release/v${{ steps.bump.outputs.version }}
title: "chore: release v${{ steps.bump.outputs.version }}"
body: |
## Release v${{ steps.bump.outputs.version }}
This PR bumps the version to `${{ steps.bump.outputs.version }}`. A change of version is a release, so CI runs the release checks on it besides the usual ones: half an hour of fuzzing, and the package.
---
**Once the merge gate passes**, this PR merges itself, and the `publish.yml` workflow will:
1. Publish the crate to crates.io
2. Create a GitHub Release with tag `v${{ steps.bump.outputs.version }}`
commit-message: "chore: release v${{ steps.bump.outputs.version }}"
labels: release
delete-branch: true
- name: Merge once the merge gate passes
env:
GH_TOKEN: ${{ secrets.PAT_TOKEN }}
PULL_REQUEST: ${{ steps.pull-request.outputs.pull-request-number }}
run: gh pr merge "$PULL_REQUEST" --repo "$GITHUB_REPOSITORY" --auto --squash