name: Release
on:
push:
branches:
- dev
workflow_dispatch:
inputs:
version:
description: Optional explicit release version (defaults to the next patch version)
required: false
type: string
permissions:
contents: write
id-token: write
pull-requests: read
concurrency:
group: release-dev
cancel-in-progress: false
jobs:
release:
runs-on: windows-latest
timeout-minutes: 90
environment: release
env:
CARGO_TERM_PROGRESS_WHEN: never
GH_TOKEN: ${{ github.token }}
steps:
- name: Checkout dev
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with:
fetch-depth: 0
persist-credentials: false
ref: dev
- name: Detect release-worthy dependency merge
id: release_context
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 with:
github-token: ${{ github.token }}
script: |
if (context.eventName === 'workflow_dispatch') {
core.setOutput('should_release', 'true');
core.setOutput('reason', 'manual');
return;
}
const message = context.payload.head_commit?.message ?? '';
const subject = message.split('\n', 1)[0] ?? '';
const match = subject.match(/\(#(\d+)\)$/);
if (!match) {
core.setOutput('should_release', 'false');
core.setOutput('reason', 'no-pr-number-in-subject');
return;
}
const prNumber = Number(match[1]);
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
});
if (
!pr.merged ||
pr.base.ref !== 'dev' ||
pr.user.login !== 'dependabot[bot]' ||
!pr.head.ref.startsWith('dependabot/cargo/')
) {
core.setOutput('should_release', 'false');
core.setOutput('reason', 'no-matching-pr');
return;
}
core.setOutput('should_release', 'true');
core.setOutput('reason', `dependabot-pr-${prNumber}`);
- name: Stop when this push is not a cargo Dependabot merge
if: steps.release_context.outputs.should_release != 'true'
shell: bash
run: |
set -euo pipefail
echo "Skipping release: ${{ steps.release_context.outputs.reason }}"
- name: Configure authenticated origin
if: steps.release_context.outputs.should_release == 'true'
shell: bash
run: |
set -euo pipefail
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
- name: Reattach local dev branch
if: steps.release_context.outputs.should_release == 'true'
shell: bash
run: |
set -euo pipefail
git checkout -B dev origin/dev
- name: Configure git author
if: steps.release_context.outputs.should_release == 'true'
shell: bash
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Install Rust toolchain (nightly)
if: steps.release_context.outputs.should_release == 'true'
uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
with:
toolchain: nightly
components: rustfmt, clippy
- name: Rust cache
if: steps.release_context.outputs.should_release == 'true'
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4
- name: Authenticate to crates.io with trusted publishing
if: steps.release_context.outputs.should_release == 'true'
id: crates_auth
continue-on-error: true
uses: rust-lang/crates-io-auth-action@bbd81622f20ce9e2dd9622e3218b975523e45bbe
- name: Verify crates.io token source
if: steps.release_context.outputs.should_release == 'true'
shell: pwsh
env:
CARGO_REGISTRY_TOKEN: ${{ steps.crates_auth.outputs.token || secrets.CARGO_REGISTRY_TOKEN }}
run: |
$ErrorActionPreference = 'Stop'
if (-not $env:CARGO_REGISTRY_TOKEN) {
throw 'No crates.io token source is available. Configure trusted publishing for this crate or add the CARGO_REGISTRY_TOKEN secret to the release environment.'
}
- name: Run release automation
if: steps.release_context.outputs.should_release == 'true'
shell: pwsh
env:
CARGO_REGISTRY_TOKEN: ${{ steps.crates_auth.outputs.token || secrets.CARGO_REGISTRY_TOKEN }}
RELEASE_VERSION: ${{ inputs.version }}
run: |
$ErrorActionPreference = 'Stop'
$version = ($env:RELEASE_VERSION ?? '').Trim()
if ($version) {
& pwsh -ExecutionPolicy Bypass -NoLogo -NoProfile -File .\scripts\release\release.ps1 $version
} else {
& pwsh -ExecutionPolicy Bypass -NoLogo -NoProfile -File .\scripts\release\release.ps1
}