# Publish to crates.io

name: Publish

on:
  push:
    tags:
      - "v[0-9]+.[0-9]+.[0-9]+"      # v1.2.3
      - "v[0-9]+.[0-9]+.[0-9]+-*"    # v1.2.3-beta.1
  workflow_dispatch:
    inputs:
      dry_run:
        description: "Dry run (validate without publishing)"
        required: false
        default: true
        type: boolean

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

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1
  MDBOOK_VERSION: "0.5.2"

jobs:
  # ===========================================
  # Validate the package before publishing
  # ===========================================
  validate:
    name: Validate Package
    runs-on: ubuntu-latest
    permissions:
      contents: read
    outputs:
      version: ${{ steps.version.outputs.version }}
      tag_version: ${{ steps.version.outputs.tag_version }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

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

      - name: Cache dependencies
        uses: Swatinem/rust-cache@v2

      - name: Install mdbook
        uses: taiki-e/install-action@v2
        with:
          tool: mdbook@${{ env.MDBOOK_VERSION }}

      - name: Extract versions
        id: version
        run: |
          # Get version from Cargo.toml
          CARGO_VERSION=$(cargo metadata --format-version=1 --no-deps | jq -r '.packages[0].version')
          echo "version=$CARGO_VERSION" >> $GITHUB_OUTPUT
          echo "Cargo.toml version: $CARGO_VERSION"

          # Get version from git tag (if triggered by tag)
          if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
            TAG_VERSION="${GITHUB_REF#refs/tags/v}"
            echo "tag_version=$TAG_VERSION" >> $GITHUB_OUTPUT
            echo "Git tag version: $TAG_VERSION"
          fi

      - name: Verify tag matches Cargo.toml version
        if: startsWith(github.ref, 'refs/tags/v')
        env:
          CARGO_VERSION: ${{ steps.version.outputs.version }}
          TAG_VERSION: ${{ steps.version.outputs.tag_version }}
        run: |
          if [[ "$CARGO_VERSION" != "$TAG_VERSION" ]]; then
            echo "::error::Version mismatch! Cargo.toml has $CARGO_VERSION but tag is v$TAG_VERSION"
            exit 1
          fi
          echo "Version match confirmed: $CARGO_VERSION"

      - name: Check formatting
        run: cargo fmt --all -- --check

      - name: Run Clippy
        run: cargo clippy --all-targets --all-features -- -D warnings

      - name: Run tests
        run: cargo test --all-features --verbose

      - name: Check documentation
        run: cargo doc --no-deps --document-private-items
        env:
          RUSTDOCFLAGS: -D warnings

      - name: Verify package contents
        run: |
          echo "=== Package contents ==="
          cargo package --list --allow-dirty
          echo ""
          echo "=== Package size ==="
          cargo package --allow-dirty 2>&1 | grep -E "Packaged|Compiling" || true

      - name: Dry run publish
        run: cargo publish --dry-run --allow-dirty

  # ===========================================
  # Publish to crates.io
  # ===========================================
  publish:
    name: Publish to crates.io
    needs: validate
    runs-on: ubuntu-latest
    environment: crates-io
    permissions:
      contents: read
      id-token: write
    # Skip publish on dry run
    if: ${{ !inputs.dry_run }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache dependencies
        uses: Swatinem/rust-cache@v2

      - name: Authenticate with crates.io (OIDC)
        uses: rust-lang/crates-io-auth-action@v1
        id: auth

      - name: Publish to crates.io
        run: cargo publish --verbose
        env:
          CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}

      - name: Verify publication
        env:
          CRATE_VERSION: ${{ needs.validate.outputs.version }}
        run: |
          echo "Waiting for crates.io to index (60s)..."
          sleep 60

          echo "Checking crates.io API..."
          if curl -sf "https://crates.io/api/v1/crates/mdbook-termlink/$CRATE_VERSION" > /dev/null 2>&1; then
            echo "mdbook-termlink v$CRATE_VERSION is now available on crates.io!"
            echo ""
            echo "Install with: cargo install mdbook-termlink"
            echo "View at: https://crates.io/crates/mdbook-termlink/$CRATE_VERSION"
          else
            echo "Package may still be indexing. Check manually:"
            echo "   https://crates.io/crates/mdbook-termlink"
          fi
