name: Publish Crate
on:
release:
types: [prereleased, released]
permissions:
contents: read
concurrency:
group: publish-${{ github.event.release.tag_name }}
cancel-in-progress: false
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo
uses: Swatinem/rust-cache@v2
- name: Normalize version from release tag
id: version
shell: bash
run: |
set -euo pipefail
RAW_TAG="${{ github.event.release.tag_name }}"
IS_PRERELEASE="${{ github.event.release.prerelease }}"
VERSION="$RAW_TAG"
BASE_VERSION="${VERSION%%-*}"
RC_SUFFIX="$(TZ=Asia/Shanghai date +%y%m%d%H)"
if [[ ! "$RAW_TAG" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.-]+)?$ ]]; then
echo "Release tag must start with a semantic version like 0.1.0: $RAW_TAG"
exit 1
fi
if [[ ! "$BASE_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Release base version must match x.y.z: $BASE_VERSION"
exit 1
fi
if [[ "$IS_PRERELEASE" == "true" ]]; then
if [[ "$VERSION" =~ -(alpha|beta|rc)(\.[0-9A-Za-z-]+)*$ ]]; then
NORMALIZED_VERSION="$VERSION"
else
NORMALIZED_VERSION="${BASE_VERSION}-rc.${RC_SUFFIX}"
fi
else
if [[ "$VERSION" == *-* ]]; then
echo "Stable release tags must not contain a suffix: $VERSION"
exit 1
fi
NORMALIZED_VERSION="$BASE_VERSION"
fi
echo "normalized_version=$NORMALIZED_VERSION" >> "$GITHUB_OUTPUT"
echo "Using crate version: $NORMALIZED_VERSION"
- name: Update Cargo.toml version
shell: bash
run: |
set -euo pipefail
VERSION="${{ steps.version.outputs.normalized_version }}"
sed -i -E "0,/^version = \".*\"$/s//version = \"$VERSION\"/" Cargo.toml
grep -n '^version = ' Cargo.toml
- name: Run tests
run: cargo test
- name: Package crate
run: cargo package --allow-dirty
- name: Publish to crates.io
run: cargo publish --allow-dirty
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}