http-kit 0.4.3

A flexible and ergonomic HTTP toolkit for Rust with async support, middleware, and zero-copy body handling
Documentation
name: Release

# `release` publishes what `main` carries; `release-pr` keeps the version
# bump and changelog pull request open against `dev`. The bump belongs on
# `dev` because a pull request opened with the default `GITHUB_TOKEN` starts
# no workflow runs, so one targeting `main` could never satisfy the required
# check there and no release could ever be merged.
#
# Publishing runs on `push` rather than on CI's `workflow_run`: crates.io
# trusted publishing refuses to mint a token for the `workflow_run` event,
# so the job waits for this commit's checks itself before it publishes.
on:
  push:
    branches: [main]
  workflow_run:
    workflows: [CI]
    branches: [dev]
    types: [completed]

jobs:
  release:
    name: Publish release
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: read
      checks: read
      id-token: write
    concurrency:
      group: release-publish-main
      cancel-in-progress: false
    steps:
      - name: Checkout the pushed main commit
        uses: actions/checkout@v6
        with:
          ref: ${{ github.sha }}
          fetch-depth: 0
          persist-credentials: false
      # Nothing publishes until this very commit is green. Every check run
      # on it must conclude, and all of them must have passed.
      - name: Wait for this commit's checks
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SHA: ${{ github.sha }}
        run: |
          set -euo pipefail
          # Outside the checkout: `cargo publish` refuses to package a dirty
          # working tree, and this file would be the dirt.
          checks="${RUNNER_TEMP}/checks.tsv"
          deadline=$(( $(date +%s) + 3300 ))
          while :; do
            gh api "repos/${GITHUB_REPOSITORY}/commits/${SHA}/check-runs?per_page=100" \
              --jq '.check_runs[] | [.name, (.conclusion // "pending")] | @tsv' \
              | grep -v '^Publish release	' > "${checks}" || true

            if grep -E '\t(failure|cancelled|timed_out|action_required|startup_failure|stale)$' "${checks}"; then
              echo "::error::a check on ${SHA} did not pass (see list above); not publishing"
              exit 1
            fi
            pending=$(grep -c $'\tpending$' "${checks}" || true)
            started=$(wc -l < "${checks}")
            if [ "${pending}" -eq 0 ] && [ "${started}" -gt 0 ]; then
              echo "every check on ${SHA} passed"
              exit 0
            fi
            if [ "$(date +%s)" -gt "${deadline}" ]; then
              echo "::error::timed out after 55 minutes waiting for checks on ${SHA}"
              cat "${checks}"
              exit 1
            fi
            sleep 30
          done
      - &rust-toolchain
        name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
      # Mint a short-lived crates.io token from the GitHub OIDC identity
      # instead of a stored CARGO_REGISTRY_TOKEN (trusted publishing is
      # configured per crate on crates.io).
      - uses: rust-lang/crates-io-auth-action@v1
        id: crates-io-auth
      - name: Publish unpublished crate version
        uses: release-plz/action@v0.5
        with:
          command: release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          CARGO_REGISTRY_TOKEN: ${{ steps.crates-io-auth.outputs.token }}

  release-pr:
    name: Prepare next release
    if: >-
      github.event_name == 'workflow_run' &&
      github.event.workflow_run.conclusion == 'success'
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    concurrency:
      group: release-plz-dev
      cancel-in-progress: false
    steps:
      - name: Checkout tested dev commit
        uses: actions/checkout@v6
        with:
          ref: dev
          fetch-depth: 0
          persist-credentials: false
      - name: Verify tested commit
        env:
          EXPECTED_SHA: ${{ github.event.workflow_run.head_sha }}
        run: |
          actual_sha="$(git rev-parse HEAD)"
          if [[ "$actual_sha" != "$EXPECTED_SHA" ]]; then
            echo "::error::dev moved after CI: expected $EXPECTED_SHA, checked out $actual_sha"
            exit 1
          fi
      - *rust-toolchain
      # The pull request lands the bump on `dev`; the release itself is the
      # `dev` -> `main` pull request that carries it, which runs the full
      # check set.
      - name: Create or update release PR
        uses: release-plz/action@v0.5
        with:
          command: release-pr
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}