name: Release

# Version string specification (see build.rs + src/main.rs long_version()):
#
# build.rs sets MLUX_BUILD_GIT_DESCRIBE from `git describe --tags --always`.
# long_version() uses this to construct the version string:
#
#   describe=""                  → Cargo.toml version (crates.io / tarball)
#   describe starts with 'v'    → describe as-is (e.g. "v1.6.0", "v1.6.0-3-gabcdef")
#   describe is hash only       → "{cargo_version}-dev+{hash}" (shallow clone, no tags)
#
# The build job creates a local tag so that `git describe` returns "v{version}"
# for release binaries. The real tag is pushed later in the release job.

on:
  workflow_dispatch:

env:
  CARGO_TERM_COLOR: always
  RUSTFLAGS: -Dwarnings

permissions:
  contents: write
  id-token: write

jobs:
  validate:
    name: Validate
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    outputs:
      version: ${{ steps.version.outputs.version }}
      tag: ${{ steps.version.outputs.tag }}
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
        with:
          fetch-depth: 0
      - name: Read version and check tag
        id: version
        run: |
          version=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
          tag="v${version}"
          if git rev-parse "$tag" >/dev/null 2>&1; then
            echo "::error::Tag $tag already exists. Bump the version in Cargo.toml first."
            exit 1
          fi
          echo "version=$version" >> "$GITHUB_OUTPUT"
          echo "tag=$tag" >> "$GITHUB_OUTPUT"
      - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # stable
        with:
          toolchain: stable
          components: clippy
      - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
      - run: cargo clippy --all-targets
      - run: cargo test

  build:
    name: Build (${{ matrix.target }})
    needs: validate
    runs-on: ${{ matrix.runner }}
    strategy:
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            runner: ubuntu-latest
          - target: aarch64-unknown-linux-gnu
            runner: ubuntu-24.04-arm
          - target: aarch64-apple-darwin
            runner: macos-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
      - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # stable
        with:
          toolchain: stable
      - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
        with:
          key: ${{ matrix.target }}
      # Local tag so build.rs `git describe` produces "v1.x.0" instead of "-dev+hash"
      # (real tag is pushed later in the release job)
      - name: Tag for version string
        run: git tag "v${{ needs.validate.outputs.version }}"
      - name: Build
        run: cargo build --release --target ${{ matrix.target }}
      - name: Package
        run: |
          dir="mlux-v${{ needs.validate.outputs.version }}-${{ matrix.target }}"
          mkdir "$dir"
          cp "target/${{ matrix.target }}/release/mlux" "$dir/"
          cp LICENSE "$dir/"
          cp fonts/OFL-NotoSansJP.txt "$dir/"
          cp fonts/OFL-STIXTwoMath.txt "$dir/"
          tar czf "$dir.tar.gz" "$dir"
      - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
        with:
          name: mlux-v${{ needs.validate.outputs.version }}-${{ matrix.target }}
          path: mlux-v${{ needs.validate.outputs.version }}-${{ matrix.target }}.tar.gz

  release:
    name: GitHub Release
    needs: [validate, publish]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
        with:
          fetch-depth: 0
      - name: Create tag
        run: |
          git tag "${{ needs.validate.outputs.tag }}"
          git push origin "${{ needs.validate.outputs.tag }}"
      - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
        with:
          path: artifacts
          merge-multiple: true
      - name: Build commit log
        run: |
          prev_tag=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
          if [ -n "$prev_tag" ]; then
            range="${prev_tag}..HEAD"
          else
            range="HEAD"
          fi
          {
            echo "## Commits"
            echo ""
            git log "$range" --pretty=format:"- %s (%h)" --no-merges
          } > commit-log.md
      - name: Create release
        run: gh release create "${{ needs.validate.outputs.tag }}" --generate-notes --notes-file commit-log.md artifacts/*.tar.gz
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  publish:
    name: Publish to crates.io
    needs: [validate, build]
    runs-on: ubuntu-latest
    environment: release
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
      - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # stable
        with:
          toolchain: stable
      - uses: rust-lang/crates-io-auth-action@bbd81622f20ce9e2dd9622e3218b975523e45bbe # v1
        id: auth
      - run: cargo publish
        env:
          CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
