name: Release

on:
  push:
    tags:
      - "v*"

permissions:
  contents: write

jobs:
  build:
    name: build (${{ matrix.target }})
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
            archive: tar.gz
            exe: ""
            install_musl: false
            smoke: true
          - target: x86_64-unknown-linux-musl
            os: ubuntu-latest
            archive: tar.gz
            exe: ""
            install_musl: true
            smoke: true
          - target: aarch64-apple-darwin
            os: macos-15
            archive: tar.gz
            exe: ""
            install_musl: false
            smoke: true
          - target: x86_64-apple-darwin
            os: macos-15-intel
            archive: tar.gz
            exe: ""
            install_musl: false
            smoke: true
          - target: x86_64-pc-windows-msvc
            os: windows-latest
            archive: zip
            exe: ".exe"
            install_musl: false
            smoke: true
    steps:
      - uses: actions/checkout@v4

      - name: Install musl tools
        if: matrix.install_musl
        run: sudo apt-get update && sudo apt-get install -y musl-tools

      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - uses: Swatinem/rust-cache@v2

      - name: Build
        shell: bash
        run: cargo build --release --target "${{ matrix.target }}"

      - name: Smoke
        if: matrix.smoke
        shell: bash
        run: |
          set -euo pipefail
          bin="target/${{ matrix.target }}/release/rgfile${{ matrix.exe }}"
          "$bin" --version

      - name: Package
        shell: bash
        run: |
          set -euo pipefail
          version="${GITHUB_REF_NAME#v}"
          target="${{ matrix.target }}"
          name="rgfile-${version}-${target}"
          mkdir -p "dist/${name}"
          cp "target/${target}/release/rgfile${{ matrix.exe }}" "dist/${name}/"
          cp LICENSE README.md "dist/${name}/"
          if [[ "${{ matrix.archive }}" == "zip" ]]; then
            (cd dist && 7z a "${name}.zip" "${name}" >/dev/null)
          else
            (cd dist && tar -czf "${name}.tar.gz" "${name}")
          fi

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

  deb:
    name: deb (x86_64, musl)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install musl tools
        run: sudo apt-get update && sudo apt-get install -y musl-tools

      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: x86_64-unknown-linux-musl

      - uses: Swatinem/rust-cache@v2

      - name: Install cargo-deb
        run: cargo install cargo-deb --locked

      - name: Build deb
        shell: bash
        run: |
          set -euo pipefail
          version="${GITHUB_REF_NAME#v}"
          cargo deb --target x86_64-unknown-linux-musl --deb-version "${version}"
          mkdir -p dist
          cp "target/x86_64-unknown-linux-musl/debian/rgfile_${version}_amd64.deb" dist/

      - name: Smoke install
        shell: bash
        run: |
          set -euo pipefail
          sudo dpkg -i dist/*.deb
          rgfile --version
          dpkg -L rgfile

      - name: Upload package artifact
        uses: actions/upload-artifact@v4
        with:
          name: package-deb
          path: dist/*.deb
          if-no-files-found: error

  release:
    name: release
    needs: [build, deb]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Download package artifacts
        uses: actions/download-artifact@v4
        with:
          pattern: package-*
          path: artifacts
          merge-multiple: true

      - name: Prepare checksums
        shell: bash
        run: |
          set -euo pipefail
          version="${GITHUB_REF_NAME#v}"
          mkdir -p release-assets
          find artifacts -type f \( -name "*.tar.gz" -o -name "*.zip" -o -name "*.deb" \) -exec cp {} release-assets/ \;

          expected=(
            "rgfile-${version}-x86_64-unknown-linux-gnu.tar.gz"
            "rgfile-${version}-x86_64-unknown-linux-musl.tar.gz"
            "rgfile-${version}-aarch64-apple-darwin.tar.gz"
            "rgfile-${version}-x86_64-apple-darwin.tar.gz"
            "rgfile-${version}-x86_64-pc-windows-msvc.zip"
            "rgfile_${version}_amd64.deb"
          )
          for asset in "${expected[@]}"; do
            test -f "release-assets/${asset}"
          done

          shopt -s nullglob
          archives=(release-assets/*.tar.gz release-assets/*.zip release-assets/*.deb)
          if [[ "${#archives[@]}" -ne 6 ]]; then
            find release-assets -maxdepth 1 -type f -print
            exit 1
          fi

          (cd release-assets && sha256sum *.tar.gz *.zip *.deb > SHA256SUMS)
          (cd release-assets && sha256sum -c SHA256SUMS)

      - name: Build release notes
        shell: bash
        run: |
          set -euo pipefail
          version="${GITHUB_REF_NAME#v}"
          changelog_version="${version%%-*}"
          awk -v version="${changelog_version}" '
            /^## \[/ {
              if (in_section) {
                exit
              }
              if (index($0, "## [" version "]") == 1) {
                in_section = 1
              }
              next
            }
            in_section {
              print
            }
          ' docs/CHANGELOG.md > changelog-excerpt.md

          {
            echo "## ${GITHUB_REF_NAME}"
            echo
            if [[ -s changelog-excerpt.md ]]; then
              cat changelog-excerpt.md
            else
              echo "Release candidate for v${changelog_version}."
            fi
            echo
            echo "### License"
            echo
            echo "This binary release is distributed under the MIT license."
            echo "Each archive includes LICENSE and README.md."
            echo "Source for this release is the repository content at:"
            echo "https://github.com/${GITHUB_REPOSITORY}/tree/${GITHUB_REF_NAME}"
          } > RELEASE_NOTES.md

      - name: Check existing GitHub Release
        id: existing_release
        env:
          GH_TOKEN: ${{ github.token }}
        shell: bash
        run: |
          set -euo pipefail
          if gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1; then
            echo "exists=true" >> "${GITHUB_OUTPUT}"
            echo "Release ${GITHUB_REF_NAME} already exists; skipping creation."
          else
            echo "exists=false" >> "${GITHUB_OUTPUT}"
          fi

      - name: Publish GitHub Release
        if: steps.existing_release.outputs.exists != 'true'
        env:
          GH_TOKEN: ${{ github.token }}
        shell: bash
        run: |
          set -euo pipefail
          args=()
          if [[ "${GITHUB_REF_NAME}" == *-* ]]; then
            args+=(--prerelease)
          fi
          gh release create "${GITHUB_REF_NAME}" release-assets/* \
            --title "${GITHUB_REF_NAME}" \
            --notes-file RELEASE_NOTES.md \
            "${args[@]}"
