name: Release (Cargo Workspaces)
on:
workflow_dispatch:
inputs:
release_type:
description: "Semver bump level for the release."
required: true
type: choice
options: [patch, minor, major]
dry_run:
description: "Set to true to simulate the release (no push or actual publish)."
required: false
default: false
type: boolean
skip_commit:
description: "If true, skip version bump commit (assume versions already updated)."
required: false
default: false
type: boolean
permissions:
contents: write
packages: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Configure Git user
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Configure SSL and cargo credentials
run: |
# Ensure SSL certificates are properly set up
echo "Setting up SSL certificates..."
sudo update-ca-certificates --fresh || true
# Set up cargo credentials
echo "Setting up cargo credentials..."
mkdir -p ~/.cargo
echo "[registry]" > ~/.cargo/credentials.toml
echo "token = \"${{ secrets.CRATES_IO_TOKEN }}\"" >> ~/.cargo/credentials.toml
chmod 600 ~/.cargo/credentials.toml
- name: Cache cargo build
uses: Swatinem/rust-cache@v2
- name: Install cargo-workspaces
uses: taiki-e/install-action@v2
with:
tool: cargo-workspaces
- name: Bump version and tag commit
if: ${{ inputs.skip_commit != 'true' }}
run: |
# Run version bump with exact version pins for dependencies
cargo workspaces version ${{ inputs.release_type }} \
--yes --allow-branch main \
--exact \
--no-git-push \
${{ inputs.dry_run == 'true' && '--dry-run' || '' }}
env:
CARGO_NET_EMPTY_VERSION_REPLACE: "true"
NODE_EXTRA_CA_CERTS: /etc/ssl/certs/ca-certificates.crt
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
- name: Tag existing commit (skip version bump)
if: ${{ inputs.skip_commit == 'true' }}
run: |
# Determine version for tagging (assuming a workspace with unified version)
VERSION=$(cargo metadata --no-deps --format-version=1 | jq -r '.packages[0].version')
git tag -a "v${VERSION}" -m "Release v${VERSION}"
echo "Tagged current commit with v${VERSION}"
- name: Push changes to GitHub
if: ${{ inputs.dry_run != 'true' }}
env:
TAG_REF: "refs/tags/$(git tag --sort=-creatordate -l | head -n1)"
run: |
echo "Pushing new commit to origin..."
git push origin HEAD:${{ github.ref_name }} # Push the new commit to the current branch
echo "Pushing tags to origin..."
git push origin --tags || {
echo "Tag push failed (tag may already exist). Forcing tag update...";
git push origin --tags --force; # Force-push tags if a conflict (existing tag) is detected
}
- name: Publish to crates.io
if: ${{ inputs.dry_run != 'true' }}
env:
CARGO_REGISTRIES_CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
NODE_EXTRA_CA_CERTS: /etc/ssl/certs/ca-certificates.crt
run: |
# Use --from-git to publish based on existing tags (skip versioning step)
# With publish = false set for subcrates, only the main crate will be published.
cargo workspaces publish \
--from-git \
--yes \
--allow-branch main \
--token "${{ secrets.CRATES_IO_TOKEN }}" \
--no-verify \
${{ inputs.dry_run == 'true' && '--dry-run' || '' }}