name: ci/build

on:
  push:
  pull_request:
    paths-ignore:
      - docs/**
      - "**/README.md"

jobs:
  build_conda:
    name: conda (${{ matrix.os }}, ${{ matrix.backend }} ${{ matrix.python-version }})
    runs-on: ${{ matrix.os }}
    defaults:
      run:
        shell: bash -el {0}
    strategy:
      fail-fast: false
      matrix:
        # TODO revert. Despite documentation to the contrary, MacOS runners are always x86-64
        #os: ["ubuntu-latest", "windows-latest", "macos-latest"]
        os: ["ubuntu-latest", "windows-latest"]
        python-version: ["3.11", "3.12", "3.13"]
        backend: ["nvidia", "cpu", "rocm", "apple-silicon"]
        exclude:
          # CPU + Nvidia only on Windows
          - os: "windows-latest"
            backend: "rocm"
          - os: windows-latest
            backend: apple-silicon
          # No apple-silicon on Linux
          - os: ubuntu-latest
            backend: apple-silicon
          # Only Apple-Silicon on MacOS
          - os: "macos-latest"
            backend: "rocm"
          - os: "macos-latest"
            backend: "cpu"
          - os: "macos-latest"
            backend: "nvidia"
    steps:
      - uses: actions/checkout@v3
      - name: Cleanup space
        # We run out of space on rocm. Ref: https://github.com/actions/runner-images/issues/709
        if: matrix.backend == 'rocm'
        run: |
          sudo rm -rf "/usr/local/share/boost" "$AGENT_TOOLSDIRECTORY"
      - name: Set cache date
        run: echo "DATE=$(date +'%Y%m%d')" >> $GITHUB_ENV
      # TODO Re-enable. Currently disabled as it does not seem to get used and takes a lot of space
      #- name: Cache conda
      #  uses: actions/cache@v3
      #  env:
      #    # Increase this value to manually reset cache
      #    CACHE_NUMBER: 1
      #    REQ_FILE: ./requirements/requirements_${{ matrix.backend }}.txt
      #  with:
      #    path: ~/conda_pkgs_dir
      #    key: ${{ runner.os }}-${{ matrix.backend }}-conda-${{ matrix.python-version }}-${{ env.CACHE_NUMBER }}-${{ env.DATE }}-${{ hashFiles('./requirements/requirements.txt', env.REQ_FILE) }}
      - name: Set up Conda
        uses: conda-incubator/setup-miniconda@v2
        with:
          python-version: ${{ matrix.python-version }}
          miniconda-version: "latest"
          auto-update-conda: true
          activate-environment: faceswap
      - name: Conda info
        run: conda info && conda list
      - name: Install
        run: |
          python setup.py --installer --dev --${{ matrix.backend }}
          pip install wheel pytest-xvfb types-attrs types-cryptography types-pyOpenSSL
      - name: Lint with flake8
        run: |
          # stop the build if there are Python syntax errors or undefined names
          flake8 . --select=E9,F63,F7,F82 --show-source
          flake8 . --exit-zero
      - name: MyPy Typing
        continue-on-error: true
        run: |
          mypy .
      - name: SysInfo
        run: python -m lib.system.sysinfo
      - name: Unit Tests
        # These backends will fail as GPU drivers not available
        if: matrix.backend == 'cpu'
        run: |
         KERAS_BACKEND=torch FACESWAP_BACKEND="${{ matrix.backend }}" py.test -v tests/;
      - name: End to End Tests
        # These backends will fail as GPU drivers not available
        if: matrix.backend == 'cpu'
        run: |
          KERAS_BACKEND=torch FACESWAP_BACKEND="${{ matrix.backend }}" python tests/simple_tests.py;

  build_linux:
    name: "pip (ubuntu-latest, ${{ matrix.backend }} ${{ matrix.python-version }})"
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.11", "3.12", "3.13"]
        backend: ["cpu"]
        include:
          - backend: "cpu"
    steps:
      - uses: actions/checkout@v5
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v6
        with:
          python-version: ${{ matrix.python-version }}
          cache: 'pip'
          cache-dependency-path: |
            './requirements/requirements_base.txt'
            './requirements/requirements_${{ matrix.backend }}.txt'
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r ./requirements/requirements_${{ matrix.backend }}.txt
          pip install -r ./requirements/_requirements_dev.txt
          pip install wheel pytest-xvfb types-attrs types-cryptography types-pyOpenSSL
      - name: Lint with flake8
        run: |
          # stop the build if there are Python syntax errors or undefined names
          flake8 . --select=E9,F63,F7,F82 --show-source
          # exit-zero treats all errors as warnings.
          flake8 . --exit-zero
      - name: MyPy Typing
        continue-on-error: true
        run: |
          mypy .
      - name: SysInfo
        run: FACESWAP_BACKEND="${{ matrix.backend }}" python -m lib.system.sysinfo
      - name: Unit Tests
        run: |
          KERAS_BACKEND=torch FACESWAP_BACKEND="${{ matrix.backend }}" py.test -v tests/;
      - name: End to End Tests
        run: |
          KERAS_BACKEND=torch FACESWAP_BACKEND="${{ matrix.backend }}" python tests/simple_tests.py;

  build_windows:
    name: "pip (windows-latest, ${{ matrix.backend }} ${{ matrix.python-version }})"
    runs-on: windows-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.11", "3.12", "3.13"]
        backend: ["cpu"]
        include:
          - backend: "cpu"
    steps:
      - uses: actions/checkout@v5
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v6
        with:
          python-version: ${{ matrix.python-version }}
          cache: 'pip'
          cache-dependency-path: |
            './requirements/requirements_base.txt'
            './requirements/requirements_${{ matrix.backend }}.txt'
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install types-attrs types-cryptography types-pyOpenSSL wheel
          pip install -r ./requirements/_requirements_dev.txt
          pip install -r ./requirements/requirements_${{ matrix.backend }}.txt
      - name: Set Faceswap Backend EnvVar
        run: echo "FACESWAP_BACKEND=${{ matrix.backend }}" | Out-File -FilePath $env:GITHUB_ENV -Append
      - name: Set Keras Backend EnvVar
        run: echo "KERAS_BACKEND=torch" | Out-File -FilePath $env:GITHUB_ENV -Append
      - name: Lint with flake8
        run: |
          # stop the build if there are Python syntax errors or undefined names
          flake8 . --select=E9,F63,F7,F82 --show-source
          # exit-zero treats all errors as warnings.
          flake8 . --exit-zero
      - name: MyPy Typing
        continue-on-error: true
        run: |
          mypy .
      - name: SysInfo
        run: python -m lib.system.sysinfo
      - name: Unit Tests
        run: py.test -v tests
      - name: End to End Tests
        run: python tests/simple_tests.py
