name: Publish release files for CD native and non-cd-native environments

on:
  repository_dispatch:
    types: [ release-created ]

permissions:
  # Write permissions to call the repository dispatch
  contents: write

defaults:
  run:
    shell: bash

jobs:
  # Publish release files for CD native environments
  native_build:
    permissions:
      # Use to sign the release artifacts
      id-token: write
      # Used to upload release artifacts
      contents: write
      # Used to generate artifact attestations
      attestations: write
    strategy:
      fail-fast: false
      matrix:
        # Use the Ubuntu 22.04 image to link with a low version of glibc
        #
        # https://github.com/topgrade-rs/topgrade/issues/1095
        platform: [ ubuntu-22.04, macos-latest, macos-15-intel, windows-latest ]
    runs-on: ${{ matrix.platform }}
    env:
      tag: ${{ github.event.client_payload.tag }}
    steps:
      - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
        with:
          persist-credentials: false

      - name: Install needed components
        run: |
          rustup component add rustfmt
          rustup component add clippy

      - name: Install cargo-deb
        run: cargo install cargo-deb
        if: ${{ startsWith(matrix.platform, 'ubuntu-') }}
        shell: bash

      - name: Check format
        run: cargo fmt --all -- --check

      - name: Run clippy
        run: cargo clippy --all-targets --locked -- -D warnings

      - name: Run clippy (All features)
        run: cargo clippy --all-targets --locked --all-features -- -D warnings

      - name: Run tests
        run: cargo test

      # Used `https://github.com/BurntSushi/ripgrep/blob/master/.github/workflows/release.yml`
      # as a reference.
      - name: Build debug binary to create release assets
        shell: bash
        run: |
          cargo build --all-features
          bin="target/debug/topgrade"
          echo "BIN=$bin" >> $GITHUB_ENV

      - name: Create deployment directory
        shell: bash
        run: |
          dir=deployment/deb
          mkdir -p "$dir"
          echo "DEPLOY_DIR=$dir" >> $GITHUB_ENV

      - name: Generate man page and shell completions
        shell: bash
        run: |
          "$BIN" --gen-manpage > "$DEPLOY_DIR/topgrade.1"
          "$BIN" --gen-completion bash > "$DEPLOY_DIR/topgrade.bash"
          "$BIN" --gen-completion fish > "$DEPLOY_DIR/topgrade.fish"
          "$BIN" --gen-completion zsh > "$DEPLOY_DIR/_topgrade"

      - name: Build in Release profile with all features enabled
        run: cargo build --release --all-features

      - name: Rename Release (Unix)
        run: |
          cargo install default-target
          mkdir -p assets
          FILENAME=topgrade-${tag}-$(default-target)
          mv target/release/topgrade assets
          cd assets
          tar --format=ustar -czf $FILENAME.tar.gz topgrade
          rm topgrade
          ls .
        if: ${{ matrix.platform != 'windows-latest' }}
        shell: bash

      - name: Build Debian-based system binary and create package
        # First remove the binary built by previous steps
        # because we don't want the auto-update feature,
        # then build the new binary without auto-updating.
        run: |
          rm -rf target/release
          cargo build --release
          cargo deb --no-build --no-strip
        if: ${{ startsWith(matrix.platform, 'ubuntu-') }}
        shell: bash

      - name: Move Debian-based system package
        run: |
          mkdir -p assets
          mv target/debian/*.deb assets
        if: ${{ startsWith(matrix.platform, 'ubuntu-') }}
        shell: bash

      - name: Rename Release (Windows)
        run: |
          cargo install default-target
          mkdir assets
          FILENAME=topgrade-${tag}-$(default-target)
          mv target/release/topgrade.exe assets/topgrade.exe
          cd assets
          powershell Compress-Archive -Path * -Destination ${FILENAME}.zip
          rm topgrade.exe
          ls .
        if: ${{ matrix.platform == 'windows-latest' }}
        shell: bash

      - name: Upload assets
        run: |
          gh release upload "${tag}" assets/*
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Generate artifact attestations
        uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
        with:
          subject-path: assets/*

  # Publish release files for non-CD-native environments
  cross_build:
    permissions:
      # Use to sign the release artifacts
      id-token: write
      # Used to upload release artifacts
      contents: write
      # Used to generate artifact attestations
      attestations: write
    strategy:
      fail-fast: false
      matrix:
        target:
          [
            "aarch64-unknown-linux-gnu",
            "armv7-unknown-linux-gnueabihf",
            "x86_64-unknown-linux-musl",
            "aarch64-unknown-linux-musl",
            "x86_64-unknown-freebsd",
          ]
    # Run this one on an older version as well, to limit glibc to 2.34 instead of 2.39.
    # Even though this is cross-compiled, it links to the libc6-<arch>-cross installed on the host
    # (see the apt-get install calls below)
    runs-on: ubuntu-22.04
    env:
      matrix_target: ${{ matrix.target }}
      tag: ${{ github.event.client_payload.tag }}
    steps:
      - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
        with:
          persist-credentials: false

      - name: Install needed components
        run: |
          rustup component add rustfmt
          rustup component add clippy

      - name: Install cargo-deb cross compilation dependencies
        run: sudo apt-get install libc6-arm64-cross libgcc-s1-arm64-cross
        if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }}
        shell: bash

      - name: Install cargo-deb cross compilation dependencies for armv7
        run: sudo apt-get install libc6-armhf-cross libgcc-s1-armhf-cross
        if: ${{ matrix.target == 'armv7-unknown-linux-gnueabihf' }}
        shell: bash

      - name: Install cargo-deb
        run: cargo install cargo-deb
        if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'armv7-unknown-linux-gnueabihf' }}
        shell: bash

      - name: install targets
        run: rustup target add "${matrix_target}"

      - name: install cross
        # Install from source to fix `ld: cannot find -lgeom` for freebsd build
        run: cargo +stable install --git https://github.com/cross-rs/cross cross

      - name: Run clippy
        run: cross clippy --all-targets --locked --target "${matrix_target}" -- -D warnings

      - name: Run clippy (All features)
        run: cross clippy  --locked --all-features --target "${matrix_target}" -- -D warnings

      - name: Run tests
        run: cross test --target "${matrix_target}"
        # Running tests on FreeBSD is impossible; see https://github.com/cross-rs/cross/wiki/FAQ#running-bsd-tests
        # Not that this is *NOT* the same as the original issue with `ld: cannot find -lgeom`, but a new issue:
        # error: test failed, to rerun pass `--lib`
        # Caused by:
        #   could not execute process `/target/x86_64-unknown-freebsd/debug/deps/topgrade-9b1670d87ca863dd` (never executed)
        # Caused by:
        #   No such file or directory (os error 2)
        # TODO: I have not tested this in GHA yet, only locally
        if: ${{ matrix.target != 'x86_64-unknown-freebsd' }}

      # Used `https://github.com/BurntSushi/ripgrep/blob/master/.github/workflows/release.yml`
      # as a reference.
      - name: Build debug binary to create release assets
        shell: bash
        run: |
          # This build is not using the target arch since this binary is only needed in CI. It needs
          # to be the compiled for the runner since it has the run the binary to generate completion
          # scripts.
          cargo build --all-features
          bin="target/debug/topgrade"
          echo "BIN=$bin" >> $GITHUB_ENV

      - name: Create deployment directory
        shell: bash
        run: |
          dir=deployment/deb
          mkdir -p "$dir"
          echo "DEPLOY_DIR=$dir" >> $GITHUB_ENV

      - name: Generate man page and shell completions
        shell: bash
        run: |
          "$BIN" --gen-manpage > "$DEPLOY_DIR/topgrade.1"
          "$BIN" --gen-completion bash > "$DEPLOY_DIR/topgrade.bash"
          "$BIN" --gen-completion fish > "$DEPLOY_DIR/topgrade.fish"
          "$BIN" --gen-completion zsh > "$DEPLOY_DIR/_topgrade"

      - name: Build in Release profile with all features enabled
        run: cross build --release --all-features --target "${matrix_target}"

      - name: Rename Release
        run: |
          mkdir -p assets
          FILENAME=topgrade-${tag}-${matrix_target}
          mv "target/${matrix_target}/release/topgrade" assets
          cd assets
          tar --format=ustar -czf "$FILENAME.tar.gz" topgrade
          rm topgrade
          ls .

      - name: Build Debian-based system package without autoupdate feature
        # First remove the binary built by previous steps
        # because we don't want the auto-update feature,
        # then build the new binary without auto-updating.
        run: |
          rm -rf "target/${matrix_target}"
          cross build --release --target "${matrix_target}"
          cargo deb --target="${matrix_target}" --no-build --no-strip
        if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'armv7-unknown-linux-gnueabihf' }}
        shell: bash

      - name: Move Debian-based system package
        run: |
          mkdir -p assets
          mv target/"${matrix_target}"/debian/*.deb assets
        if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'armv7-unknown-linux-gnueabihf' }}
        shell: bash


      - name: Upload assets
        run:
          gh release upload "${tag}" assets/*
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Generate artifact attestations
        uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
        with:
          subject-path: assets/*

  triggers:
    runs-on: ubuntu-latest
    needs: [ native_build, cross_build ]
    env:
      tag: ${{ github.event.client_payload.tag }}
    steps:
      - name: Trigger workflows
        run: |
          gh api "repos/${GITHUB_REPOSITORY}/dispatches" \
            -f "event_type=release-assets-built" \
            -F "client_payload[tag]=${tag}"
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
