ps-qa 0.3.2

Drive a running Blitz app through its MCP control socket and assert what the renderer did
name: Publish

# Publish on a version bump, not on every push to master.
#
# The trigger is a change to Cargo.toml's version rather than a tag, because
# nothing here tags releases and a tag nobody remembers to push is a crate
# nobody gets. Bumping the version in a normal PR is the whole release ritual.
#
# Republishing an existing version is a hard error on crates.io, so the job
# checks the registry first and exits clean when the version is already there.
# That keeps an unrelated push to master, or a re-run of this workflow, from
# failing red for having nothing to do.
on:
  push:
    branches: [master]
    paths:
      - Cargo.toml
      - Cargo.lock
      - src/**
      - tests/**
  workflow_dispatch:
    inputs:
      dry_run:
        description: 'Package and verify, but do not upload'
        required: false
        type: boolean
        default: false

concurrency:
  group: ${{ github.workflow }}
  cancel-in-progress: false

jobs:
  publish:
    name: crates.io
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@stable

      - uses: Swatinem/rust-cache@v2

      # The gate. `cargo publish` on an existing version fails, and this job
      # runs on every push that touches the source, so most runs have nothing
      # to do and must say so quietly rather than failing.
      - name: Is this version already on crates.io?
        id: check
        run: |
          name=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[0].name')
          version=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[0].version')
          echo "name=$name"       >> "$GITHUB_OUTPUT"
          echo "version=$version" >> "$GITHUB_OUTPUT"
          published=$(curl -sS -H 'User-Agent: pathscale-ci' \
            "https://crates.io/api/v1/crates/$name/versions" \
            | jq -r --arg v "$version" '.versions[]? | select(.num == $v) | .num' || true)
          if [ -n "$published" ]; then
            echo "already=true" >> "$GITHUB_OUTPUT"
            echo "$name $version is already published; nothing to do"
          else
            echo "already=false" >> "$GITHUB_OUTPUT"
            echo "$name $version is new"
          fi

      - name: Build
        if: steps.check.outputs.already == 'false'
        run: cargo build --release

      - name: Test
        if: steps.check.outputs.already == 'false'
        run: cargo test --release

      # Catches the packaging failures that only appear in the published
      # artifact: a file the manifest excludes, or a path dependency that
      # cannot be resolved from the registry.
      - name: Package
        if: steps.check.outputs.already == 'false'
        run: cargo package --locked

      - name: Publish
        if: steps.check.outputs.already == 'false' && !inputs.dry_run
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
        run: |
          if [ -z "$CARGO_REGISTRY_TOKEN" ]; then
            echo "CARGO_REGISTRY_TOKEN is not set on this repository" >&2
            echo "Add it under Settings -> Secrets -> Actions." >&2
            exit 1
          fi
          cargo publish --locked

      - name: Summary
        if: always()
        run: |
          {
            if [ '${{ steps.check.outputs.already }}' = 'true' ]; then
              echo "Nothing to publish: \`${{ steps.check.outputs.name }}\` \
          ${{ steps.check.outputs.version }} is already on crates.io."
              echo
              echo 'Bump `version` in Cargo.toml to cut a new one.'
            elif [ '${{ inputs.dry_run }}' = 'true' ]; then
              echo "Dry run: packaged \`${{ steps.check.outputs.name }}\` \
          ${{ steps.check.outputs.version }} without uploading."
            else
              echo "Published \`${{ steps.check.outputs.name }}\` \
          ${{ steps.check.outputs.version }}."
            fi
          } >> "$GITHUB_STEP_SUMMARY"