name: Release
on:
push:
tags:
- "v*.*.*"
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-D warnings"
jobs:
verify-tag:
name: verify tag matches Cargo.toml
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check tag matches Cargo.toml version
run: |
tag="${GITHUB_REF#refs/tags/v}"
cargo_version=$(grep '^version' Cargo.toml | head -1 | sed -E 's/.*"(.+)".*/\1/')
if [ "$tag" != "$cargo_version" ]; then
echo "::error::Tag v$tag does not match Cargo.toml version $cargo_version"
exit 1
fi
echo "Tag v$tag matches Cargo.toml version $cargo_version"
test:
name: full test suite
runs-on: ubuntu-latest
needs: verify-tag
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: cargo test --locked --all-targets --all-features
- run: cargo test --locked --doc --all-features
publish:
name: publish to crates.io
runs-on: ubuntu-latest
needs: test
environment: crates-io
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: cargo publish (skip if version already on crates.io)
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
run: |
version="${GITHUB_REF#refs/tags/v}"
# crates.io returns 200 for an existing crate@version, 404 if
# not yet published. A User-Agent is required or it 403s.
# This makes a manual first publish + tag push idempotent:
# 0.1.0 published from a workstation, later 0.1.x cut by CI.
code=$(curl -sSL -o /dev/null -w '%{http_code}' \
-H 'User-Agent: simulacra-release-ci (https://github.com/jbravar/simulacra)' \
"https://crates.io/api/v1/crates/simulacra/${version}")
if [ "$code" = "200" ]; then
echo "simulacra ${version} is already on crates.io — skipping publish."
else
echo "simulacra ${version} not found (HTTP ${code}) — publishing."
cargo publish --locked
fi