################################################################################
#
#  Github actions trigger (workflow script) for building Macaulay2
#
#    See https://help.github.com/en/actions for the documentation.
#
################################################################################

name: Build and Test Macaulay2

on:
  workflow_dispatch:
  push:
    branches:
      - pre-master # when we're ready to merge 'development' into 'master', we merge it first into 'pre-master', so it can be tested
  pull_request:
    branches:
      - master
      - development
  schedule:
    # cron time in UTC
    # a scheduled job runs on the default branch: 'master'
    - cron: '0 6 * * *'

defaults:
  run:
    working-directory: M2/BUILD/build

jobs:
  build:
    if: github.repository == 'Macaulay2/M2' || contains(github.ref, 'global')
    name: ${{ matrix.build-system }}-${{ matrix.os }}-${{ matrix.compiler }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        build-system:
          - cmake
          - autotools
        os:
          - ubuntu-22.04
          - macos-12
        compiler:
          - default
        include:
          - build-system: cmake
            os: ubuntu-22.04
            compiler: clang-15
            cxx: clang++-15
            cc: clang-15
          # This build tests Clang rather than AppleClang (keep)
          - build-system: cmake
            os: macos-12
            compiler: clang-15
            cxx: clang++
            cc: clang
        exclude:
          - build-system: cmake
            os: macos-12
            compiler: default
    steps:
      - uses: actions/checkout@v3

# ----------------------
#   Install missing tools and libraries for macOS
# ----------------------

      - name: Install requirements for macOS
        if: runner.os == 'macOS'
        run: |
          brew config
          brew tap macaulay2/tap
          brew install automake boost tbb ccache ctags llvm make ninja yasm libffi
          brew install --only-dependencies macaulay2/tap/M2

# ----------------------
#   Install missing tools and libraries for Linux
# ----------------------

      - name: Install requirements for Linux
        if: runner.os == 'Linux'
        run: |
          sudo add-apt-repository -y -n ppa:macaulay2/macaulay2
          sudo apt-get update
          sudo apt-get install -y -q --no-install-recommends clang-15 gfortran libtool-bin ninja-build yasm ccache
          sudo apt-get install -y -q --no-install-recommends libboost-stacktrace-dev \
                  libncurses-dev libncurses5-dev libreadline-dev libeigen3-dev liblapack-dev libxml2-dev \
                  libgc-dev libgdbm-dev libglpk-dev libgmp3-dev libgtest-dev libmpfr-dev libmpfi-dev libntl-dev gfan \
                  libgivaro-dev libboost-regex-dev fflas-ffpack libflint-dev libmps-dev libfrobby-dev \
                  libsingular-dev singular-data libcdd-dev cohomcalg topcom 4ti2 normaliz coinor-csdp \
                  nauty lrslib polymake phcpack w3c-markup-validator libtbb-dev qepcad libomp-15-dev

# ----------------------
#   Steps common to all build variants
# ----------------------

      - name: Prepare build environment
        run: |
          echo "CC=${{  matrix.cc  }}" >> $GITHUB_ENV
          echo "CXX=${{ matrix.cxx }}" >> $GITHUB_ENV
          if [[ "${{ runner.os }}" == "Linux" ]]
          then shopt -s expand_aliases
               alias llvm-config="/usr/bin/llvm-config-15"
               echo "/usr/lib/ccache"                     >> $GITHUB_PATH
               echo "/home/linuxbrew/.linuxbrew/bin"      >> $GITHUB_PATH
          else echo `brew --prefix ccache`/libexec        >> $GITHUB_PATH
               echo `brew --prefix make  `/libexec/gnubin >> $GITHUB_PATH
               echo `brew --prefix llvm`/bin              >> $GITHUB_PATH
               PATH=`brew --prefix llvm`/bin:$PATH
               echo `brew --prefix libtool`/libexec/gnubin >> $GITHUB_PATH
          fi
          # Necessary for clang to find the right libomp
          echo "LIBRARY_PATH=`llvm-config --libdir`" >> $GITHUB_ENV

      - uses: actions/cache@v3
        if: matrix.build-system == 'cmake'
        id: restore-cache
        with:
          path: |
            ~/.ccache
            ~/work/M2/M2/M2/BUILD/build/usr-host
          key: build-cache-${{ runner.os }}-${{ matrix.compiler }}-${{ matrix.build-system }}-${{ hashFiles('**/cmake/*-libraries.cmake', '.github/workflows/test_build.yml') }}


# ----------------------
#   Configure and build M2 using CMake
# ----------------------

      - name: Configure Macaulay2 using CMake
        if: matrix.build-system == 'cmake'
        run: |
          cmake -S../.. -B. -GNinja \
            -DCMAKE_BUILD_TYPE=Release -DBUILD_NATIVE=OFF \
            -DCMAKE_PREFIX_PATH="`brew --prefix`;`brew --prefix libffi`" \
            -DCMAKE_INSTALL_PREFIX=/usr \
            -DWITH_PYTHON=ON \
            --debug-trycompile

      - name: Build libraries using Ninja
        if: matrix.build-system == 'cmake'
        run: |
          cmake --build . --target build-libraries build-programs

      - name: Build Macaulay2 using Ninja
        if: matrix.build-system == 'cmake'
        run: |
          cmake --build . --target M2-core M2-emacs install-packages
          if [[ "${{ runner.os }}" == "Linux" ]] && [[ "${{ matrix.compiler }}" == "clang-15" ]]; then
              sudo apt-get install -y -q --no-install-recommends dpkg-dev
              echo "GIT_COMMIT=`git describe --dirty --always --match HEAD`" >> $GITHUB_ENV
              cpack -G DEB
          fi

# ----------------------
#   Configure and build M2 using Autotools
# ----------------------

      - name: Configure Macaulay2 using Autotools
        if: matrix.build-system == 'autotools'
        run: |
          make -C ../.. all
          export PYVERSION=`python3 -c "from sys import version_info; \
            print(f'{version_info.major}.{version_info.minor}')"`
          export CPPFLAGS="-I`brew --prefix`/include -I`brew --prefix libomp`/include"
          export  LDFLAGS="-L`brew --prefix`/lib -L`brew --prefix libomp`/lib \
            -L/Library/Frameworks/Python.framework/Versions/${PYVERSION}/lib"
          ../../configure --enable-download --with-python --with-system-gc

      - name: Build Macaulay2 using Make
        if: matrix.build-system == 'autotools'
        run: |
          make -j$(nproc 2>/dev/null || sysctl -n hw.logicalcpu)

# ----------------------
#   Run tests
# ----------------------

      - name: Run Tests using CTest
        if: matrix.build-system == 'cmake' && runner.os == 'Linux' && matrix.compiler == 'clang-15'
        run: |
          set -xe
          ./M2 -q --check 1 -e 'exit 0'
          ./M2 -q --check 2 -e 'exit 0'
          ./M2 -q --check 3 -e 'exit 0'
          cmake --build . --target M2-tests
          cmake --build . --target M2-unit-tests
          cmake --build . --target memtailor-unit-tests mathic-unit-tests mathicgb-unit-tests
          ctest -j1 --output-on-failure -R "unit-tests"
          ctest -j4 --output-on-failure -R "ComputationsBook"
          # TODO: add Macaulay2/tests/engine when https://github.com/Macaulay2/M2/issues/1213 is fixed

      - name: Run Tests using Autotools
        if: matrix.build-system == 'autotools' && runner.os == 'Linux' && matrix.compiler == 'default'
        run: |
          make check -o check-in-libraries
          make -C Macaulay2/html-check-links check

      - name: Validate HTML documentation
        if: matrix.build-system == 'autotools' && runner.os == 'Linux'
        run: |
          python3 -m pip install html5validator
          if test ${{ github.event_name }} = pull_request
          then
            git fetch --depth=1 origin development
            # validate everything if any changes to Core
            if test "$(git diff --stat origin/development HEAD -- ../../Macaulay2/m2)"
            then
              make validate-html
            else
            # otherwise, just validate HTML docs for packages that have been updated
              PACKAGES=$(git diff --stat origin/development HEAD -- ../../Macaulay2/packages/ | grep -Po "(?<=Macaulay2/packages/)[^/\.]*(?=\.m2|/)" | uniq | xargs)
              make validate-html PACKAGES="$PACKAGES"
            fi
          else
            # if not a pull request (scheduled or pre-master builds), then validate everything
            make validate-html
          fi

# ----------------------
#   Upload build artifacts
# ----------------------

      - name: Upload build logs
        if: always()
        uses: actions/upload-artifact@v3
        with:
           name: ${{ matrix.build-system }}-${{ matrix.os }}-${{ matrix.compiler }}-logs
           path: |
             # Autotools
             M2/BUILD/build/config.log
             M2/BUILD/build/include/*
             M2/BUILD/build/libraries/*/build/*/config.log
             # CMake
             M2/BUILD/build/CMakeCache.txt
             M2/BUILD/build/CMakeFiles/CMakeError.log
             M2/BUILD/build/CMakeFiles/CMakeOutput.log
             M2/BUILD/build/libraries/*/build/config.log
             # package example errors
             M2/BUILD/build/usr-dist/common/share/doc/Macaulay2/*/example-output/*.errors
             # package test errors under Ubuntu
             /tmp/M2-*/*.tmp
             /tmp/M2-*/*.m2
             # Test errors
             M2/BUILD/build/Macaulay2/tests/*/*.errors

      - name: Upload Macaulay2 package for Ubuntu (x86_64)
        if: matrix.build-system == 'cmake' && runner.os == 'Linux' && matrix.compiler == 'clang-15' && success()
        uses: actions/upload-artifact@v3
        with:
          name: Macaulay2-${{ env.GIT_COMMIT }}-ubuntu-x86_64
          path: |
            M2/BUILD/build/Macaulay2-*
          retention-days: 1
