name: Basix CI

# This workflow will install Python dependencies, run tests and lint
# with a single version of Python For more information see:
# https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

on:
  push:
    branches:
      - "**"
    tags:
      - "v*"
  pull_request:
    branches:
      - main
  merge_group:
    branches:
      - main
  workflow_dispatch:
  # Weekly build on Mondays at 8 am
  schedule:
    - cron: "0 8 * * 1"
jobs:
  lint:
    name: Lint code
    runs-on: ubuntu-latest
    steps:
      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: "3.13"
      - uses: actions/checkout@v5
      - name: Ruff check
        run: |
          pip install ruff
          ruff check .
          ruff format --check .
      - name: MyPy check
        run: |
          pip install mypy numpy
          pip install git+https://github.com/FEniCS/ufl.git
          mypy python/basix

  build:
    name: Build and test
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-22.04]
        python-version: ["3.10", "3.11", "3.12", "3.13"]
    steps:
      - uses: actions/checkout@v5
      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: ${{ matrix.python-version }}
      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y doxygen graphviz libopenblas-dev liblapack-dev ninja-build
      - name: Install UFL branch
        run: pip -v install git+https://github.com/FEniCS/ufl.git
      - name: Install Basix
        run: pip -v install .[ci]
      - name: Run units tests
        run: pytest -n auto --durations 20 test/
      - name: Run simple CMake integration test
        run: |
          cd test/test_cmake
          cmake -DCMAKE_BUILD_TYPE=Debug -DPython3_EXECUTABLE=python3 -G Ninja -B build-dir -S .
          cmake --build build-dir/
          build-dir/a.out
      - name: Run Python demos
        run: pytest demo/python/test.py
      - name: Run C++ demos
        run: pytest demo/cpp/test.py
      - name: Build documentation
        run: |
          export BASIX_VERSION=`python3 -c "import basix; print(basix.__version__)"`
          cd doc/cpp
          doxygen
          cd ../python
          python -m sphinx -W -b html source build/html
          rm -rf build/html/.doctrees
      - name: Upload C++ documentation artifact
        uses: actions/upload-artifact@v4
        with:
          name: doc-cpp-${{ matrix.python-version }}
          path: |
            doc/cpp/html
          retention-days: 2
          if-no-files-found: error
      - name: Upload Python documentation artifact
        uses: actions/upload-artifact@v4
        with:
          name: doc-python-${{ matrix.python-version }}
          path: |
            doc/python/build/html
          retention-days: 2
          if-no-files-found: error
      - name: Build website documentation
        run: |
          sudo apt-get install -y ruby-bundler ruby-dev
          export BASIX_VERSION=`python3 -c "import basix; print(basix.__version__)"`
          cd doc/web
          python make_html.py
      - name: Set version name
        if: ${{ github.repository == 'FEniCS/basix' && ( github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') ) && matrix.python-version == '3.11' }}
        run: |
          echo "VERSION_NAME=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
      - name: Build documentation to upload
        if: ${{ github.repository == 'FEniCS/basix' && ( github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') ) && matrix.python-version == '3.11' }}
        run: |
          export BASIX_VERSION=`python3 -c "import basix; print(basix.__version__)"`
          cd doc/web
          python make_html.py --url https://docs.fenicsproject.org/basix/${{ env.VERSION_NAME }}
      - name: Checkout FEniCS/docs
        if: ${{ github.repository == 'FEniCS/basix' && ( github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') ) && matrix.python-version == '3.11' }}
        uses: actions/checkout@v5
        with:
          repository: "FEniCS/docs"
          path: "docs"
          ssh-key: "${{ secrets.SSH_GITHUB_DOCS_PRIVATE_KEY }}"
      - name: Copy documentation into repository
        if: ${{ github.repository == 'FEniCS/basix' && ( github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') ) && matrix.python-version == '3.11' }}
        run: |
          cd docs
          git rm -r --ignore-unmatch basix/${{ env.VERSION_NAME }}
          mkdir -p basix/${{ env.VERSION_NAME }}
          cp -r ../doc/web/html/* basix/${{ env.VERSION_NAME }}
      - name: Commit and push documentation to FEniCS/docs
        if: ${{ github.repository == 'FEniCS/basix' && ( github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') ) && matrix.python-version == '3.11' }}
        run: |
          cd docs
          git config --global user.email "fenics@github.com"
          git config --global user.name "FEniCS GitHub Actions"
          git add --all
          git commit --allow-empty -m "Update Basix docs FEniCS/basix@${{ github.sha }}"
          git push

  isolated-python-build:
    name: Build Python using '--no-build-isolation'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: "3.13"
      - name: Install dependencies
        run: sudo apt-get install -y libopenblas-dev liblapack-dev ninja-build
      - name: Install Python dependencies
        run: pip install nanobind scikit-build-core[pyproject]
      - name: Install Basix
        run: pip install --no-build-isolation .

  build-cmake:
    name: Build using C++ and Python parts separately and run tests
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: "3.13"
      - name: Install dependencies
        run: sudo apt-get install -y libopenblas-dev liblapack-dev
      - name: Install Basix C++ library
        run: |
          cd cpp
          cmake -DCMAKE_BUILD_TYPE=Release -B build-dir -S . # Use make (not ninja)
          cmake --build build-dir
          sudo cmake --install build-dir
      - name: Install Basix Python wrapper
        run: |
          cd python
          pip install .[test]
      - name: Run units tests
        run: |
          pip install pytest-xdist # in ci extras, but most not needed.
          pytest -n auto --durations 20 test/
      - name: Run Python demos
        run: pytest demo/python/test.py
      - name: Run C++ demos
        run: pytest demo/cpp/test.py

  build-cpp-only:
    name: Build C++ only and run demos
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - name: Install dependencies
        run: sudo apt-get install -y libopenblas-dev liblapack-dev ninja-build
      - name: Install Basix
        run: |
          cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -B build-dir -S cpp
          cmake --build build-dir
          sudo cmake --install build-dir
      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: "3.13"
      - name: Run tests
        run: |
          pip install pytest
          pytest demo/cpp/test.py
