name: Release
on:
push:
tags: ['v*']
permissions:
contents: write id-token: write
concurrency:
group: release-${{ github.repository }}
cancel-in-progress: false
jobs:
gate:
uses: paiml/infra/.github/workflows/clean-room-gate.yml@ba2f56a7d9f421feef737b6b642b644bcdaba567 with:
repo: ${{ github.event.repository.name }}
pr_sha: ${{ github.sha }}
secrets: inherit
verify:
needs: gate
runs-on: [self-hosted, clean-room]
outputs:
crate_name: ${{ steps.parse.outputs.crate_name }}
version: ${{ steps.parse.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Parse tag and verify version
id: parse
run: |
TAG="${GITHUB_REF_NAME}"
# Parse tag format: v1.0.0 or v-cratename-1.0.0
if [[ "$TAG" =~ ^v-([a-z][a-z0-9_-]*)-([0-9]+\..+)$ ]]; then
CRATE_NAME="${BASH_REMATCH[1]}"
TAG_VER="${BASH_REMATCH[2]}"
echo "Workspace release: crate=$CRATE_NAME version=$TAG_VER"
elif [[ "$TAG" =~ ^v([0-9]+\..+)$ ]]; then
CRATE_NAME=""
TAG_VER="${BASH_REMATCH[1]}"
echo "Single-crate release: version=$TAG_VER"
else
echo "::error::Tag '$TAG' does not match expected format (v1.0.0 or v-crate-1.0.0)"
exit 1
fi
# Use cargo metadata for reliable version extraction
if [ -n "$CRATE_NAME" ]; then
CARGO_VER=$(cargo metadata --format-version 1 --no-deps \
| jq -r ".packages[] | select(.name == \"$CRATE_NAME\") | .version")
if [ -z "$CARGO_VER" ] || [ "$CARGO_VER" = "null" ]; then
echo "::error::Crate '$CRATE_NAME' not found in workspace"
exit 1
fi
else
CARGO_VER=$(cargo metadata --format-version 1 --no-deps \
| jq -r '.packages[0].version')
fi
if [ "$TAG_VER" != "$CARGO_VER" ]; then
echo "::error::Tag version $TAG_VER != Cargo.toml version $CARGO_VER"
exit 1
fi
echo "crate_name=$CRATE_NAME" >> "$GITHUB_OUTPUT"
echo "version=$TAG_VER" >> "$GITHUB_OUTPUT"
echo "Version verified: $TAG_VER"
- name: Verify package tarball
run: |
CRATE="${{ steps.parse.outputs.crate_name }}"
if [ -n "$CRATE" ]; then
cargo package --verify -p "$CRATE"
else
cargo package --verify
fi
publish:
needs: verify
runs-on: [self-hosted, clean-room]
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Authenticate to crates.io (OIDC)
uses: rust-lang/crates-io-auth-action@b7e9a28eded4986ec6b1fa40eeee8f8f165559ec
- name: Publish
run: |
CRATE="${{ needs.verify.outputs.crate_name }}"
if [ -n "$CRATE" ]; then
cargo publish -p "$CRATE"
else
cargo publish
fi
- name: Create GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "$GITHUB_REF_NAME" \
--title "$GITHUB_REF_NAME" \
--generate-notes