name: Release
on:
push:
tags:
- "v*"
permissions:
contents: write
jobs:
validate:
name: Validate release tag
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Install Rust (stable)
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
profile: minimal
components: clippy, rustfmt
- name: Cache cargo registry + build
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }}
- name: Run release preflight
run: ./scripts/release-check.sh
publish:
name: Publish crate and GitHub release
runs-on: ubuntu-latest
needs: validate
steps:
- name: Checkout sources
uses: actions/checkout@v4
- name: Install Rust (stable)
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
profile: minimal
- name: Verify tag matches crate version
shell: bash
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME}"
crate_version=$(awk '
/^\[package\]$/ { in_package=1; next }
/^\[/ && in_package { exit }
in_package && $1 == "version" {
gsub(/"/, "", $3);
print $3;
exit
}
' Cargo.toml)
if [[ -z "${crate_version}" ]]; then
echo "Unable to read package version from Cargo.toml" >&2
exit 1
fi
if [[ "${tag}" != "v${crate_version}" ]]; then
echo "Tag ${tag} does not match crate version v${crate_version}" >&2
exit 1
fi
- name: Cargo publish (dry-run)
run: cargo publish --dry-run
- name: Cargo publish
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: cargo publish
- name: Build release notes from changelog
shell: bash
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME#v}"
awk -v version="${tag}" '
BEGIN { in_section=0 }
$0 ~ "^## \\[" version "\\]" { in_section=1; next }
/^## \[/ && in_section { exit }
in_section { print }
' CHANGELOG.md > release-notes.md
if [[ ! -s release-notes.md ]]; then
echo "No changelog section found for ${tag}" >&2
exit 1
fi
- name: Create GitHub release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
body_path: release-notes.md
draft: false
prerelease: false