name: CI
on: [push, pull_request]

jobs:

  build-and-test-ubuntu:
    #if: false  # Temporarily disable
    name: Build And Test Ubuntu ${{ matrix.row }}
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        include:
          - row: clang-openssl-baseline
            compiler: clang
            build_dir: build-ci-quick-clang
            sanitizer: none
            use_webrtc: false
            crypto: default
            crypto25519: default
            targets: "test_connection test_p2p trivial_signaling_server publish_test_script test_crypto"
            run_tests: true
            tests: "test_crypto test_connection:suite-quick test_p2p.py:--spewlevel=debug:--loglevel-p2prendezvous=debug"
          - row: gcc-openssl-crypto
            compiler: gcc
            build_dir: build-ci-quick-gcc
            sanitizer: none
            use_webrtc: false
            crypto: default
            crypto25519: default
            targets: "test_connection test_p2p trivial_signaling_server publish_test_script test_crypto"
            run_tests: true
            tests: "test_crypto test_connection:suite-quick test_p2p.py:--spewlevel=debug:--loglevel-p2prendezvous=debug"
          - row: clang-libsodium
            compiler: clang
            build_dir: build-ci-quick-sodium
            sanitizer: none
            use_webrtc: false
            crypto: libsodium
            crypto25519: libsodium
            targets: "test_connection test_p2p trivial_signaling_server publish_test_script test_crypto"
            run_tests: true
            tests: "test_crypto test_connection:suite-quick test_p2p.py:--spewlevel=debug:--loglevel-p2prendezvous=debug"
          - row: clang-reference-25519
            compiler: clang
            build_dir: build-ci-quick-ref25519
            sanitizer: none
            use_webrtc: false
            crypto: default
            crypto25519: Reference
            targets: "test_connection test_p2p trivial_signaling_server publish_test_script test_crypto"
            run_tests: true
            tests: "test_crypto test_connection:suite-quick test_p2p.py:--spewlevel=debug:--loglevel-p2prendezvous=debug"
          - row: clang-openssl-webrtc
            compiler: clang
            build_dir: build-ci-quick-webrtc
            sanitizer: none
            use_webrtc: true
            crypto: default
            crypto25519: default
            targets: "test_connection test_p2p trivial_signaling_server publish_test_script test_crypto"
            run_tests: true
            tests: "test_crypto test_connection:suite-quick test_p2p.py:--spewlevel=debug:--loglevel-p2prendezvous=debug"
    env:
      CI_BUILD: 1
      IMAGE: ubuntu
      IMAGE_TAG: noble
    steps:
      - uses: actions/checkout@main
      # Note only alpine needs "preinstall" step
      - name: Update packages
        run: sudo -E bash .github/update-packages.sh
      - name: Install dependencies
        run: |
          sudo -E bash .github/install.sh
          sudo -E bash .github/install-post.sh
      - name: Build and test (RelWithDebInfo)
        run: |
          set -euo pipefail

          args=(
            --compiler "${{ matrix.compiler }}"
            --build-dir "${{ matrix.build_dir }}"
            --sanitizer "${{ matrix.sanitizer }}"
          )

          if [[ "${{ matrix.use_webrtc }}" == "true" ]]; then
            args+=(--use-webrtc)
          fi

          if [[ "${{ matrix.crypto }}" != "default" ]]; then
            args+=(--crypto "${{ matrix.crypto }}")
          fi

          if [[ "${{ matrix.crypto25519 }}" != "default" ]]; then
            args+=(--crypto25519 "${{ matrix.crypto25519 }}")
          fi

          if [[ -n "${{ matrix.targets }}" ]]; then
            read -r -a target_args <<< "${{ matrix.targets }}"
            args+=(--targets "${target_args[@]}")
          fi

          if [[ "${{ matrix.run_tests }}" == "true" ]]; then
            args+=(--run-tests)
            if [[ -n "${{ matrix.tests }}" ]]; then
              read -r -a test_args <<< "${{ matrix.tests }}"
              args+=(--tests "${test_args[@]}")
            fi
          fi

          python3 .github/run-single-config.py "${args[@]}"

      - name: Build (Release)
        run: |
          set -euo pipefail

          args=(
            --compiler "${{ matrix.compiler }}"
            --build-dir "build-release"
            --build-type Release
            --sanitizer none
          )

          if [[ "${{ matrix.use_webrtc }}" == "true" ]]; then
            args+=(--use-webrtc)
          fi

          if [[ "${{ matrix.crypto }}" != "default" ]]; then
            args+=(--crypto "${{ matrix.crypto }}")
          fi

          if [[ "${{ matrix.crypto25519 }}" != "default" ]]; then
            args+=(--crypto25519 "${{ matrix.crypto25519 }}")
          fi

          python3 .github/run-single-config.py "${args[@]}"

      - name: Build (Debug)
        run: |
          set -euo pipefail

          args=(
            --compiler "${{ matrix.compiler }}"
            --build-dir "build-debug"
            --build-type Debug
            --sanitizer none
          )

          if [[ "${{ matrix.use_webrtc }}" == "true" ]]; then
            args+=(--use-webrtc)
          fi

          if [[ "${{ matrix.crypto }}" != "default" ]]; then
            args+=(--crypto "${{ matrix.crypto }}")
          fi

          if [[ "${{ matrix.crypto25519 }}" != "default" ]]; then
            args+=(--crypto25519 "${{ matrix.crypto25519 }}")
          fi

          python3 .github/run-single-config.py "${args[@]}"

      # Don't do it this way.  This causes the main badge to
      # go red if one of the flavors fails.
      ## Trigger testing of more linux flavors
      #- name: Trigger linux flavors build
      #  uses: peter-evans/repository-dispatch@v2
      #  with:
      #    event-type: build-linux-flavors

  build-and-test-windows:
    #if: false  # Temporarily disable
    name: Build And Test Windows ${{ matrix.os-version }} ${{ matrix.crypto }}
    runs-on: windows-${{ matrix.os-version }}
    strategy:
      fail-fast: false
      matrix:
        # Windows Server 2019 has been retired. The Windows Server 2019 image has been removed as of 2025-06-30. For more details, see https://github.com/actions/runner-images/issues/12045
        os-version: [2022, 2025]
        crypto: [OpenSSL, BCrypt]
    env:
      VCPKG_ROOT: ${{ github.workspace }}/vcpkg
      VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg-bincache
      VCPKG_BINARY_SOURCES: clear;files,${{ github.workspace }}/vcpkg-bincache,readwrite
    steps:
      - uses: actions/checkout@main

      # Mark all directories as safe so checkouts performed in CMakeLists.txt don't cause "unsafe repository" errors.
      # See https://github.com/actions/checkout/issues/766
      - name: Configure Git
        run: git config --global --add safe.directory '*'
        shell: cmd

      - uses: lukka/get-cmake@latest

      # Setup MSVC command prompt environment vars.
      # We must do this before sedtting up our local vcpkg,
      # Because it will set VCPKG_ROOT to point to some global
      # install of vcpkg, and we don't want that
      - uses: ilammy/msvc-dev-cmd@v1

      - name: set VCPKG_ROOT
        run: |
          "VCPKG_ROOT=${{ github.workspace }}/vcpkg" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
        shell: pwsh

      - name: Setup local vcpkg
        run: |
          git clone https://github.com/microsoft/vcpkg.git "${{ env.VCPKG_ROOT }}"
          cd /d "${{ env.VCPKG_ROOT }}"
          git checkout c3867e714dd3a51c272826eea77267876517ed99
          call bootstrap-vcpkg.bat -disableMetrics
        shell: cmd

      - name: Ensure vcpkg cache directories exist
        run: |
          New-Item -ItemType Directory -Path "${{ env.VCPKG_ROOT }}/downloads" -Force | Out-Null
          New-Item -ItemType Directory -Path "${{ env.VCPKG_DEFAULT_BINARY_CACHE }}" -Force | Out-Null
        shell: pwsh

      - name: Restore vcpkg caches
        uses: actions/cache@v4
        with:
          path: |
            ${{ env.VCPKG_ROOT }}/downloads
            ${{ env.VCPKG_DEFAULT_BINARY_CACHE }}
          key: vcpkg-${{ runner.os }}-${{ matrix.os-version }}-${{ matrix.crypto }}-${{ env.VCToolsVersion }}-c3867e714dd3a51c272826eea77267876517ed99-${{ hashFiles('vcpkg.json') }}
          restore-keys: |
            vcpkg-${{ runner.os }}-${{ matrix.os-version }}-${{ matrix.crypto }}-${{ env.VCToolsVersion }}-
            vcpkg-${{ runner.os }}-${{ matrix.os-version }}-${{ matrix.crypto }}-

      - name: vcpkg check / install dependencies
        working-directory: '${{ github.workspace }}'
        run: '"${{env.VCPKG_ROOT}}\vcpkg" install --vcpkg-root "${{env.VCPKG_ROOT}}" --triplet=x64-windows'
        shell: cmd

      - name: Configure CMake (RelWithDebInfo)
        run: |
          mkdir build
          cd build
          cmake -S .. -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON -DBUILD_TOOLS=ON "-DCMAKE_TOOLCHAIN_FILE=${{env.VCPKG_ROOT}}/scripts/buildsystems/vcpkg.cmake" -DUSE_CRYPTO=${{matrix.crypto}}
        shell: cmd

      - name: Build (RelWithDebInfo)
        working-directory: '${{ github.workspace }}/build'
        run: ninja
        shell: cmd

      - name: Test crypto
        working-directory: '${{ github.workspace }}/build/bin'
        run: test_crypto.exe
        shell: cmd

      - name: Test connection
        working-directory: '${{ github.workspace }}/build/bin'
        run: test_connection.exe suite-quick
        shell: cmd

      - name: Test p2p
        working-directory: '${{ github.workspace }}/build/bin'
        run: py -3 test_p2p.py --spewlevel=debug --loglevel-p2prendezvous=debug
        shell: cmd

      - name: Configure CMake (Release)
        run: |
          mkdir build-release
          cd build-release
          cmake -S .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON -DBUILD_TOOLS=ON "-DCMAKE_TOOLCHAIN_FILE=${{env.VCPKG_ROOT}}/scripts/buildsystems/vcpkg.cmake" -DUSE_CRYPTO=${{matrix.crypto}}
        shell: cmd

      - name: Build (Release)
        working-directory: '${{ github.workspace }}/build-release'
        run: ninja
        shell: cmd

      - name: Configure CMake (Debug)
        run: |
          mkdir build-debug
          cd build-debug
          cmake -S .. -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON -DBUILD_TOOLS=ON "-DCMAKE_TOOLCHAIN_FILE=${{env.VCPKG_ROOT}}/scripts/buildsystems/vcpkg.cmake" -DUSE_CRYPTO=${{matrix.crypto}}
        shell: cmd

      - name: Build (Debug)
        working-directory: '${{ github.workspace }}/build-debug'
        run: ninja
        shell: cmd
