name: release

on:
  push:
    tags:
    - "v*"

permissions:
  attestations: write
  contents: write
  id-token: write

defaults:
  run:
    shell: bash

env:
  CARGO_INCREMENTAL: 0
  RUSTFLAGS: -Dwarnings

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
    - name: Parse version
      id: parse
      run: |
        version="${GITHUB_REF_NAME#v}"
        echo "version=$version" >> "$GITHUB_OUTPUT"
        echo "::notice::Version: $version"
    - name: Checkout
      uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
    - name: Cache
      uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
      with:
        path: |
          ~/.cargo/bin/
          ~/.cargo/registry/index/
          ~/.cargo/registry/cache/
          ~/.cargo/git/db/
          target/
        key: ${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('**/Cargo.lock') }}
    - name: Set up toolchain
      run: rustup install
    - name: Verify version
      run: |
        expected='${{ steps.parse.outputs.version }}'
        actual="$(cargo run -- --version)"
        if [[ "$actual" != "akv $expected" ]]; then
          echo "::error::\`akv --version\` '$actual' does not match '$expected'"
          exit 1
        fi

  test:
    uses: ./.github/workflows/ci.yml
    needs: verify
    with:
      release: true

  draft:
    runs-on: ubuntu-latest
    needs: test
    steps:
    # Check out with full history to generate release notes.
    - name: Checkout
      uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      with:
        fetch-depth: 0
    - name: Set up toolchain
      run: rustup install
    - name: Draft release
      run: gh release create '${{ github.ref_name }}' --draft --generate-notes
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  package:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os:
        - macos-14 # arm64
        - ubuntu-22.04
        - ubuntu-22.04-arm
        - windows-2022
        - windows-11-arm
        include:
        - os: windows-2022
          extension: '.exe'
        - os: windows-11-arm
          extension: '.exe'
    needs: draft
    steps:
    - name: Checkout
      uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
    - name: Cache
      uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
      with:
        path: |
          ~/.cargo/bin/
          ~/.cargo/registry/index/
          ~/.cargo/registry/cache/
          ~/.cargo/git/db/
          target/
        key: ${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('**/Cargo.lock') }}
    - name: Set up toolchain
      run: rustup install
    - name: Build
      id: build
      run: |
        cargo build --release --all-features --workspace
        echo "dir=target/release/" | tee -a "$GITHUB_OUTPUT"
        echo "name=akv${{ matrix.extension }}" | tee -a "$GITHUB_OUTPUT"
        echo "target=target/release/akv${{ matrix.extension }}" | tee -a "$GITHUB_OUTPUT"
    - name: Attest executable
      uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
      with:
        subject-path: ${{ steps.build.outputs.target }}
    - name: Package
      id: package
      run: |
        name=$(echo 'akv-${{ runner.os }}-${{ runner.arch }}' | tr '[:upper:]' '[:lower:]' | sed 's/x64/amd64/')
        if [[ '${{ runner.os }}' == 'Windows' ]]; then
          name="$name.zip"
          target="target/release/$name"
          # Must explicitly start from $PWD (#145).
          7z a "$target" "./${{ steps.build.outputs.target }}" -mx=9
        else
          name="$name.tar.gz"
          target="target/release/$name"
          tar czf "$target" -C "${{ steps.build.outputs.dir }}" "${{ steps.build.outputs.name }}"
        fi
        echo "name=$name" >> "$GITHUB_OUTPUT"
        echo "target=$target" >> "$GITHUB_OUTPUT"
    - name: Upload
      uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
      with:
        name: ${{ steps.package.outputs.name }}
        path: ${{ steps.package.outputs.target }}
    - name: Publish
      run: gh release upload '${{ github.ref_name }}' '${{ steps.package.outputs.target }}'
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  attest:
    runs-on: ubuntu-latest
    needs: package
    steps:
    - name: Download
      uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
    - name: Attest
      uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
      with:
        subject-path: ${{ github.workspace }}/*

  # Publish separately to crates.io to allow retries e.g., expired token.
  publish:
    runs-on: ubuntu-latest
    needs: package
    environment: crates-io
    steps:
    - name: Checkout
      uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
    - name: Set up toolchain
      run: rustup install
    - name: Authenticate with crates.io
      id: auth
      uses: rust-lang/crates-io-auth-action@bbd81622f20ce9e2dd9622e3218b975523e45bbe # v1.0.4
    - name: Publish
      run: cargo publish
      env:
        CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}

  release:
    runs-on: ubuntu-latest
    needs: attest
    steps:
    - name: Checkout
      uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
    - name: Release
      run: gh release edit '${{ github.ref_name }}' --draft=false
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  brew:
    needs: release
    uses: ./.github/workflows/brew.yml
    with:
      tag: ${{ github.ref_name }}
    secrets:
      HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}

  # winget:
  #   needs: release
  #   uses: ./.github/workflows/winget.yml
  #   with:
  #     tag: ${{ github.ref_name }}
  #   secrets:
  #     WINGET_CREATE_GITHUB_TOKEN: ${{ secrets.WINGET_CREATE_GITHUB_TOKEN }}
