on:
  push:
    branches:
      - main
  pull_request:
  merge_group:
    branches:
      - main
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }}
  cancel-in-progress: true

name: CI

jobs:
  check:
    name: Check
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
      - run: cargo check --all

  test:
    name: Test Suite
    runs-on: ${{ matrix.os }}
    continue-on-error: ${{ matrix.zig == 'master' || matrix.toolchain == 'nightly' || matrix.os == 'windows-latest' }}
    strategy:
      # If one platform fails, allow the rest to keep testing if `CI-no-fail-fast` label is present
      fail-fast: ${{ !contains(github.event.pull_request.labels.*.name, 'CI-no-fail-fast') }}
      matrix:
        os: [ubuntu-latest, macos-13, windows-latest]
        toolchain: [1.74.0, stable, nightly]
        zig: [0.11.0, 0.14.0, master]
        exclude:
          # Only test MSRV with zig stable version
          - toolchain: 1.74.0
            zig: master
    env:
      RUST_BACKTRACE: "1"
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@master
        id: rustup
        with:
          toolchain: ${{ matrix.toolchain }}
      - name: Install zig
        uses: korandoru/setup-zig@v1
        with:
          zig-version: ${{ matrix.zig }}
      - run: zig version
      - run: cargo build
      - name: Install Rust targets
        shell: bash
        run: |
          rustup target add aarch64-unknown-linux-gnu \
            x86_64-unknown-linux-gnu \
            i686-unknown-linux-gnu \
            arm-unknown-linux-gnueabihf \
            armv7-unknown-linux-gnueabihf \
            aarch64-apple-darwin \
            x86_64-apple-darwin \
            x86_64-pc-windows-gnu \
            i686-pc-windows-gnu
      - name: Test bindgen
        # zstd with bindgen requires Rust 1.77+
        if: ${{ matrix.toolchain != '1.74.0' }}
        shell: bash
        run: |
          set -e
          git clone --recurse-submodules https://github.com/gyscos/zstd-rs.git tests/zstd-rs
          cargo run zigbuild --manifest-path tests/zstd-rs/Cargo.toml --features bindgen --target aarch64-unknown-linux-gnu
          cargo run zigbuild --manifest-path tests/zstd-rs/Cargo.toml --features bindgen --target x86_64-pc-windows-gnu
          cargo run zigbuild --manifest-path tests/zstd-rs/Cargo.toml --features bindgen --target aarch64-apple-darwin
      - name: Test bindgen-exhaustive
        shell: bash
        run: |
          set -e
          cargo run zigbuild --manifest-path tests/bindgen-exhaustive/Cargo.toml --target aarch64-unknown-linux-gnu
          cargo run zigbuild --manifest-path tests/bindgen-exhaustive/Cargo.toml --target x86_64-pc-windows-gnu
          cargo run zigbuild --manifest-path tests/bindgen-exhaustive/Cargo.toml --target aarch64-apple-darwin
      - name: Install x86-instruction-set-analyzer
        uses: taiki-e/install-action@v2
        with:
          tool: x86-instruction-set-analyzer@0.1.0
      - name: Test RUSTFLAGS
        shell: bash
        run: |
          set -e
          cargo build  # Build without RUSTFLAGS

          echo "Running -C target_cpu=x86-64..."
          echo
          export RUSTFLAGS="-C target_cpu=x86-64"
          target/debug/cargo-zigbuild zigbuild --manifest-path tests/target-cpu/Cargo.toml --target x86_64-unknown-linux-gnu --release
          x86-instruction-set-analyzer tests/target-cpu/target/x86_64-unknown-linux-gnu/release/target-cpu | tee output.txt
          echo
          if grep -q 'AVX2' output.txt; then
            echo "Test fail, should not contain AVX2 instruction set"
            false
          else
            echo "Test pass"
          fi

          echo "Running -C target_cpu=x86-64-v4..."
          echo
          export RUSTFLAGS="-C target_cpu=x86-64-v4"
          target/debug/cargo-zigbuild zigbuild --manifest-path tests/target-cpu/Cargo.toml --target x86_64-unknown-linux-gnu --release
          x86-instruction-set-analyzer tests/target-cpu/target/x86_64-unknown-linux-gnu/release/target-cpu | tee output.txt
          echo
          if ! grep -q 'AVX2' output.txt; then
            echo "Test fail, should contain AVX2 instruction set"
            false
          else
            echo "Test pass"
          fi
      - name: macOS - Test build
        run: |
          cargo run zigbuild --target aarch64-apple-darwin
          cargo run zigbuild --target aarch64-apple-darwin --release
      - name: macOS - Test build universal2
        run: cargo run zigbuild --target universal2-apple-darwin
      - name: macOS - Test build with SDKROOT
        if: matrix.os == 'ubuntu-latest'
        env:
          SDK: MacOSX11.3.sdk
        run: |
          set -e
          curl -sqL https://github.com/phracker/MacOSX-SDKs/releases/download/11.3/$SDK.tar.xz | tar -Jx
          export SDKROOT=$PWD/$SDK

          cargo run zigbuild --target aarch64-apple-darwin --manifest-path tests/hello-tls/Cargo.toml
          cargo run zigbuild --target aarch64-apple-darwin --manifest-path tests/hello-rustls/Cargo.toml
      - name: macOS - Test build bindgen with SDKROOT
        if: ${{ matrix.os == 'ubuntu-latest' && matrix.toolchain != '1.74.0' }}
        env:
          SDK: MacOSX11.3.sdk
        run: cargo run zigbuild --manifest-path tests/zstd-rs/Cargo.toml --features bindgen --target aarch64-apple-darwin
      - name: Linux - Test x86_64 build
        if: matrix.os == 'ubuntu-latest'
        run: |
          cargo run zigbuild --target x86_64-unknown-linux-gnu
          ldd -r -v ./target/x86_64-unknown-linux-gnu/debug/cargo-zigbuild
      - name: Linux - Test x86_64 glibc build
        if: ${{ matrix.os == 'ubuntu-latest' && (matrix.toolchain == 'stable' || matrix.toolchain == 'nightly') }}
        run: |
          cargo run zigbuild --target x86_64-unknown-linux-gnu.2.17
      - name: Linux - Test x86_64 glibc run
        if: ${{ matrix.os == 'ubuntu-latest' && (matrix.toolchain == 'stable' || matrix.toolchain == 'nightly') }}
        uses: addnab/docker-run-action@v3
        with:
          image: centos:7
          options: -v ${{ github.workspace }}:/io -w /io
          run: |
            ldd -r -v ./target/x86_64-unknown-linux-gnu/debug/cargo-zigbuild
            ./target/x86_64-unknown-linux-gnu/debug/cargo-zigbuild --help
      - name: Linux - Test glibc build
        run: |
          cargo run zigbuild --target aarch64-unknown-linux-gnu
          cargo run zigbuild --target aarch64-unknown-linux-gnu.2.17

          cargo run zigbuild --target aarch64-unknown-linux-gnu --manifest-path tests/hello-cmake/Cargo.toml
          cargo run zigbuild --target aarch64-unknown-linux-gnu --manifest-path tests/hello-rustls/Cargo.toml
          cargo run zigbuild --target armv7-unknown-linux-gnueabihf --manifest-path tests/hello-rustls/Cargo.toml
          cargo run zigbuild --target arm-unknown-linux-gnueabihf --manifest-path tests/hello-rustls/Cargo.toml
          cargo run zigbuild --target i686-unknown-linux-gnu --manifest-path tests/hello-rustls/Cargo.toml

          # Test building shared library
          cargo run zigbuild --target aarch64-unknown-linux-gnu --manifest-path tests/libhello/Cargo.toml
      - name: Linux - Test glibc run/test
        if: matrix.os == 'ubuntu-latest'
        run: |
          # Install qemu for `cargo-zigbuild run` support
          sudo apt-get update
          sudo apt-get install -y qemu-user qemu-user-static gcc-aarch64-linux-gnu binfmt-support
          sudo update-binfmts --enable qemu-aarch64
          export QEMU_LD_PREFIX=/usr/aarch64-linux-gnu

          cargo run run --target aarch64-unknown-linux-gnu --manifest-path tests/hello-rustls/Cargo.toml
          cargo run test --target aarch64-unknown-linux-gnu --manifest-path tests/hello-rustls/Cargo.toml
      - name: Linux - Test glibc build openssl
        if: matrix.os != 'windows-latest'
        run: |
          cargo run zigbuild --target aarch64-unknown-linux-gnu --manifest-path tests/hello-tls/Cargo.toml
      - name: Linux - Test musl libc build
        run: |
          rustup target add aarch64-unknown-linux-musl
          cargo run zigbuild --target aarch64-unknown-linux-musl
          cargo run zigbuild --target aarch64-unknown-linux-musl --manifest-path tests/hello-rustls/Cargo.toml
      - name: Windows - Test gnu build
        # We are having trouble building with zig 0.13+
        if: ${{ matrix.zig == '0.11.0' }}
        run: |
          cargo run zigbuild --target x86_64-pc-windows-gnu
          cargo run zigbuild --target x86_64-pc-windows-gnu --manifest-path tests/hello-windows/Cargo.toml
          cargo run zigbuild --target i686-pc-windows-gnu
          cargo run zigbuild --target i686-pc-windows-gnu --manifest-path tests/hello-windows/Cargo.toml
      - name: Windows - Test build curl
        if: matrix.os == 'windows-latest'
        run: |
          cargo run zigbuild --target aarch64-unknown-linux-gnu --manifest-path tests/hello-rustls/Cargo.toml --features curl
      - name: Windows - Test run
        if: ${{ matrix.os == 'windows-latest' && matrix.zig == '0.11.0' }}
        run: |
          ./target/x86_64-pc-windows-gnu/debug/cargo-zigbuild.exe zigbuild --help
          ./tests/hello-windows/target/x86_64-pc-windows-gnu/debug/hello-windows.exe

  fmt:
    name: Rustfmt
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt
      - run: cargo fmt --all -- --check

  clippy:
    name: Clippy
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy
      - run: cargo clippy --all-features

  spellcheck:
    name: spellcheck
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
      - uses: codespell-project/actions-codespell@master
