name: Release PR
on:
push:
branches: [master]
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
jobs:
release-pr:
name: release-plz PR
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
concurrency:
group: release-plz-pr-${{ github.ref }}
cancel-in-progress: false
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Install Linux build deps
run: |
sudo apt-get update
sudo apt-get install -y \
libudev-dev pkg-config gcc g++ clang libssl-dev libzstd-dev
- name: Load GitHub App credentials from 1Password
id: load_secrets
uses: 1password/load-secrets-action@v4
with:
export-env: false
env:
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
GITHUB_APP_ID: ${{ secrets.OP_GITHUB_APP_ITEM }}/GITHUB_APP_ID
GITHUB_APP_PRIVATE_KEY: ${{ secrets.OP_GITHUB_APP_ITEM }}/GITHUB_APP_PRIVATE_KEY
CARGO_REGISTRY_TOKEN: ${{ secrets.OP_GITHUB_APP_ITEM }}/CARGO_REGISTRY_TOKEN
- name: Decode GitHub App private key
id: app_key
env:
APP_KEY_B64: ${{ steps.load_secrets.outputs.GITHUB_APP_PRIVATE_KEY }}
run: |
key="$(printf '%s' "$APP_KEY_B64" | tr -d '[:space:]' | base64 -d)"
{
echo 'pem<<__PEM__'
printf '%s\n' "$key"
echo '__PEM__'
} >> "$GITHUB_OUTPUT"
- name: Mint GitHub App token
id: app-token
uses: actions/create-github-app-token@v3
with:
client-id: ${{ steps.load_secrets.outputs.GITHUB_APP_ID }}
private-key: ${{ steps.app_key.outputs.pem }}
- name: Prune stale release-plz branches
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
REPO: ${{ github.repository }}
run: |
for branch in $(gh api "repos/$REPO/branches" --paginate --jq '.[].name' \
| grep '^release-plz-' || true); do
open=$(gh pr list --repo "$REPO" --head "$branch" --state open --json number --jq 'length')
if [ "$open" = "0" ]; then
echo "Pruning stale release branch: $branch"
gh api -X DELETE "repos/$REPO/git/refs/heads/$branch" \
|| echo "::warning::could not delete $branch"
else
echo "Keeping $branch (open PR exists)"
fi
done
- name: Run release-plz (release-pr)
id: release_pr
uses: release-plz/action@v0.5
with:
command: release-pr
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
CARGO_REGISTRY_TOKEN: ${{ steps.load_secrets.outputs.CARGO_REGISTRY_TOKEN }}
- name: Guard against a silently stalled release
if: steps.release_pr.outputs.prs_created == 'false'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
REPO: ${{ github.repository }}
run: |
# An already-open release PR is the normal "updated, not created" path.
open_release_pr=$(gh pr list --repo "$REPO" --state open --json headRefName \
--jq '[.[] | select(.headRefName | startswith("release-plz-"))] | length')
if [ "$open_release_pr" != "0" ]; then
echo "A release PR is already open — nothing to flag."
exit 0
fi
last_tag=$(git describe --tags --abbrev=0 --match 'v*' 2>/dev/null || true)
# The release job runs in parallel and cuts the `v{version}` tag only
# after publishing, so that tag is usually absent from this job's
# checkout — never trust the local tag list to decide "did a release
# just happen". Read the manifest instead: merging a release PR bumps
# the workspace version, so a manifest version ahead of the last tag
# means the release already landed (the parallel job is tagging it),
# not a stall. Only when the manifest still sits at the last released
# tag can leftover release-worthy commits mean a swallowed release-pr.
manifest_version=$(awk '
/^\[workspace\.package\]/ { in_section = 1; next }
/^\[/ { in_section = 0 }
in_section && /^version[[:space:]]*=/ {
gsub(/.*=[[:space:]]*"|".*/, ""); print; exit
}
' Cargo.toml)
if [ -n "$last_tag" ] && [ -n "$manifest_version" ] \
&& [ "v$manifest_version" != "$last_tag" ]; then
echo "Workspace version $manifest_version is ahead of $last_tag — a release PR already merged; the release job cuts the tag. Nothing to flag."
exit 0
fi
range="${last_tag:+$last_tag..}HEAD"
worthy=$(git log "$range" --format='%s' \
| grep -cE '^(feat|fix|perf)(\(.+\))?!?:|^[a-z]+(\(.+\))?!:' || true)
if [ "$worthy" != "0" ]; then
echo "::error::release-plz opened no release PR, but $worthy release-worthy commit(s) exist since ${last_tag:-repo start} and none is open — likely a swallowed release-plz failure (see the release-pr step)."
exit 1
fi
echo "No release PR and no release-worthy commits since ${last_tag:-repo start}; nothing to release."
release:
name: release-plz release
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: read
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Install Linux build deps
run: |
sudo apt-get update
sudo apt-get install -y \
libudev-dev pkg-config gcc g++ clang libssl-dev libzstd-dev
- name: Load GitHub App credentials from 1Password
id: load_secrets
uses: 1password/load-secrets-action@v4
with:
export-env: false
env:
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
GITHUB_APP_ID: ${{ secrets.OP_GITHUB_APP_ITEM }}/GITHUB_APP_ID
GITHUB_APP_PRIVATE_KEY: ${{ secrets.OP_GITHUB_APP_ITEM }}/GITHUB_APP_PRIVATE_KEY
CARGO_REGISTRY_TOKEN: ${{ secrets.OP_GITHUB_APP_ITEM }}/CARGO_REGISTRY_TOKEN
- name: Decode GitHub App private key
id: app_key
env:
APP_KEY_B64: ${{ steps.load_secrets.outputs.GITHUB_APP_PRIVATE_KEY }}
run: |
key="$(printf '%s' "$APP_KEY_B64" | tr -d '[:space:]' | base64 -d)"
{
echo 'pem<<__PEM__'
printf '%s\n' "$key"
echo '__PEM__'
} >> "$GITHUB_OUTPUT"
- name: Mint GitHub App token
id: app-token
uses: actions/create-github-app-token@v3
with:
client-id: ${{ steps.load_secrets.outputs.GITHUB_APP_ID }}
private-key: ${{ steps.app_key.outputs.pem }}
- name: Run release-plz (release)
uses: release-plz/action@v0.5
with:
command: release
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
CARGO_REGISTRY_TOKEN: ${{ steps.load_secrets.outputs.CARGO_REGISTRY_TOKEN }}