name: Release
on:
push:
branches: [main]
env:
CARGO_TERM_COLOR: always
permissions:
contents: write
jobs:
check-version:
name: Check for version bump
runs-on: ubuntu-latest
outputs:
should_release: ${{ steps.check.outputs.should_release }}
version: ${{ steps.check.outputs.version }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
fetch-tags: true
- name: Check if version tag exists
id: check
run: |
VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
if git tag -l "v$VERSION" | grep -q "v$VERSION"; then
echo "Tag v$VERSION already exists, skipping release"
echo "should_release=false" >> "$GITHUB_OUTPUT"
else
echo "Tag v$VERSION does not exist, proceeding with release"
echo "should_release=true" >> "$GITHUB_OUTPUT"
fi
release:
name: Publish and tag
needs: check-version
if: needs.check-version.outputs.should_release == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- uses: Swatinem/rust-cache@v2
- name: cargo check
run: cargo check --locked
- name: cargo test
run: cargo test --locked
- name: cargo test (no default features)
run: cargo test --locked --no-default-features
- name: cargo clippy
run: cargo clippy --locked --all-targets -- -D warnings
- uses: taiki-e/install-action@cargo-deny
- name: cargo deny check licenses
run: cargo deny check licenses
- name: Publish to crates.io
run: |
set -o pipefail
# Capture output so we can distinguish "already exists" from real failures.
if OUTPUT=$(cargo publish 2>&1); then
echo "$OUTPUT"
else
echo "$OUTPUT"
if echo "$OUTPUT" | grep -q "already exists on crates.io"; then
echo "::warning::Version already published to crates.io, skipping"
else
exit 1
fi
fi
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
- name: Create git tag
run: |
git tag "v${{ needs.check-version.outputs.version }}"
git push origin "v${{ needs.check-version.outputs.version }}"
- name: Create GitHub release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.check-version.outputs.version }}
name: v${{ needs.check-version.outputs.version }}
generate_release_notes: true