name: release

permissions: {}

on:
  push:
    tags:
      - v[0-9]+.*
  workflow_dispatch:
    inputs:
      version:
        description: "Version (without leading v)"
        required: true
        type: string

env:
  CARGO_TERM_COLOR: always
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

jobs:
  build-binaries:
    runs-on: ${{ matrix.runner }}
    timeout-minutes: 90
    permissions:
      contents: write
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: aarch64-apple-darwin
            os: macos-latest
            runner: namespace-profile-endev-macos-arm64
            build-tool: cargo
            optimized: false
          - target: x86_64-unknown-linux-musl
            os: ubuntu-latest
            runner: namespace-profile-endev-linux-amd64
            build-tool: cross
            optimized: false
          - target: aarch64-unknown-linux-musl
            os: ubuntu-latest
            runner: namespace-profile-endev-linux-amd64
            build-tool: cross
            optimized: false
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
            runner: namespace-profile-endev-linux-amd64
            build-tool: cross
            optimized: true
          - target: aarch64-unknown-linux-gnu
            os: ubuntu-latest
            runner: namespace-profile-endev-linux-amd64
            build-tool: cross
            optimized: false
          - target: x86_64-pc-windows-msvc
            os: windows-latest
            runner: windows-latest
            build-tool: cargo
            optimized: false
          - target: aarch64-pc-windows-msvc
            os: windows-latest
            runner: windows-latest
            build-tool: cargo
            optimized: false
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          persist-credentials: false
      - if: matrix.os == 'macos-latest'
        uses: apple-actions/import-codesign-certs@5142e029c445c10ffc7149d172e540235a065466 # v7
        with:
          p12-file-base64: ${{ secrets.CERTIFICATES_P12 }}
          p12-password: ${{ secrets.CERTIFICATES_P12_PASS }}
      - name: Install PGO and BOLT build tools
        if: matrix.optimized
        shell: bash
        run: |
          rustup component add llvm-tools
          cargo install cross --locked --version 0.2.5
          sudo apt-get update
          sudo apt-get install -y --no-install-recommends wget gnupg ca-certificates
          sudo install -d -m 0755 /etc/apt/keyrings
          wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key \
            | sudo gpg --dearmor -o /etc/apt/keyrings/llvm.gpg
          codename=$(. /etc/os-release && echo "$VERSION_CODENAME")
          echo "deb [signed-by=/etc/apt/keyrings/llvm.gpg] https://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-18 main" \
            | sudo tee /etc/apt/sources.list.d/llvm-toolchain-18.list
          sudo apt-get update
          sudo apt-get install -y bolt-18
      - name: Build PGO+BOLT binary
        if: matrix.optimized
        shell: bash
        env:
          HK_PGO_BUILD_TOOL: ${{ matrix.build-tool }}
          HK_PGO_TARGET: ${{ matrix.target }}
        run: scripts/pgo-bolt.bash
      - name: Package PGO+BOLT binary
        if: matrix.optimized
        shell: bash
        env:
          TARGET: ${{ matrix.target }}
        run: |
          # Match upload-rust-binary-action's default Unix archive format.
          # tar.xz is disabled by default and zip is reserved for Windows.
          tar -czf "hk-${TARGET}.tar.gz" \
            -C "target/${TARGET}/serious-pgo" hk
      - if: matrix.optimized != true
        uses: taiki-e/upload-rust-binary-action@f0d45ae91ee7b8ee928de7a9d04d893a08bcbec6 # v1
        with:
          bin: hk
          target: ${{ matrix.target }}
          build-tool: ${{ matrix.build-tool }}
          token: ${{ secrets.GITHUB_TOKEN }}
          features: git2/vendored-libgit2,git2/vendored-openssl
          profile: serious
          codesign: "Developer ID Application: Jeffrey Dickey (4993Y37DX6)"
          codesign_prefix: dev.jdx.
          dry-run: true # Always dry-run to just build without uploading
      - name: Upload binary artifact
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
        with:
          name: binary-${{ matrix.target }}
          path: |
            hk-*.tar.gz
            hk-*.tar.xz
            hk-*.zip
          retention-days: 1

  build-pkl:
    runs-on: namespace-profile-endev-linux-amd64
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          persist-credentials: false
      - uses: jdx/mise-action@7e36c90d9ab29c415a2384db3006f3ec8a8cc654 # v4.2.4
        with:
          cache: false
      - name: Package Pkl
        env:
          INPUTS_VERSION: ${{ inputs.version }}
          GITHUB_REF_NAME: ${{ github.ref_name }}
        run: |
          if [[ -n "${INPUTS_VERSION}" ]]; then
            TAG_NAME="v${INPUTS_VERSION}"
          else
            TAG_NAME="${GITHUB_REF_NAME}"
          fi
          VERSION="${TAG_NAME#v}"
          echo "Building pkl package for version: $VERSION"

          # Use the mise task which outputs to docs/public/pkl
          VERSION="${VERSION}" mise run pkl:dist

          echo "Contents of docs/public/pkl:"
          ls -la docs/public/pkl || true
      - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
        with:
          name: pkl-packages
          path: docs/public/pkl/*
          if-no-files-found: error
          retention-days: 1

  create-release:
    needs: [build-binaries, build-pkl]
    runs-on: namespace-profile-endev-linux-amd64
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          fetch-depth: 0
          persist-credentials: false
      - uses: jdx/mise-action@7e36c90d9ab29c415a2384db3006f3ec8a8cc654 # v4.2.4
        with:
          cache: false
      - name: Extract release notes from CHANGELOG.md
        run: |
          awk '/^## \[/{if(found) exit; found=1} found{print}' CHANGELOG.md > release-notes.md
          if [[ ! -s release-notes.md ]]; then
            echo "No release notes available" > release-notes.md
          fi
      - name: Download all artifacts
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
        with:
          path: artifacts
      - name: Prepare release assets
        run: |
          mkdir -p release-assets
          find artifacts/binary-* -type f \( -name "*.tar.gz" -o -name "*.tar.xz" -o -name "*.zip" \) -exec mv {} release-assets/ \;
          if [ -d "artifacts/pkl-packages" ]; then
            find artifacts/pkl-packages -type f -exec mv {} release-assets/ \;
          fi
          ls -la release-assets/
      - name: Create release with all assets
        env:
          INPUTS_VERSION: ${{ inputs.version }}
          GITHUB_REF_NAME: ${{ github.ref_name }}
        run: |
          if [[ -n "${INPUTS_VERSION}" ]]; then
            TAG_NAME="v${INPUTS_VERSION}"
          else
            TAG_NAME="${GITHUB_REF_NAME}"
          fi
          gh release create "$TAG_NAME" \
            --title "$TAG_NAME" \
            --notes-file release-notes.md \
            release-assets/*

  publish-crate:
    needs: [create-release]
    if: github.repository == 'jdx/hk'
    runs-on: namespace-profile-endev-linux-amd64
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          persist-credentials: false
      - uses: jdx/mise-action@7e36c90d9ab29c415a2384db3006f3ec8a8cc654 # v4.2.4
        with:
          cache: false
      - run: cargo publish # zizmor: ignore[use-trusted-publishing]
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

  enhance-release:
    needs: [create-release]
    runs-on: namespace-profile-endev-linux-amd64
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          fetch-depth: 0
          persist-credentials: false
      - uses: jdx/mise-action@7e36c90d9ab29c415a2384db3006f3ec8a8cc654 # v4.2.4
        with:
          cache: false
      - name: Enhance release notes with communique
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          INPUTS_VERSION: ${{ inputs.version }}
          GITHUB_REF_NAME: ${{ github.ref_name }}
        run: |
          if [[ -n "${INPUTS_VERSION}" ]]; then
            TAG_NAME="v${INPUTS_VERSION}"
          else
            TAG_NAME="${GITHUB_REF_NAME}"
          fi
          communique generate "$TAG_NAME" --github-release
      - name: Append jdx.dev sponsor blurb
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          INPUTS_VERSION: ${{ inputs.version }}
          GITHUB_REF_NAME: ${{ github.ref_name }}
        run: |
          if [[ -n "${INPUTS_VERSION}" ]]; then
            TAG_NAME="v${INPUTS_VERSION}"
          else
            TAG_NAME="${GITHUB_REF_NAME}"
          fi
          gh release view "$TAG_NAME" --json body --jq .body \
            | perl -0pe 's/\n*^##[^\n]*Sponsor hk\b.*\z//ms' \
            > /tmp/release-notes.md
          printf '\n\n' >> /tmp/release-notes.md
          cat <<'EOF' >> /tmp/release-notes.md
          ## 💚 Sponsor hk

          hk is maintained by [@jdx](https://github.com/jdx), an open source developer for [**entire.io**](https://entire.io), the title sponsor of the [jdx.dev](https://jdx.dev) open source tools including [mise](https://mise.jdx.dev/), [aube](https://aube.jdx.dev/), and more. Work on hk is funded by sponsorships.

          If hk has sped up your pre-commit loop or made linting feel less painful, please consider [sponsoring at jdx.dev](https://jdx.dev/sponsors.html). Sponsorships are what keep hk moving and the project independent.
          EOF

          gh release edit "$TAG_NAME" --notes-file /tmp/release-notes.md
