name: Tests

on:
  push:
    branches:
      - master
      - checks
  pull_request:
    branches:
      - master

jobs:
  changes:
    name: "Check for changes"
    runs-on: ubuntu-latest
    outputs:
      changes: ${{ steps.changes.outputs.src }}
    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - uses: dorny/paths-filter@v2
        id: changes
        with:
          filters: |
            python: &python
            - 'theano/**/*.py'
            - 'tests/**/*.py'
            - '*.py'
            src:
            - *python
            - '.github/**/*.yml'
            - 'setup.cfg'
            - 'requirements.txt'
            - '.coveragerc'

  style:
    name: Check code style
    needs: changes
    runs-on: ubuntu-latest
    if: ${{ needs.changes.outputs.changes == 'true' }}
    steps:
      - uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v1
        with:
          python-version: 3.7
      - name: Install dependencies
        run: |
          python -m pip install -U pip
          python -m pip install -U black flake8 isort
      - name: Check the style
        run: |
          black -t py36 --check theano/ tests/ setup.py conftest.py
          isort --check theano/ tests/ setup.py conftest.py
          flake8

  test:
    name: "Test py${{ matrix.python-version }}: ${{ matrix.part }}"
    needs:
      - changes
      - style
    runs-on: ubuntu-latest
    if: ${{ needs.changes.outputs.changes == 'true' && needs.style.result == 'success' }}
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.6", "3.7"]
        fast-compile: [0]
        float32: [0]
        part:
          - "tests --ignore=tests/tensor --ignore=tests/sparse --ignore=tests/tensor/nnet"
          - "tests/tensor tests/sparse --ignore=tests/tensor/test_basic.py --ignore=tests/tensor/test_basic_scipy.py --ignore=tests/tensor/test_inplace.py --ignore=tests/tensor/test_elemwise.py --ignore=tests/tensor/test_opt.py --ignore=tests/tensor/nnet"
          - "tests/tensor/test_basic.py tests/tensor/test_basic_scipy.py tests/tensor/test_inplace.py"
          - "tests/tensor/test_elemwise.py tests/tensor/test_opt.py"
          - "tests/tensor/nnet --ignore-glob='*/test_abstract_conv.py'"
          - "tests/tensor/nnet/test_abstract_conv.py"
        include:
          - python-version: "3.7"
            fast-compile: 1
            float32: 1
            part: "tests --ignore=tests/tensor/nnet --ignore=tests/tensor/signal"
          - python-version: "3.7"
            fast-compile: 1
            float32: 0
            part: "tests --ignore=tests/tensor/nnet --ignore=tests/tensor/signal"
          - python-version: "3.7"
            fast-compile: 1
            float32: 1
            part: "tests/tensor/nnet"
          - python-version: "3.7"
            fast-compile: 1
            float32: 0
            part: "tests/tensor/nnet"
          - python-version: "3.7"
            fast-compile: 1
            float32: 1
            part: "tests/tensor/signal"
          - python-version: "3.7"
            fast-compile: 1
            float32: 0
            part: "tests/tensor/signal"

    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Set up Python ${{ matrix.python-version }}
        uses: conda-incubator/setup-miniconda@v2
        with:
          mamba-version: "*"
          channels: conda-forge,defaults
          channel-priority: true
          python-version: ${{ matrix.python-version }}
          auto-update-conda: true

      - name: Create matrix id
        id: matrix-id
        env:
          MATRIX_CONTEXT: ${{ toJson(matrix) }}
        run: |
          echo $MATRIX_CONTEXT
          export MATRIX_ID=`echo $MATRIX_CONTEXT | md5sum | cut -c 1-32`
          echo $MATRIX_ID
          echo "::set-output name=id::$MATRIX_ID"

      - name: Install dependencies
        shell: bash -l {0}
        run: |
          mamba install --yes -q mkl numpy scipy pip mkl-service graphviz cython libgpuarray pygpu
          if [[ "$PYTHON_VERSION" != "3.6" ]]; then mamba install --yes -q -c conda-forge jax jaxlib; fi
          pip install -q -r requirements.txt
          mamba list && pip freeze
          python -c 'import theano; print(theano.config.__str__(print_doc=False))'
          python -c 'import theano; assert(theano.config.blas__ldflags != "")'
        env:
          PYTHON_VERSION: ${{ matrix.python-version }}

      - name: Run tests
        shell: bash -l {0}
        run: |
          if [[ $FAST_COMPILE == "1" ]]; then export THEANO_FLAGS=$THEANO_FLAGS,mode=FAST_COMPILE; fi
          if [[ $FLOAT32 == "1" ]]; then export THEANO_FLAGS=$THEANO_FLAGS,floatX=float32; fi
          export THEANO_FLAGS=$THEANO_FLAGS,warn.ignore_bug_before=all,on_opt_error=raise,on_shape_error=raise,gcc.cxxflags=-pipe
          python -m pytest -x -r A --verbose --runslow --cov=theano/ --cov-report=xml:coverage/coverage-${MATRIX_ID}.xml --no-cov-on-fail $PART
        env:
          MATRIX_ID: ${{ steps.matrix-id.outputs.id }}
          MKL_THREADING_LAYER: GNU
          MKL_NUM_THREADS: 1
          OMP_NUM_THREADS: 1
          PART: ${{ matrix.part }}
          FAST_COMPILE: ${{ matrix.fast-compile }}
          FLOAT32: ${{ matrix.float32 }}

      - name: Upload coverage file
        uses: actions/upload-artifact@v2
        with:
          name: coverage
          path: coverage/coverage-${{ steps.matrix-id.outputs.id }}.xml

  combine:
    if: ${{ always() }}
    runs-on: ubuntu-latest
    name: "All tests and coverage"
    needs: [changes, style, test]
    steps:
      - name: Check build matrix status
        if: ${{ needs.changes.outputs.changes == 'true' && (needs.style.result != 'success' || needs.test.result != 'success') }}
        run: exit 1

      - uses: actions/checkout@v2

      - name: Set up Python
        uses: actions/setup-python@v1
        with:
          python-version: 3.7

      - name: Install dependencies
        run: |
          python -m pip install -U coverage>=5.1 coveralls

      - name: Download coverage file
        uses: actions/download-artifact@v2
        with:
          name: coverage
          path: coverage

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v1
        with:
          directory: ./coverage/
          fail_ci_if_error: true
