name: Release

on:
  push:
    tags:
      - 'v*.*.*'
  workflow_dispatch:
    inputs:
      tag:
        description: 'Tag to build and release (e.g. v0.1.0)'
        required: true
        type: string

permissions:
  contents: write

env:
  BIN_NAME: bifrost

jobs:
  build:
    name: build (${{ matrix.target }})
    runs-on: ${{ matrix.runner }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            rust_targets: x86_64-unknown-linux-gnu
            runner: ubuntu-latest
            archive: tar.gz
          - target: aarch64-unknown-linux-gnu
            rust_targets: aarch64-unknown-linux-gnu
            runner: ubuntu-24.04-arm
            archive: tar.gz
          - target: universal-apple-darwin
            rust_targets: x86_64-apple-darwin,aarch64-apple-darwin
            runner: macos-latest
            archive: tar.gz
          - target: x86_64-pc-windows-msvc
            rust_targets: x86_64-pc-windows-msvc
            runner: windows-latest
            archive: zip
          - target: aarch64-pc-windows-msvc
            rust_targets: aarch64-pc-windows-msvc
            runner: windows-latest
            archive: zip

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          ref: ${{ inputs.tag || github.ref }}

      - name: Resolve tag
        id: tag
        shell: bash
        run: |
          if [ -n "${{ inputs.tag }}" ]; then
            echo "name=${{ inputs.tag }}" >> "$GITHUB_OUTPUT"
          else
            echo "name=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
          fi

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.rust_targets }}

      - name: Cache cargo + target
        uses: Swatinem/rust-cache@v2
        with:
          key: ${{ matrix.target }}

      - name: Build
        if: matrix.target != 'universal-apple-darwin'
        run: cargo build --release --locked --bin ${{ env.BIN_NAME }} --target ${{ matrix.target }}

      - name: Build macOS universal binary
        if: matrix.target == 'universal-apple-darwin'
        shell: bash
        run: |
          cargo build --release --locked --bin "${BIN_NAME}" --target x86_64-apple-darwin
          cargo build --release --locked --bin "${BIN_NAME}" --target aarch64-apple-darwin
          mkdir -p "target/${{ matrix.target }}/release"
          lipo -create \
            "target/x86_64-apple-darwin/release/${BIN_NAME}" \
            "target/aarch64-apple-darwin/release/${BIN_NAME}" \
            -output "target/${{ matrix.target }}/release/${BIN_NAME}"
          lipo -info "target/${{ matrix.target }}/release/${BIN_NAME}"

      - name: Stage artifacts (Unix)
        if: matrix.archive == 'tar.gz'
        shell: bash
        run: |
          stage="${BIN_NAME}-${{ steps.tag.outputs.name }}-${{ matrix.target }}"
          mkdir -p "dist/${stage}"
          cp "target/${{ matrix.target }}/release/${BIN_NAME}" "dist/${stage}/"
          cp LICENSE.md README.md "dist/${stage}/"
          tar -C dist -czf "dist/${stage}.tar.gz" "${stage}"
          (cd dist && shasum -a 256 "${stage}.tar.gz" > "${stage}.tar.gz.sha256")

      - name: Stage artifacts (Windows)
        if: matrix.archive == 'zip'
        shell: pwsh
        run: |
          $stage = "${env:BIN_NAME}-${{ steps.tag.outputs.name }}-${{ matrix.target }}"
          New-Item -ItemType Directory -Path "dist/$stage" | Out-Null
          Copy-Item "target/${{ matrix.target }}/release/${env:BIN_NAME}.exe" "dist/$stage/"
          Copy-Item LICENSE.md, README.md "dist/$stage/"
          Compress-Archive -Path "dist/$stage" -DestinationPath "dist/$stage.zip"
          $hash = (Get-FileHash -Algorithm SHA256 "dist/$stage.zip").Hash.ToLower()
          "$hash  $stage.zip" | Out-File -Encoding ascii "dist/$stage.zip.sha256"

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: ${{ env.BIN_NAME }}-${{ matrix.target }}
          path: |
            dist/*.tar.gz
            dist/*.zip
            dist/*.sha256
          if-no-files-found: error

  release:
    name: release
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Resolve tag
        id: tag
        shell: bash
        run: |
          if [ -n "${{ inputs.tag }}" ]; then
            echo "name=${{ inputs.tag }}" >> "$GITHUB_OUTPUT"
          else
            echo "name=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
          fi

      - name: Download all artifacts
        uses: actions/download-artifact@v4
        with:
          path: dist
          merge-multiple: true

      - name: Publish GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ steps.tag.outputs.name }}
          name: ${{ steps.tag.outputs.name }}
          generate_release_notes: true
          files: |
            dist/*.tar.gz
            dist/*.zip
            dist/*.sha256
