name: CI Build and Test

on:
  pull_request:
    branches:
      - main
      - "feature/**"
      - "release/**"
  merge_group:
  workflow_dispatch:

# Cancel in-progress run when a pull request is updated
# Code taken from:
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#example-using-a-fallback-value
concurrency:
  group: ${{ github.head_ref || github.run_id }}
  cancel-in-progress: true

env:
  CARGO_TERM_COLOR: always
  NODE_VERSION: "22.14.0"
  PYTHON_VERSION: "3.11"
  RUST_TOOLCHAIN_VERSION: "1.90"
  RUST_TOOLCHAIN_COMPONENTS: rustfmt clippy

jobs:
  format:
    name: Format
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: "true"
      - name: Setup rust toolchain
        uses: ./.github/actions/toolchains/rust
        with:
          toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
          components: ${{ env.RUST_TOOLCHAIN_COMPONENTS }}
      - name: Check Formatting
        run: cargo fmt --all -- --check

  clippy:
    name: Clippy
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: "true"
      - name: Setup rust toolchain
        uses: ./.github/actions/toolchains/rust
        with:
          toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
          components: ${{ env.RUST_TOOLCHAIN_COMPONENTS }}
      - uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/bin/
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            target/
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
      - name: Clippy Lints
        run: cargo clippy --all-targets --all-features -- -D warnings

  format-qsc:
    name: Format Q# Files
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: "true"
      - name: Setup rust toolchain
        uses: ./.github/actions/toolchains/rust
        with:
          toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
          components: ${{ env.RUST_TOOLCHAIN_COMPONENTS }}
      - name: Check Formatting for Libraries and Samples
        run: cargo run --release --bin qsc_formatter -- ./library/ ./samples/ -r

  web-check:
    name: Check web files
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          submodules: "true"
      - uses: actions/setup-node@v6
        with:
          node-version: ${{ env.NODE_VERSION }}
      - name: npm install
        run: npm install
      - name: npm check
        run: npm run check

  build:
    name: Build and test
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6
        with:
          submodules: "true"
      - name: Setup rust toolchain
        uses: ./.github/actions/toolchains/rust
        with:
          toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
          components: ${{ env.RUST_TOOLCHAIN_COMPONENTS }}
      - uses: actions/setup-python@v6
        with:
          python-version: ${{ env.PYTHON_VERSION }}
      - uses: actions/setup-node@v6
        with:
          node-version: ${{ env.NODE_VERSION }}
      - uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/bin/
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            target/
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
      - name: Prereqs
        run: python ./prereqs.py --install
      - name: Build and Test
        run: python ./build.py --no-check --wasm --npm --vscode --play --pip --widgets --jupyterlab --qdk

  unit-tests:
    name: Rust Unit tests
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6
        with:
          submodules: "true"
      - name: Setup rust toolchain
        uses: ./.github/actions/toolchains/rust
        with:
          toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
          components: ${{ env.RUST_TOOLCHAIN_COMPONENTS }}
      - uses: actions/setup-python@v6
        with:
          python-version: ${{ env.PYTHON_VERSION }}
      - uses: actions/setup-node@v6
        with:
          node-version: ${{ env.NODE_VERSION }}
      - uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/bin/
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            target/
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
      - name: Prereqs
        run: python ./prereqs.py --install
      - name: Build and Test
        run: python ./build.py --no-check --cli

  integration-tests:
    name: Integration tests
    timeout-minutes: 40
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6
        with:
          submodules: "true"
      - name: Setup rust toolchain
        uses: ./.github/actions/toolchains/rust
        with:
          toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
          components: ${{ env.RUST_TOOLCHAIN_COMPONENTS }}
      - uses: actions/setup-python@v6
        with:
          python-version: ${{ env.PYTHON_VERSION }}
      - uses: actions/setup-node@v6
        with:
          node-version: ${{ env.NODE_VERSION }}
      - uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/bin/
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            target/
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
      - name: Prereqs
        run: python ./prereqs.py --install
      - name: Run integration tests
        run: python ./build.py --no-check --no-test --wasm --npm --vscode --pip --widgets --qdk --integration-tests

  status-check:
    name: Status Check
    needs:
      [
        format,
        clippy,
        web-check,
        build,
        unit-tests,
        format-qsc,
        integration-tests,
      ]
    runs-on: ubuntu-latest
    if: failure()
    steps:
      - run: |
          echo "::error Build failed"
          exit 1
