name: Publish to crates.io
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag_name:
description: 'Tag to publish (e.g. v0.1.0). If empty, uses the current ref.'
required: false
type: string
permissions:
contents: write
jobs:
validate:
name: Validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Verify tag matches Cargo.toml version
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
INPUT_TAG: ${{ inputs.tag_name }}
run: |
if [ "$EVENT_NAME" == "workflow_dispatch" ] && [ -n "$INPUT_TAG" ]; then
TAG_NAME="$INPUT_TAG"
else
TAG_NAME="${GITHUB_REF#refs/tags/}"
fi
TAG_VERSION="${TAG_NAME#v}"
CARGO_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
echo "Tag version: $TAG_VERSION"
echo "Cargo version: $CARGO_VERSION"
if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
echo "Error: tag $TAG_VERSION does not match Cargo.toml $CARGO_VERSION"
exit 1
fi
- name: Verify CHANGELOG.md has entry for this version
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
INPUT_TAG: ${{ inputs.tag_name }}
run: |
if [ "$EVENT_NAME" == "workflow_dispatch" ] && [ -n "$INPUT_TAG" ]; then
TAG_NAME="$INPUT_TAG"
else
TAG_NAME="${GITHUB_REF#refs/tags/}"
fi
VERSION="${TAG_NAME#v}"
if ! grep -q "^## \[$VERSION\]" CHANGELOG.md; then
echo "Error: No entry for version $VERSION found in CHANGELOG.md"
exit 1
fi
echo "CHANGELOG.md entry found for $VERSION"
ci:
name: CI
needs: validate
uses: ./.github/workflows/ci.yml
publish:
name: Publish
needs: ci
runs-on: windows-latest
environment: publish
steps:
- uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo
uses: Swatinem/rust-cache@v2
- name: Publish to crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: cargo publish --all-features
release:
name: GitHub Release
needs: publish
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate Release Notes
id: notes
uses: ./.github/actions/generate-release-notes
with:
tag_name: ${{ inputs.tag_name || github.ref_name }}
- name: Detect Pre-release
id: check-pre
shell: bash
env:
REF_NAME: ${{ inputs.tag_name || github.ref_name }}
run: |
if [[ "$REF_NAME" =~ (alpha|beta|rc|preview) ]]; then
echo "is_prerelease=true" >> $GITHUB_OUTPUT
else
echo "is_prerelease=false" >> $GITHUB_OUTPUT
fi
- name: Create GitHub Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ inputs.tag_name || github.ref_name }}
NOTES: ${{ steps.notes.outputs.release_body }}
PRERELEASE: ${{ steps.check-pre.outputs.is_prerelease }}
run: |
PRERELEASE_FLAG=""
if [ "$PRERELEASE" = "true" ]; then
PRERELEASE_FLAG="--prerelease"
fi
gh release create "$TAG" \
--title "$TAG" \
--notes "$NOTES" \
--draft \
$PRERELEASE_FLAG