name: Release
on:
push:
tags:
- 'v[0-9]+.*'
workflow_dispatch:
inputs:
version:
description: 'Version to release (e.g., v0.2.0)'
required: true
type: string
concurrency:
group: release
cancel-in-progress: false
env:
CARGO_TERM_COLOR: always
jobs:
validate:
name: Validate Release
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get version
id: version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
VERSION="${{ github.event.inputs.version }}"
else
VERSION="${GITHUB_REF#refs/tags/}"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Releasing version: $VERSION"
- name: Validate version format
run: |
VERSION="${{ steps.version.outputs.version }}"
if ! echo "$VERSION" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$'; then
echo "Invalid version format: $VERSION"
echo "Expected format: v0.0.0 or v0.0.0-alpha.1"
exit 1
fi
- uses: dtolnay/rust-toolchain@stable
- name: Check Cargo.toml version matches tag
run: |
CARGO_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
TAG_VERSION="${{ steps.version.outputs.version }}"
TAG_VERSION="${TAG_VERSION#v}" # Remove 'v' prefix
if [ "$CARGO_VERSION" != "$TAG_VERSION" ]; then
echo "Version mismatch!"
echo "Cargo.toml: $CARGO_VERSION"
echo "Git tag: $TAG_VERSION"
exit 1
fi
echo "Version match confirmed: $CARGO_VERSION"
test:
name: Test Suite
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
- name: Run all checks
run: |
cargo fmt --all -- --check &
cargo clippy --all-features -- -D warnings &
cargo test --all-features &
wait
changelog:
name: Generate Changelog
needs: validate
runs-on: ubuntu-latest
outputs:
changelog: ${{ steps.changelog.outputs.changelog }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install git-cliff
uses: taiki-e/install-action@git-cliff
- name: Generate changelog
id: changelog
run: |
# Generate changelog for this release only
CHANGELOG=$(git cliff --current --strip header)
# Handle multiline output
echo "changelog<<EOF" >> $GITHUB_OUTPUT
echo "$CHANGELOG" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Update CHANGELOG.md
run: git cliff --output .github/CHANGELOG.md
- name: Upload changelog artifact
uses: actions/upload-artifact@v4
with:
name: changelog
path: .github/CHANGELOG.md
release:
name: Create Release
needs: [validate, test, changelog]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Download changelog
uses: actions/download-artifact@v4
with:
name: changelog
path: .github/
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.validate.outputs.version }}
name: ${{ needs.validate.outputs.version }}
body: ${{ needs.changelog.outputs.changelog }}
draft: false
prerelease: ${{ contains(needs.validate.outputs.version, '-') }}
generate_release_notes: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}