on:
  pull_request:
  push:
    branches:
      - main
      - 'patch-release-*'

name: continuous-integration

env:
  NUSHELL_CARGO_PROFILE: ci
  NU_LOG_LEVEL: DEBUG
  # If changing these settings also change toolkit.nu
  CLIPPY_OPTIONS: "-D warnings -D clippy::unwrap_used -D clippy::unchecked_duration_subtraction"

concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
  cancel-in-progress: true

jobs:
  fmt-clippy:
    strategy:
      fail-fast: true
      matrix:
        # Pinning to Ubuntu 22.04 because building on newer Ubuntu versions causes linux-gnu
        # builds to link against a too-new-for-many-Linux-installs glibc version. Consider
        # revisiting this when 22.04 is closer to EOL (June 2027)
        #
        # Using macOS 13 runner because 14 is based on the M1 and has half as much RAM (7 GB,
        # instead of 14 GB) which is too little for us right now. Revisit when `dfr` commands are
        # removed and we're only building the `polars` plugin instead
        platform: [windows-latest, macos-13, ubuntu-22.04]

    runs-on: ${{ matrix.platform }}

    steps:
      - uses: actions/checkout@v4.1.7

      - name: Setup Rust toolchain and cache
        uses: actions-rust-lang/setup-rust-toolchain@v1.11.0

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

        # If changing these settings also change toolkit.nu
      - name: Clippy
        run: cargo clippy --workspace --exclude nu_plugin_* -- $CLIPPY_OPTIONS

        # In tests we don't have to deny unwrap
      - name: Clippy of tests
        run: cargo clippy --tests --workspace --exclude nu_plugin_* -- -D warnings

      - name: Clippy of benchmarks
        run: cargo clippy --benches --workspace --exclude nu_plugin_* -- -D warnings

  tests:
    strategy:
      fail-fast: true
      matrix:
        platform: [windows-latest, macos-latest, ubuntu-22.04]

    runs-on: ${{ matrix.platform }}

    steps:
      - uses: actions/checkout@v4.1.7

      - name: Setup Rust toolchain and cache
        uses: actions-rust-lang/setup-rust-toolchain@v1.11.0

      - name: Tests
        run: cargo test --workspace --profile ci --exclude nu_plugin_*
      - name: Check for clean repo
        shell: bash
        run: |
          if [ -n "$(git status --porcelain)" ]; then
            echo "there are changes";
            git status --porcelain
            exit 1
          else
            echo "no changes in working directory";
          fi

  std-lib-and-python-virtualenv:
    strategy:
      fail-fast: true
      matrix:
        platform: [ubuntu-22.04, macos-latest, windows-latest]
        py:
          - py

    runs-on: ${{ matrix.platform }}

    steps:
      - uses: actions/checkout@v4.1.7

      - name: Setup Rust toolchain and cache
        uses: actions-rust-lang/setup-rust-toolchain@v1.11.0

      - name: Install Nushell
        run: cargo install --path . --locked --force

      - name: Standard library tests
        run: nu -c 'use crates/nu-std/testing.nu; testing run-tests --path crates/nu-std'

      - name: Ensure that Cargo.toml MSRV and rust-toolchain.toml use the same version
        run: nu .github/workflows/check-msrv.nu

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.10"

      - name: Install virtualenv
        run: pip install virtualenv
        shell: bash

      - name: Test Nushell in virtualenv
        run: nu scripts/test_virtualenv.nu
        shell: bash

      - name: Check for clean repo
        shell: bash
        run: |
          if [ -n "$(git status --porcelain)" ]; then
            echo "there are changes";
            git status --porcelain
            exit 1
          else
            echo "no changes in working directory";
          fi

  plugins:
    strategy:
      fail-fast: true
      matrix:
        # Using macOS 13 runner because 14 is based on the M1 and has half as much RAM (7 GB,
        # instead of 14 GB) which is too little for us right now.
        #
        # Failure occurring with clippy for rust 1.77.2
        platform: [windows-latest, macos-13, ubuntu-22.04]

    runs-on: ${{ matrix.platform }}

    steps:
      - uses: actions/checkout@v4.1.7

      - name: Setup Rust toolchain and cache
        uses: actions-rust-lang/setup-rust-toolchain@v1.11.0

      - name: Clippy
        run: cargo clippy --package nu_plugin_* -- $CLIPPY_OPTIONS

      - name: Tests
        run: cargo test --profile ci --package nu_plugin_*

      - name: Check for clean repo
        shell: bash
        run: |
          if [ -n "$(git status --porcelain)" ]; then
            echo "there are changes";
            git status --porcelain
            exit 1
          else
            echo "no changes in working directory";
          fi

  wasm:
    env:
      WASM_OPTIONS: --no-default-features --target wasm32-unknown-unknown
      CLIPPY_CONF_DIR: ${{ github.workspace }}/clippy/wasm/

    strategy:
      matrix:
        job:
          - name: Build WASM
            command: cargo build
            args:
          - name: Clippy WASM
            command: cargo clippy
            args: -- $CLIPPY_OPTIONS

    name: ${{ matrix.job.name }}

    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4.1.7

      - name: Setup Rust toolchain and cache
        uses: actions-rust-lang/setup-rust-toolchain@v1.11.0

      - name: Add wasm32-unknown-unknown target
        run: rustup target add wasm32-unknown-unknown

      - run: ${{ matrix.job.command }} -p nu-cmd-base $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-cmd-extra $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-cmd-lang $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-color-config $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-command $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-derive-value $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-engine $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-glob $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-json $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-parser $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-path $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-pretty-hex $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-protocol $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-std $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-system $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-table $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-term-grid $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nu-utils $WASM_OPTIONS ${{ matrix.job.args }}
      - run: ${{ matrix.job.command }} -p nuon $WASM_OPTIONS ${{ matrix.job.args }}
