Skip to content

Release Please

Release Please #769

# Opens/updates the release PR on every push to main, and when a release is
# created (release PR merged), ensures the cargo-dist Release workflow runs
# for the new tag. App-token tags fire on.push.tags; dispatch-release only
# workflow_dispatches when no healthy tag-push Release exists (#1380).
# See ci-build-release skill (App-token dual Release runs).
#
# Why a separate file: the cargo-dist Release workflow historically only ran
# on tags and, after adding branches: [main], still recorded zero push events
# (issue #785). A minimal dedicated workflow matches the official
# release-please pattern and is reliable on push.
name: Release Please
# Why schedule exists: merges performed by github-actions (auto-merge with GITHUB_TOKEN) do not create new workflow runs. Human merges and this hourly cron still run release-please.
on:
push:
branches: [main]
# GITHUB_TOKEN merges (auto-approve + auto-merge) do not trigger push workflows.
# Hourly catch-up opens/updates the release PR when human merges were not used.
# See issue #785.
schedule:
- cron: "17 * * * *"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: release-please-${{ github.ref }}
cancel-in-progress: false
jobs:
release-please:
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
contents: write
pull-requests: write
outputs:
release_created: ${{ steps.rp.outputs.release_created }}
tag_name: ${{ steps.rp.outputs.tag_name }}
pr: ${{ steps.rp.outputs.pr }}
steps:
- name: Harden runner
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
with:
egress-policy: audit
- uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
id: app-token
with:
client-id: ${{ vars.AUTO_APPROVE_CLIENT_ID }}
private-key: ${{ secrets.AUTO_APPROVE_PRIVATE_KEY }}
# Least privilege for release-please (tags, releases, PRs).
permission-contents: write
permission-pull-requests: write
- uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0
id: rp
with:
token: ${{ steps.app-token.outputs.token }}
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
# After release-please opens/updates the PR: align path-dep version pins
# and Cargo.lock workspace member versions so CI --locked stays green.
# release-type "simple" + workspace.package.version does NOT update the lock
# (unlike release-type "rust" on a single root package, e.g. patchloom).
sync-release-pr-versions:
needs: [release-please]
if: >-
needs.release-please.outputs.release_created != 'true' &&
needs.release-please.outputs.pr != ''
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
contents: write
steps:
- name: Harden runner
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
with:
egress-policy: audit
- name: Get PR branch
id: pr-branch
env:
PR_JSON: ${{ needs.release-please.outputs.pr }}
run: |
branch=$(echo "$PR_JSON" | jq -r .headBranchName)
echo "branch=$branch" >> "$GITHUB_OUTPUT"
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
ref: ${{ steps.pr-branch.outputs.branch }}
persist-credentials: false
- uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
- name: Sync path-dep versions
run: bash scripts/sync-path-dep-versions.sh
- name: Sync Cargo.lock workspace package versions
run: bash scripts/sync-cargo-lock-workspace-versions.sh
- name: Commit and push if changed
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if git diff --quiet; then
echo "path-dep versions and Cargo.lock already aligned"
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add crates/*/Cargo.toml Cargo.lock
git commit -s -m "chore: sync path-dep versions and Cargo.lock with workspace version"
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
git push
# Dispatch cargo-dist Release when a release is created.
#
# Historical note: pure GITHUB_TOKEN tags do not fire on.push.tags, so
# dispatch was required. This workflow uses a GitHub App token (identity
# separation for auto-approve), and App-token tags DO fire tag-push. Always
# dispatching then doubles multi-arch cargo-dist + publish (#1380 / v0.4.0).
#
# Policy: prefer the tag-push Release when it already exists (queued,
# in progress, or successful). Only workflow_dispatch when no healthy
# tag-push run appears (GITHUB_TOKEN-only tags, or tag-push failure).
# Manual re-runs: `gh workflow run Release -f tag=vX.Y.Z` still works alone.
dispatch-release:
needs: [release-please]
if: needs.release-please.outputs.release_created == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 5
permissions:
actions: write
contents: read
steps:
- name: Harden runner
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
with:
egress-policy: audit
- name: Dispatch cargo-dist Release workflow (if needed)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ needs.release-please.outputs.tag_name }}
run: |
set -euo pipefail
if [[ -z "${TAG}" ]]; then
echo "No tag_name from release-please; refusing to dispatch." >&2
exit 1
fi
# Tag-push registration can lag a few seconds after App-token tag create.
existing=""
for attempt in 1 2 3 4 5 6; do
existing="$(
gh run list --workflow=Release --repo "${GITHUB_REPOSITORY}" --limit 30 \
--json databaseId,event,status,conclusion,headBranch \
--jq ".[]
| select(
.event == \"push\"
and .headBranch == \"${TAG}\"
and (
.status == \"queued\"
or .status == \"waiting\"
or .status == \"pending\"
or .status == \"in_progress\"
or (.status == \"completed\" and .conclusion == \"success\")
)
)
| .databaseId" \
| head -n 1 || true
)"
if [[ -n "${existing}" ]]; then
break
fi
if [[ "${attempt}" -lt 6 ]]; then
echo "No healthy tag-push Release for ${TAG} yet (attempt ${attempt}/6); waiting 10s..."
sleep 10
fi
done
if [[ -n "${existing}" ]]; then
echo "Tag-push Release already covers ${TAG} (run ${existing}); skipping workflow_dispatch (#1380)."
exit 0
fi
echo "No healthy tag-push Release for ${TAG}; dispatching from main (GITHUB_TOKEN fallback or failed tag-push)."
gh workflow run Release --repo "${GITHUB_REPOSITORY}" --ref main -f "tag=${TAG}"
# verified push trigger after workflow registration