name: Release

on:
  push:
    branches:
      - master
  workflow_dispatch:

jobs:
  release-plz-release:
    name: Release-plz release
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: read
    concurrency:
      group: release-plz-release-${{ github.ref }}
      cancel-in-progress: false
    outputs:
      releases_created: ${{ steps.outputs.outputs.releases_created }}
      tag: ${{ steps.outputs.outputs.tag }}
      draft_release_created: ${{ steps.outputs.outputs.draft_release_created }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          persist-credentials: false

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Run release-plz
        id: release
        uses: release-plz/action@v0.5
        with:
          command: release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

      - name: Recover skipped release tag
        id: recovery
        if: steps.release.outputs.releases_created != 'true'
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          set -euo pipefail
          head_subject=$(git log -1 --pretty=%s)
          if [[ ! "$head_subject" =~ ^chore:\ release\ v ]]; then
            echo "HEAD ($head_subject) is not a release commit; nothing to recover."
            exit 0
          fi
          version=$(awk -F'"' '/^version = / { print $2; exit }' Cargo.toml)
          tag="v${version}"
          if git ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then
            echo "Tag ${tag} already exists on remote; enabling downstream binary upload."
            {
              echo "tag_present=true"
              echo "tag=${tag}"
            } >> "$GITHUB_OUTPUT"
            exit 0
          fi
          echo "::warning::release-plz skipped tagging ${tag} (likely already published on crates.io). Creating tag now."
          head_sha=$(git rev-parse HEAD)
          tag_sha=$(gh api -X POST "repos/${GITHUB_REPOSITORY}/git/tags" \
            -f tag="${tag}" \
            -f message="${tag}" \
            -f object="${head_sha}" \
            -f type=commit \
            --jq '.sha')
          gh api -X POST "repos/${GITHUB_REPOSITORY}/git/refs" \
            -f ref="refs/tags/${tag}" \
            -f sha="${tag_sha}" >/dev/null
          {
            echo "tag_present=true"
            echo "tag=${tag}"
          } >> "$GITHUB_OUTPUT"

      - name: Resolve job outputs
        id: outputs
        env:
          RELEASES_CREATED: ${{ steps.release.outputs.releases_created }}
          RELEASES_JSON: ${{ steps.release.outputs.releases }}
          RECOVERY_TAG_PRESENT: ${{ steps.recovery.outputs.tag_present }}
          RECOVERY_TAG: ${{ steps.recovery.outputs.tag }}
        run: |
          set -euo pipefail
          if [[ "$RELEASES_CREATED" == "true" ]]; then
            tag=$(echo "$RELEASES_JSON" | jq -r '.[0].tag')
            echo "releases_created=true" >> "$GITHUB_OUTPUT"
            echo "tag=${tag}" >> "$GITHUB_OUTPUT"
            echo "draft_release_created=true" >> "$GITHUB_OUTPUT"
          elif [[ "$RECOVERY_TAG_PRESENT" == "true" ]]; then
            echo "releases_created=true" >> "$GITHUB_OUTPUT"
            echo "tag=${RECOVERY_TAG}" >> "$GITHUB_OUTPUT"
            echo "draft_release_created=false" >> "$GITHUB_OUTPUT"
          else
            echo "releases_created=false" >> "$GITHUB_OUTPUT"
            echo "draft_release_created=false" >> "$GITHUB_OUTPUT"
          fi

  release-plz-pr:
    name: Release-plz PR
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    concurrency:
      group: release-plz-${{ github.ref }}
      cancel-in-progress: false
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          persist-credentials: false

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Run release-plz
        uses: release-plz/action@v0.5
        with:
          command: release-pr
        env:
          GITHUB_TOKEN: ${{ secrets.RELEASE_PLZ_TOKEN }}
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

  upload-binaries:
    name: Upload ${{ matrix.target }}
    needs: release-plz-release
    if: needs.release-plz-release.outputs.releases_created == 'true'
    runs-on: ${{ matrix.os }}
    permissions:
      contents: write
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
          - target: aarch64-unknown-linux-gnu
            os: ubuntu-latest
          - target: aarch64-apple-darwin
            os: macos-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ needs.release-plz-release.outputs.tag }}

      - uses: taiki-e/setup-cross-toolchain-action@v1
        with:
          target: ${{ matrix.target }}
        if: matrix.target == 'aarch64-unknown-linux-gnu'

      - uses: taiki-e/upload-rust-binary-action@v1
        with:
          bin: auberge
          target: ${{ matrix.target }}
          ref: refs/tags/${{ needs.release-plz-release.outputs.tag }}
          checksum: sha256
          token: ${{ secrets.GITHUB_TOKEN }}

  publish-release:
    name: Publish draft release
    needs: [release-plz-release, upload-binaries]
    if: needs.release-plz-release.outputs.draft_release_created == 'true'
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - name: Flip draft to published
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          TAG: ${{ needs.release-plz-release.outputs.tag }}
        run: gh release edit "$TAG" --draft=false --latest --repo "$GITHUB_REPOSITORY"
