name: Release

on:
  push:
    tags:
      - "v*.*.*"
  workflow_dispatch:
    inputs:
      tag:
        description: "Tag to build artifacts for (e.g. v0.1.0). Must already exist."
        required: true

permissions:
  contents: write   # for creating GitHub releases + uploading assets

env:
  CARGO_TERM_COLOR: always

jobs:
  verify:
    name: verify build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - run: cargo fmt --all -- --check
      - run: cargo clippy --all-targets --all-features -- -D warnings
      - run: cargo test --all-features

  package:
    name: package .crate
    needs: verify
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2

      - name: Determine tag
        id: tag
        run: |
          if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
            echo "tag=${{ github.event.inputs.tag }}" >> "$GITHUB_OUTPUT"
          else
            echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
          fi

      # cargo package produces a crates.io-ready tarball under
      # target/package/. We attach it to the GitHub release for
      # mirror downloads; the actual crates.io publish stays manual
      # (`cargo publish` from a maintainer's workstation).
      - name: cargo package
        run: cargo package --allow-dirty

      - name: Compute checksum
        shell: bash
        run: |
          cd target/package
          for f in *.crate; do
            shasum -a 256 "$f" > "$f.sha256"
          done
          ls -la

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: fast-flirt-crate
          path: |
            target/package/*.crate
            target/package/*.sha256
          if-no-files-found: error

  github-release:
    name: create GitHub release
    needs: package
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Determine tag
        id: tag
        run: |
          if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
            echo "tag=${{ github.event.inputs.tag }}" >> "$GITHUB_OUTPUT"
          else
            echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
          fi

      - name: Generate release notes
        id: notes
        run: |
          tag="${{ steps.tag.outputs.tag }}"
          previous=$(git describe --tags --abbrev=0 "${tag}^" 2>/dev/null || echo "")
          {
            echo "notes<<EOF"
            if [ -n "$previous" ]; then
              echo "## Changes since $previous"
              echo
              git log --pretty=format:"- %s (%h)" "${previous}..${tag}"
            else
              echo "## Initial release"
              echo
              git log --pretty=format:"- %s (%h)" "${tag}"
            fi
            echo
            echo
            echo "## Install"
            echo
            echo '```toml'
            echo "fast-flirt = \"${tag#v}\""
            echo '```'
            echo
            echo "The attached \`.crate\` is the same artifact published to crates.io."
            echo EOF
          } >> "$GITHUB_OUTPUT"

      - name: Download artifacts
        uses: actions/download-artifact@v4
        with:
          path: artifacts

      - name: Flatten artifacts
        run: |
          mkdir -p release
          find artifacts -type f \( -name '*.crate' -o -name '*.sha256' \) -exec mv {} release/ \;
          ls -la release

      - name: Create release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ steps.tag.outputs.tag }}
          name: ${{ steps.tag.outputs.tag }}
          body: ${{ steps.notes.outputs.notes }}
          files: release/*
          draft: false
          prerelease: ${{ contains(steps.tag.outputs.tag, '-') }}
