name: Release-plz

# Runs on every push to main.
#
# 1. Reads conventional commits since the last tag and computes the next
#    SemVer bump.
# 2. Updates Cargo.toml + CHANGELOG.md and commits directly to main
#    (no PR review required).
# 3. Creates an annotated git tag (e.g. v0.2.0).  The tag triggers the
#    release workflow (.github/workflows/main.yml) which builds
#    multi-platform binaries and creates the GitHub Release.
#
# Infinite-loop prevention: when a version-bump commit is pushed, the
# "Tag release" step is skipped in that run.  The push re-triggers the
# workflow; on the second run no file changes are detected, so no new
# commit is created, but the tag IS created — ending the cycle.
#
# Conventional commit → version bump mapping:
#   fix: …                    → patch   (0.1.0 → 0.1.1)
#   feat: …                   → minor   (0.1.0 → 0.2.0)
#   feat!: … / BREAKING CHANGE → minor (0.x) / major (≥1.x)
#   chore:, docs:, test:, …   → no bump (nothing is committed)

on:
  push:
    branches:
      - main

permissions:
  contents: write      # push commits and create tags

concurrency:
  group: release-plz-${{ github.ref }}
  cancel-in-progress: false          # let the running release finish

jobs:
  release:
    name: Release
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0   # full history needed to read all commits since last tag
          fetch-tags: true # release-plz update needs tags to detect what changed since last release
          token: ${{ secrets.SEMVER_GH_TOKEN }}
      - uses: dtolnay/rust-toolchain@stable
      - name: Install cargo-semver-checks
        # Used internally by `release-plz update` to detect semver-incompatible
        # API changes and decide the correct version bump level.
        uses: taiki-e/install-action@v2
        with:
          tool: cargo-semver-checks
      - name: Install cargo-binstall
        uses: cargo-bins/cargo-binstall@v1.17.5
      - name: Install release-plz
        run: cargo binstall release-plz@0.3.156 -y
      - name: Update version and changelog
        run: release-plz update
      - name: Commit and push version bump
        id: commit_version_bump
        run: |
          set -euo pipefail
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add -A
          if git diff --cached --quiet; then
            echo "No version changes needed"
            echo "version_changed=false" >> "$GITHUB_OUTPUT"
          else
            # jq is pre-installed on GitHub-hosted Ubuntu runners
            VERSION=$(cargo metadata --no-deps --format-version 1 | jq -r '. as $m | $m.packages[] | select(.id == $m.resolve.root) | .version')
            git commit -m "chore(release): bump version to v${VERSION}"
            git push
            echo "version_changed=true" >> "$GITHUB_OUTPUT"
          fi
      # Tag release: skip when a version-bump commit was just pushed to
      # prevent tagging before the re-triggered run.  On the next run no
      # commit is created, so the tag step executes normally — no infinite
      # loop because release-plz release only creates tags, not commits.
      - name: Tag release
        if: steps.commit_version_bump.outputs.version_changed != 'true'
        run: |
          git fetch --tags
          release-plz release --git-token "$GITHUB_TOKEN"
        env:
          # SEMVER_GH_TOKEN must be a PAT with minimum scope: contents:write
          # (push commits and create tags).  Avoid broader permissions.
          GITHUB_TOKEN: ${{ secrets.SEMVER_GH_TOKEN }}
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
