# Releases are automated: merging a PR whose last commit bumps the version IS the
# release. On every push to main this workflow reads Cargo.toml's version, publishes the
# crate if crates.io does not serve it at that version yet, and then tags the commit and
# creates the GitHub release. A merge without a version bump publishes nothing and changes
# nothing; a run that failed halfway is safe to re-run, it just finishes.
#
# Authentication is crates.io Trusted Publishing (OIDC): no long-lived token is stored
# anywhere. The crate carries a Trusted Publishing entry on crates.io naming this repo and
# this workflow file; the auth action exchanges the runner's identity for a short-lived,
# crate-scoped token at publish time.
#
# The gate is not re-run here: main requires the `test` check (which itself insists the
# version is strictly above crates.io), so the tree being pushed has already passed it,
# and `cargo publish` verify-builds the tarball against the registry anyway.
name: publish
on:
  push:
    branches: [main]

permissions:
  contents: write # create the release tag
  id-token: write # crates.io Trusted Publishing (OIDC)

# Never two releases at once; a second merge waits for the first to finish.
concurrency:
  group: publish
  cancel-in-progress: false

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Read the version
        id: version
        run: |
          version="$(sed -n 's/^version = "\(.*\)"$/\1/p' Cargo.toml | head -1)"
          [ -n "$version" ] || { echo "no version found in Cargo.toml"; exit 1; }
          echo "version=$version" >> "$GITHUB_OUTPUT"

      - name: Ask the index whether this version still needs publishing
        id: todo
        run: |
          # The sparse-index path for a 4-character name: first two / next two / name.
          if curl -fsSL "https://index.crates.io/sc/sh/scsh" | grep -q "\"vers\":\"${{ steps.version.outputs.version }}\""; then
            echo "scsh ${{ steps.version.outputs.version }} is already on crates.io"
            echo "missing=" >> "$GITHUB_OUTPUT"
          else
            echo "scsh ${{ steps.version.outputs.version }} needs publishing"
            echo "missing=scsh" >> "$GITHUB_OUTPUT"
          fi

      - name: Mint a short-lived crates.io token (Trusted Publishing)
        if: steps.todo.outputs.missing != ''
        id: auth
        uses: rust-lang/crates-io-auth-action@v1

      - name: Publish
        if: steps.todo.outputs.missing != ''
        env:
          CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
        run: cargo publish

      - name: Tag the release on GitHub
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          tag="v${{ steps.version.outputs.version }}"
          if gh release view "$tag" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
            echo "release $tag already exists"
          else
            gh release create "$tag" --repo "$GITHUB_REPOSITORY" --target "$GITHUB_SHA" --title "$tag" --generate-notes
          fi
