Repository navigation
Release #64
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
| name: Release | |
| on: # zizmor: ignore[dangerous-triggers] -- Exact SHA/API-verified same-repository main pushes only; no PR artifacts/caches consumed. | |
| workflow_run: | |
| workflows: [CI] | |
| branches: [main] | |
| types: [completed] | |
| # crates.io Trusted Publishing refuses OIDC tokens from workflow_run events, so | |
| # the verified workflow_run dispatches this same workflow for the publish job. | |
| # Every input is re-verified through the API before anything is published. | |
| workflow_dispatch: | |
| inputs: | |
| sha: | |
| description: Merged release-plz commit on main to publish (40 hex) | |
| required: true | |
| type: string | |
| ci_run_id: | |
| description: Successful ci.yml push-to-main run for that commit | |
| required: true | |
| type: string | |
| permissions: {} | |
| concurrency: | |
| group: release-main | |
| cancel-in-progress: false | |
| queue: max | |
| defaults: | |
| run: | |
| shell: bash | |
| jobs: | |
| verify: | |
| if: >- | |
| github.event_name == 'workflow_dispatch' || ( | |
| github.event.workflow_run.event == 'push' && | |
| github.event.workflow_run.head_repository.full_name == 'PerryTS/turnloop' && | |
| github.event.workflow_run.conclusion == 'success') | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: read | |
| actions: read | |
| pull-requests: read | |
| timeout-minutes: 10 | |
| outputs: | |
| release: ${{ steps.ci.outputs.release }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| # A dispatch runs main's verifier (github.sha), never the input commit's | |
| # scripts; the verifier proves inputs.sha is a merged release commit. | |
| ref: ${{ github.event.workflow_run.head_sha || github.sha }} | |
| - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: '3.14' | |
| - name: Verify the exact main commit's ci-gate through the API | |
| id: ci | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| RELEASE_SHA: ${{ github.event.workflow_run.head_sha || inputs.sha }} | |
| CI_RUN_ID: ${{ github.event.workflow_run.id || inputs.ci_run_id }} | |
| run: python3 scripts/ci/check-ci.py --release-pr | |
| release-pr: | |
| needs: verify | |
| if: github.event_name == 'workflow_run' | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: read | |
| timeout-minutes: 30 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| ref: main | |
| fetch-depth: 0 | |
| - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: '3.14' | |
| - name: Install pinned Rust | |
| run: rustup toolchain install nightly-2026-08-20 --profile minimal --component rustfmt,clippy | |
| - name: Install release PR tools | |
| run: python3 scripts/ci/install-tools.py release-plz cargo-semver-checks | |
| - name: Short-lived GitHub App token so release PRs trigger normal CI | |
| id: app | |
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 | |
| with: | |
| app-id: ${{ vars.RELEASE_APP_ID }} | |
| private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} | |
| owner: PerryTS | |
| repositories: turnloop | |
| permission-contents: write | |
| permission-pull-requests: write | |
| - name: Prepare version bumps and changelogs | |
| env: | |
| GIT_TOKEN: ${{ steps.app.outputs.token }} | |
| RUSTUP_TOOLCHAIN: nightly-2026-08-20 | |
| # release-plz resolves each crate against the registry, where our own | |
| # siblings are hours old, so the seven-day publish-age soak rejects | |
| # them ("turnloop-io = ^0.1.0-alpha.3 is too new"). The soak exists for | |
| # third-party supply chain, and this resolution produces no artifact: | |
| # every lockfile the release PR carries is still gated by | |
| # scripts/ci/soak.py in required CI, which no exception here can skip. | |
| CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE: allow | |
| run: release-plz release-pr --repo-url https://github.com/PerryTS/turnloop --config release-plz.toml | |
| dispatch-publish: | |
| needs: verify | |
| if: github.event_name == 'workflow_run' && needs.verify.outputs.release == 'true' | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| actions: write | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Dispatch the Trusted Publishing run for the verified release commit | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| RELEASE_SHA: ${{ github.event.workflow_run.head_sha }} | |
| CI_RUN_ID: ${{ github.event.workflow_run.id }} | |
| run: gh workflow run release.yml --repo PerryTS/turnloop --ref main -f "sha=$RELEASE_SHA" -f "ci_run_id=$CI_RUN_ID" | |
| publish: | |
| needs: verify | |
| if: github.event_name == 'workflow_dispatch' && needs.verify.outputs.release == 'true' | |
| runs-on: ubuntu-24.04 | |
| # The owner must configure required reviewers and main-only deployments. | |
| environment: crates-io | |
| permissions: | |
| contents: write | |
| actions: read | |
| id-token: write | |
| timeout-minutes: 60 | |
| env: | |
| RELEASE_SHA: ${{ inputs.sha }} | |
| CI_RUN_ID: ${{ inputs.ci_run_id }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| ref: ${{ inputs.sha }} | |
| fetch-depth: 0 | |
| - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: '3.14' | |
| - name: Install pinned Rust | |
| run: rustup toolchain install nightly-2026-08-20 --profile minimal --component rustfmt,clippy | |
| - name: Install release checks and audit toolchain | |
| run: | | |
| python3 scripts/ci/install-tools.py cargo-semver-checks | |
| rustup toolchain install nightly-2026-09-07 --profile minimal | |
| - name: Supply-chain and all-target runtime gates | |
| run: | | |
| python3 scripts/ci/soak.py | |
| bash scripts/ci/no-tokio.sh | |
| - name: Semver and dry-run for every publishable crate before any upload | |
| run: python3 scripts/ci/release.py preflight | |
| - name: Verify ci-gate again after environment approval | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: python3 scripts/ci/check-ci.py | |
| - name: Obtain a short-lived crates.io token through OIDC | |
| id: crates | |
| uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1.0.5 | |
| - name: Publish in dependency order, then create crate tags and GitHub Releases | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ steps.crates.outputs.token }} | |
| GH_TOKEN: ${{ github.token }} | |
| run: python3 scripts/ci/release.py publish |