name: "CI"
on:
  pull_request:
    paths-ignore:
      - "release-plz.toml"
  push:
    paths-ignore:
      - "docs/**"
      - "**.md"
      - "LICENSE"
      - "release-plz.toml"
    branches:
      - main

env:
  RUST_BACKTRACE: 1
  CARGO_TERM_COLOR: always
  CLICOLOR: 1
  CLICOLOR_FORCE: 1

permissions:
  actions: read
  contents: read

# Only allow one run of the workflow per branch / PR at a time.
concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  # Build and upload release binaries for all relevant architectures.
  build:
    strategy:
      fail-fast: false
      matrix:
        include:
          # Build for x86_64/linux target on native host.
          # N.B. We intentionally pin to Ubuntu 22.04 for now to increase
          # the range of distros that will be able to run the produced binaries.
          # Newer release of Ubuntu upgrade glibc to a point not yet supported
          # by some latest stable versions of distros.
          - host: "ubuntu-22.04"
            target: ""
            cross_command: ""
            cross_tool_to_install: ""
            os: "linux"
            arch: "x86_64"
            binary_name: "brush"
            extra_build_args: ""
          # Build for x86_64/linux using musl as target C runtime.
          # We don't bother pinning to an ealier version of Ubuntu because
          # the produced binary will statically link the C runtime anyhow.
          - host: "ubuntu-24.04"
            target: "x86_64-unknown-linux-musl"
            cross_command: "cross"
            cross_tool_to_install: "cross"
            os: "linux-musl"
            arch: "x86_64"
            binary_name: "brush"
            extra_build_args: ""
          # Build for aarch64/macos target on native host.
          - host: "macos-latest"
            target: ""
            cross_command: ""
            cross_tool_to_install: ""
            os: "macos"
            arch: "aarch64"
            required_tools: ""
            binary_name: "brush"
            extra_build_args: ""
          # Build for aarch64/linux target on x86_64/Linux host.
          - host: "ubuntu-24.04"
            target: "aarch64-unknown-linux-gnu"
            cross_command: "cross"
            cross_tool_to_install: "cross"
            os: "linux"
            arch: "aarch64"
            required_tools: "gcc-aarch64-linux-gnu"
            binary_name: "brush"
            extra_build_args: ""
          # Build for wasm32 target on x86_64/linux host.
          - host: "ubuntu-24.04"
            target: "wasm32-unknown-unknown"
            cross_command: "cross"
            cross_tool_to_install: "cross"
            os: "unknown"
            arch: "wasm32"
            required_tools: ""
            binary_name: "brush.wasm"
            extra_build_args: "--no-default-features --features minimal"
          # Build for WASI-0.2 target on x86_64/linux host.
          - host: "ubuntu-24.04"
            target: "wasm32-wasip2"
            cross_command: "cross"
            cross_tool_to_install: "cross"
            os: "wasi-0.2"
            arch: "wasm32"
            required_tools: ""
            binary_name: "brush.wasm"
            extra_build_args: "--no-default-features --features minimal"
          # Build for x86_64/windows target on x86_64/linux host.
          - host: "ubuntu-24.04"
            target: "x86_64-pc-windows-gnu"
            cross_command: "cross"
            cross_tool_to_install: "cross"
            os: "windows"
            arch: "x86_64"
            required_tools: ""
            binary_name: "brush.exe"
            extra_build_args: ""
          # Build for x86_64/android target on x86_64/linux host.
          - host: "ubuntu-24.04"
            target: "x86_64-linux-android"
            cross_command: "cargo ndk"
            cross_tool_to_install: "cargo-ndk"
            os: "android"
            arch: "x86_64"
            required_tools: ""
            binary_name: "brush"
            extra_build_args: ""

    name: "Build (${{ matrix.arch }}/${{ matrix.os }})"
    runs-on: ${{ matrix.host }}
    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: Set up rust toolchain
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
        with:
          toolchain: stable
          targets: ${{ matrix.target }}

      - name: Enable cargo cache
        uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
        with:
          key: "${{ matrix.target }}"

      - name: Install additional prerequisite tools
        if: ${{ matrix.required_tools != '' }}
        env:
          REQUIRED_TOOLS: ${{ matrix.required_tools }}
        run: sudo apt-get update -y && sudo apt-get install -y ${REQUIRED_TOOLS}

      - name: Install cross-compilation toolchain
        if: ${{ matrix.target != '' }}
        uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18
        with:
          tool: ${{ matrix.cross_tool_to_install }}

      - name: "Build (native)"
        if: ${{ matrix.target == '' }}
        env:
          EXTRA_BUILD_ARGS: ${{ matrix.extra_build_args }}
        run: cargo build --release --all-targets ${EXTRA_BUILD_ARGS}

      - name: "Build (cross)"
        if: ${{ matrix.target != '' }}
        env:
          CROSS_COMMAND: ${{ matrix.cross_command }}
          TARGET: ${{ matrix.target }}
          EXTRA_BUILD_ARGS: ${{ matrix.extra_build_args }}
          CARGO_NDK_PLATFORM: 24
        run: ${CROSS_COMMAND} build --release --target=${TARGET} ${EXTRA_BUILD_ARGS}

      - name: "Upload binaries"
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: binaries-${{ matrix.arch }}-${{ matrix.os }}
          path: target/${{ matrix.target }}/release/${{ matrix.binary_name }}

      - name: "Upload integration test binaries"
        if: ${{ matrix.target == '' }}
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: integration-tests-${{ matrix.arch }}-${{ matrix.os }}
          path: |
            target/${{ matrix.target }}/release/deps/brush_*_tests-*
            !**/*.d

  # Test functional correctness
  test:
    strategy:
      fail-fast: false
      matrix:
        include:
          - host: "ubuntu-24.04"
            variant: "linux-x86_64"
            artifact_suffix: "linux-x86_64"
            name_suffix: "(linux/x86_64)"
            homebrew_supported: true
            coverage: true
            coverage_min_percent: 70

          - host: "ubuntu-24.04-arm"
            variant: "linux-aarch64"
            artifact_suffix: "linux-aarch64"
            name_suffix: "(linux/aarch64)"
            homebrew_supported: false
            coverage: true
            coverage_min_percent: 70

          - host: "macos-latest"
            variant: "macos"
            artifact_suffix: "-macos"
            name_suffix: "(macOS)"
            homebrew_supported: true
            coverage: true
            coverage_min_percent: 70

          - host: "windows-2025"
            variant: "windows"
            artifact_suffix: "-windows"
            name_suffix: "(windows)"
            homebrew_supported: false
            coverage: true
            coverage_min_percent: 20

          - host: "ubuntu-24.04"
            variant: "wasi"
            artifact_suffix: "-wasi"
            name_suffix: "(wasm32/wasi-0.2)"
            homebrew_supported: false
            coverage: false
            extra_rust_targets: "wasm32-wasip2"
            wasi_runtime: "wasmtime"
            xtask_test_args: "--wasi"

    name: "Test ${{ matrix.name_suffix }}"
    runs-on: ${{ matrix.host }}
    defaults:
      run:
        shell: bash
    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: Set up rust toolchain
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
        with:
          toolchain: stable
          targets: ${{ matrix.extra_rust_targets || '' }}
          components: llvm-tools-preview

      - name: Enable cargo cache
        uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
        with:
          # Needed to make sure cargo-deny is correctly cached.
          cache-all-crates: true

      - name: Install cargo-nextest
        uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18
        with:
          tool: cargo-nextest

      - name: Install cargo-llvm-cov
        if: ${{ matrix.coverage }}
        uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18
        with:
          tool: cargo-llvm-cov

      - name: Install WASI runtime
        if: ${{ matrix.wasi_runtime }}
        uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18
        with:
          tool: ${{ matrix.wasi_runtime }}

      - name: Set up Homebrew
        if: ${{ matrix.homebrew_supported }}
        id: set-up-homebrew
        # We ignore the stale-action-refs check because this action does not have any releases or tags.
        # We're forced to pick a specific commit.
        uses: Homebrew/actions/setup-homebrew@b04401e20b1aef21843d7c3e261d27a89f65af7d # zizmor: ignore[stale-action-refs]
        with:
          stable: true

      - name: "Install recent bash for tests"
        if: ${{ matrix.homebrew_supported }}
        run: |
          set -x

          # Install it
          brew install bash

          # Find the path
          BASH_PATH="$(brew --prefix bash)/bin/bash"

          # Log what we're using
          echo "Using bash from: ${BASH_PATH}"
          echo "bash version:"
          ${BASH_PATH} --version
          echo "BASH_PATH=${BASH_PATH}">>$GITHUB_ENV

      - name: "Download recent bash-completion sources for tests"
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
          repository: "scop/bash-completion"
          ref: "2.17.0"
          path: "bash-completion"

      - name: "Setup bash-completion"
        run: echo "BASH_COMPLETION_PATH=${GITHUB_WORKSPACE}/bash-completion/bash_completion">>$GITHUB_ENV

      - name: Test
        env:
          VARIANT: ${{ matrix.variant }}
        run: |
          args="${{ matrix.xtask_test_args || '' }}"
          args="${args} --results-output ./test-results-${VARIANT}.xml"
          if [[ "${{ matrix.coverage }}" == "true" ]]; then
            args="${args} --coverage --coverage-output ./codecov-${VARIANT}.xml"
          fi
          cargo xtask test integration ${args}

      - name: "Upload test results"
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        if: always()
        with:
          name: test-reports${{ matrix.artifact_suffix }}
          path: test-results-*.xml

      - name: "Generate code coverage report"
        uses: clearlyip/code-coverage-report-action@9e2cd22e39153feba8b4477e4fefcc0b5e2727ba # v6.0
        if: ${{ always() && matrix.coverage }}
        id: "code_coverage_report"
        with:
          artifact_download_workflow_names: "CI"
          artifact_name: coverage-%name%${{ matrix.artifact_suffix }}
          filename: codecov-${{ matrix.variant }}.xml
          overall_coverage_fail_threshold: ${{ matrix.coverage_min_percent }}
          only_list_changed_files: ${{ github.event_name == 'pull_request' }}
          fail_on_negative_difference: true
          negative_difference_by: "overall"
          negative_difference_threshold: 5

      - name: "Upload code coverage report"
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        if: always()
        with:
          name: codecov-reports${{ matrix.artifact_suffix }}
          path: code-coverage-results.md

  # Static analysis of the code.
  check:
    name: "Source code checks"
    runs-on: ${{ matrix.os }}

    strategy:
      matrix:
        # Test latest stable as well as MSRV.
        rust-version: ["stable", "1.88.0"]
        # Run checks on Linux, Windows, and macOS.
        os: ["ubuntu-24.04", "windows-2025", "macos-latest"]

    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: Set up rust toolchain (${{ matrix.rust-version }})
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
        with:
          toolchain: ${{ matrix.rust-version }}
          components: clippy, rustfmt

      - name: Enable cargo cache
        uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
        with:
          # Needed to make sure cargo-deny is correctly cached.
          cache-all-crates: true

      - name: Format check
        run: cargo xtask check fmt

      - name: Check
        run: cargo xtask check build

      - name: Install cargo-deny
        if: runner.os == 'Linux'
        uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18
        with:
          tool: cargo-deny

      # NOTE: Only run on Linux. cargo-deny checks (advisories, licenses, bans,
      # sources) are platform-independent, so running on one OS is sufficient.
      # Also works around a cargo-deny 0.19.x bug where its advisory DB parser
      # panics on Windows due to CRLF line endings (hardcoded LF-only matching).
      - name: Deny check
        if: runner.os == 'Linux'
        run: cargo xtask check deps

      - name: Clippy check
        if: matrix.rust-version == 'stable'
        run: cargo xtask check lint

  # Check for unneeded dependencies.
  check-deps:
    name: "Check for unneeded dependencies"
    runs-on: ubuntu-24.04
    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: Set up nightly rust toolchain
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
        with:
          toolchain: nightly

      - name: Install cargo-udeps
        uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18
        with:
          tool: cargo-udeps

      - name: Check for unused dependencies
        run: cargo xtask check unused-deps

  # Check that generated schemas are up-to-date
  check-schemas:
    name: "Check generated schemas"
    runs-on: ubuntu-24.04
    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: Set up rust toolchain
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
        with:
          toolchain: stable

      - name: Enable cargo cache
        uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1

      - name: Check generated schemas
        run: cargo xtask check schemas

  # Analyze public API surface
  analyze-public-api:
    if: github.event_name == 'pull_request'
    name: "Analyze public API"
    runs-on: ubuntu-24.04
    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: Set up nightly rust toolchain
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
        with:
          toolchain: nightly

      - name: Install cargo-public-api
        uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18
        with:
          tool: cargo-public-api

      - name: Set up branches
        run: |
          set -euo pipefail
          git fetch origin main

      - name: Compare public APIs with main
        run: cargo xtask analyze public-api --base origin/main --output-dir reports

      - name: Upload test report
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: test-reports-public-api
          path: reports/*.md

  # Performance analysis of the code.
  benchmark:
    if: github.event_name == 'pull_request'
    name: "Benchmarks"
    runs-on: ubuntu-24.04
    steps:
      - name: Checkout PR sources
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
          path: pr

      - name: Checkout main sources
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
          path: main
          ref: main

      - name: Set up rust toolchain
        uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
        with:
          toolchain: stable

      - name: Enable cargo cache
        uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
        with:
          workspaces: |
            ./pr
            ./main

      - name: Performance analysis on PR
        run: cargo xtask analyze bench --output benchmarks.txt
        working-directory: pr

      - name: Performance analysis on main
        run: cargo bench --workspace --benches -- --output-format bencher | tee benchmarks.txt
        working-directory: main

      - name: Compare benchmark results
        run: |
          ./pr/scripts/compare-benchmark-results.py -b main/benchmarks.txt -t pr/benchmarks.txt >benchmark-results.md

      - name: Upload performance results
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: perf-reports
          path: |
            pr/benchmarks.txt
            main/benchmarks.txt
            benchmark-results.md

  # Run bash-completion test suite
  bash-completion-tests:
    name: "External tests / bash-completion test suite"
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Checkout brush
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
          path: "brush"

      - name: Checkout bash-completion
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
          repository: "scop/bash-completion"
          ref: "2.16.0"
          path: "bash-completion"

      - name: Download prebuilt brush binaries
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          name: "binaries-x86_64-linux"
          path: "binaries"

      - name: Setup downloads
        run: |
          chmod +x binaries/*
          ls -l binaries

      - name: Install prerequisites for running tests
        run: |
          set -x
          sudo apt-get update -y
          sudo apt-get install -y python3
          python3 -m pip install --user pytest pytest-xdist pytest-md-report pytest-json-report

      - name: "Run test suite (brush)"
        working-directory: brush
        run: |
          cargo xtask test \
              --brush-path $GITHUB_WORKSPACE/binaries/brush \
              external bash-completion \
              --bash-completion-path $GITHUB_WORKSPACE/bash-completion \
              --output $GITHUB_WORKSPACE/test-results-bash-completion.json \
              --summary-output $GITHUB_WORKSPACE/test-results-bash-completion.md || true

      - name: Upload test report
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: test-reports-bash-completion
          path: |
            test-results-bash-completion.md

  # Test release binary on a variety of OS platforms.
  os-tests:
    strategy:
      fail-fast: false
      matrix:
        include:
          # N.B. We don't include Ubuntu because it's already covered by the initial test job.
          - container: "archlinux:latest"
            description: "Arch Linux/latest"
            prereqs_command: "pacman -Sy --noconfirm bash-completion iputils grep less sed util-linux"

          - container: "mcr.microsoft.com/azurelinux/base/core:3.0"
            description: "Azure Linux/3.0"
            prereqs_command: "tdnf install -y bash-completion ca-certificates git iputils grep less sed util-linux"

          - container: "debian:testing"
            description: "Debian/testing"
            prereqs_command: "apt-get update -y && apt-get install -y bash-completion bsdmainutils iputils-ping grep less sed"

          - container: "fedora:latest"
            description: "Fedora/latest"
            prereqs_command: "dnf install -y bash-completion iputils grep less sed util-linux"

          # NOTE: NixOS tests are temporarily disabled due to containerd v2.2.0+ regression.
          # The nixos/nix image uses absolute symlinks for /etc/passwd and /etc/group which
          # causes "path escapes from parent" errors during container initialization.
          # This cannot be worked around from within the container since the error occurs
          # before any workflow steps run.
          # Reference: https://github.com/containerd/containerd/issues/12683
          # Reference: https://github.com/actions/runner-images/issues/13682
          # TODO: Re-enable when containerd or NixOS fixes the upstream issue.
          # - container: "nixos/nix:latest"
          #   description: "NixOS/latest"
          #   prereqs_command: "nix --extra-experimental-features nix-command --extra-experimental-features flakes profile install nixpkgs#gnused nixpkgs#hexdump nixpkgs#bash-completion"

          # NOTE: We use Tumbleweed to make sure we get a recent enough version of bash.
          - container: "opensuse/tumbleweed:latest"
            description: "openSUSE Tumbleweed/latest"
            prereqs_command: "zypper install -y bash-completion git"

    name: "OS target tests (${{ matrix.description }})"
    runs-on: ubuntu-24.04
    container: ${{ matrix.container }}
    needs: build
    env:
      # Reference: https://github.com/Azure/azure-cli/issues/29835
      GNUPGHOME: /root/.gnupg
    steps:
      # Install prerequisites *first*; may need some of them for checkout itself.
      - name: Install prerequisites
        if: ${{ matrix.prereqs_command != '' }}
        env:
          PREREQS_COMMAND: ${{ matrix.prereqs_command }}
        run: bash -c "${PREREQS_COMMAND}"

      # Workaround path issues on NixOS
      - name: "Apply workarounds: NixOS"
        if: ${{ matrix.container == 'nixos/nix:latest' }}
        run: |
          set -x

          # Allow use of experimental features to avoid nix from complaining.
          export NIX_CONFIG="extra-experimental-features = nix-command flakes"

          # Hacks to get the mounted nodejs by github actions work as it's dynamically linked
          # https://github.com/actions/checkout/issues/334#issuecomment-716068696
          nix build --no-link --max-jobs 2 --cores 0 'nixpkgs#stdenv.cc.cc.lib' 'nixpkgs#glibc'
          echo "LD_LIBRARY_PATH=$(nix path-info 'nixpkgs#stdenv.cc.cc.lib')/lib" >> "$GITHUB_ENV"
          ln -s "$(nix path-info 'nixpkgs#glibc' --recursive | grep glibc | grep -v bin)/lib64" /lib64

          # Provide alternate path for bash-completion
          echo "BASH_COMPLETION_PATH=$(nix path-info 'nixpkgs#bash-completion')/share/bash-completion/bash_completion">>"$GITHUB_ENV"

          # Forcibly add system paths
          echo "BRUSH_TEST_PATH_VAR=$PATH">>"$GITHUB_ENV"

      # Checkout sources for YAML-based test cases
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
          path: sources

      - name: Download prebuilt brush binaries
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          name: binaries-x86_64-linux
          path: binaries

      - name: Download integration test binaries
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          name: integration-tests-x86_64-linux
          path: binaries

      - name: Setup downloads
        run: |
          # N.B. Can't use -o pipefail because it's not supported on Debian.
          set -eux
          chmod +x binaries/*
          ls -l -R sources/brush-shell/tests
          ls -l binaries

      - name: Run tests
        shell: bash
        run: |
          export BRUSH_PATH=$PWD/binaries/brush
          export BRUSH_VERBOSE=true

          result=0
          for test_name in binaries/*tests*; do
            if [[ ${test_name} == *compat* ]]; then
              export BRUSH_TEST_CASES=$PWD/sources/brush-shell/tests/cases/compat
            elif [[ ${test_name} == *integration* ]]; then
              export BRUSH_TEST_CASES=$PWD/sources/brush-shell/tests/cases/brush
            elif [[ ${test_name} == *interactive* || ${test_name} == *version* ]]; then
              # TODO(tests): Re-enable these tests.
              echo "WARNING: skipping test: ${test_name}"
              continue
            fi

            echo "Running test: ${test_name}"
            chmod +x ${test_name}
            ${test_name} || result=$?
          done

          exit ${result}
