name: Release
run-name: Release ${{ github.ref_name }}
on:
push:
tags:
- "v*"
concurrency:
group: release
cancel-in-progress: false
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
jobs:
validate-version:
name: Validate Version Tag
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v5
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Validate tag against Cargo.toml
id: version
run: |
TAG="${GITHUB_REF_NAME}"
TAG_VERSION="${TAG#v}"
CARGO_VERSION=$(cargo metadata --no-deps --format-version=1 \
| jq -r '.packages[] | select(.name == "boostr") | .version')
CARGO_BASE=$(echo "$CARGO_VERSION" | grep -oP '^\d+\.\d+\.\d+')
echo "Tag version: $TAG_VERSION"
echo "Cargo.toml version: $CARGO_VERSION"
echo "Cargo.toml base: $CARGO_BASE"
if [[ ! "$TAG_VERSION" =~ ^([0-9]+\.[0-9]+\.[0-9]+)(-[a-zA-Z]+\.[0-9]+)?$ ]]; then
echo "::error::Invalid tag format '$TAG'. Expected: vX.Y.Z or vX.Y.Z-label.N"
exit 1
fi
TAG_BASE="${BASH_REMATCH[1]}"
if [[ "$TAG_BASE" != "$CARGO_BASE" ]]; then
echo "::error::Base version mismatch! Tag '$TAG_BASE' != Cargo.toml '$CARGO_BASE'"
exit 1
fi
echo "version=$TAG_VERSION" >> $GITHUB_OUTPUT
ci:
name: CI
needs: validate-version
uses: ./.github/workflows/test.yml
publish:
name: Publish to crates.io
needs: [validate-version, ci]
runs-on: ubuntu-latest
environment: crates-io
steps:
- uses: actions/checkout@v5
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Set version from tag (if needed)
run: |
VERSION="${{ needs.validate-version.outputs.version }}"
CURRENT=$(cargo metadata --no-deps --format-version=1 | jq -r '.packages[] | select(.name == "boostr") | .version')
if [[ "$VERSION" != "$CURRENT" ]]; then
sed -i "0,/^version = \".*\"/s//version = \"$VERSION\"/" Cargo.toml
echo "Updated Cargo.toml: $CURRENT -> $VERSION"
else
echo "Version already matches, no change needed"
fi
- name: Dry run
run: cargo publish --dry-run --allow-dirty
- name: Publish to crates.io
run: cargo publish --allow-dirty
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}