Release Please #755
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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 |