name: Publish Release

# Two ways to fire this:
#   1. Manual: Actions → Publish Release → Run workflow (pick level).
#   2. Push a trigger tag from git / jj:
#         git tag release-patch && git push origin release-patch
#         jj bookmark create --revision @ release-tag    # then jj git push --tag
#      Tag names: release-patch | release-minor | release-major
#      The workflow parses the level from the tag, runs `cargo release`,
#      and then deletes the trigger tag from origin so it's reusable.
on:
  workflow_dispatch:
    inputs:
      level:
        description: "Semver bump level"
        required: true
        type: choice
        options:
          - patch
          - minor
          - major
      dry-run:
        description: "Dry-run (skip --execute)"
        required: false
        type: boolean
        default: false
  push:
    tags:
      - "release-patch"
      - "release-minor"
      - "release-major"

permissions:
  contents: write

jobs:
  publish:
    runs-on: ubuntu-latest
    env:
      CARGO_TERM_COLOR: always
      CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
    steps:
      - name: Resolve bump level
        id: resolve
        run: |
          if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
            LEVEL="${{ inputs.level }}"
            DRY="${{ inputs.dry-run }}"
          else
            LEVEL="${GITHUB_REF_NAME#release-}"
            DRY="false"
          fi
          case "$LEVEL" in
            patch|minor|major) ;;
            *) echo "::error::invalid level '$LEVEL'"; exit 1 ;;
          esac
          echo "level=$LEVEL" >>"$GITHUB_OUTPUT"
          echo "dry=$DRY"     >>"$GITHUB_OUTPUT"
          echo "Releasing: level=$LEVEL dry-run=$DRY (event=${{ github.event_name }})"

      - uses: actions/checkout@v6
        with:
          ref: master
          fetch-depth: 0
          persist-credentials: true
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Verify trigger tag points at master HEAD
        if: github.event_name == 'push'
        run: |
          TAG_SHA="${{ github.sha }}"
          MASTER_SHA="$(git rev-parse origin/master)"
          if [[ "$TAG_SHA" != "$MASTER_SHA" ]]; then
            echo "::error::Trigger tag ${{ github.ref_name }} ($TAG_SHA) is not on master ($MASTER_SHA). Move it to master HEAD and re-push."
            exit 1
          fi

      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy

      - uses: Swatinem/rust-cache@v2

      - uses: jdx/mise-action@v2

      - uses: taiki-e/install-action@v2
        with:
          tool: cargo-release,cargo-sort,cargo-machete

      - name: Configure git identity
        run: |
          git config user.name  "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

      - name: cargo release ${{ steps.resolve.outputs.level }}
        run: |
          ARGS=("${{ steps.resolve.outputs.level }}" --no-confirm)
          if [[ "${{ steps.resolve.outputs.dry }}" != "true" ]]; then
            ARGS+=(--execute)
          fi
          cargo release "${ARGS[@]}"

      - name: Delete trigger tag
        if: always() && github.event_name == 'push'
        run: git push --delete origin "${{ github.ref_name }}" || true
