diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 4579501b2..248a5ad8f 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -4,8 +4,33 @@ on: push: branches: - '**' + paths-ignore: + - 'python/docs/**' + - 'doc_resources/**' + - 'Doxyfile' + - '**/*.md' + - '**/*.html' + - '.github/workflows/build_docs.yml' pull_request: + paths-ignore: + - 'python/docs/**' + - 'doc_resources/**' + - 'Doxyfile' + - '**/*.md' + - '**/*.html' + - '.github/workflows/build_docs.yml' workflow_call: + inputs: + minimal: + description: 'Build only the ubuntu-latest / python-3.11 wheel; skip C++ tests, Windows, macOS, and wheel tests.' + required: false + type: boolean + default: false + ref: + description: 'Branch, tag, or SHA to check out before building (defaults to the calling workflow''s ref).' + required: false + type: string + default: '' workflow_dispatch: inputs: full_matrix: @@ -13,6 +38,11 @@ on: required: false type: boolean default: false + minimal: + description: 'Build only the ubuntu-latest / python-3.11 wheel; skip C++ tests, Windows, macOS, and wheel tests.' + required: false + type: boolean + default: false concurrency: group: build-${{ github.ref }} @@ -34,9 +64,12 @@ jobs: # Mac available to the maintainer). Intel macOS support is paused # pending a reproducer or an upstream fix. Re-add "macos-15-intel" # below when ready to revisit. - if [[ "${{ github.ref }}" == "refs/heads/main" || "${{ github.ref }}" == "refs/heads/develop" || "${{ github.ref }}" == refs/tags/* || "${{ inputs.full_matrix }}" == "true" || "${{ github.event.pull_request.base.ref }}" == "develop" || "${{ github.event.pull_request.base.ref }}" == "main" ]]; then + if [[ "${{ inputs.minimal }}" == "true" ]]; then + echo 'os=["ubuntu-latest"]' >> $GITHUB_OUTPUT + echo 'python_versions=["3.11"]' >> $GITHUB_OUTPUT + elif [[ "${{ github.ref }}" == "refs/heads/main" || "${{ github.ref }}" == "refs/heads/develop" || "${{ github.ref }}" == refs/tags/* || "${{ inputs.full_matrix }}" == "true" || "${{ github.event.pull_request.base.ref }}" == "develop" || "${{ github.event.pull_request.base.ref }}" == "main" ]]; then echo 'os=["ubuntu-latest","macos-14"]' >> $GITHUB_OUTPUT - echo 'python_versions=["3.9","3.10","3.11","3.12","3.13"]' >> $GITHUB_OUTPUT + echo 'python_versions=["3.9","3.10","3.11","3.12","3.13","3.14"]' >> $GITHUB_OUTPUT else echo 'os=["ubuntu-latest","macos-14"]' >> $GITHUB_OUTPUT echo 'python_versions=["3.11"]' >> $GITHUB_OUTPUT @@ -44,6 +77,7 @@ jobs: test_cpp_unix: name: C++ tests on ${{ matrix.os }} + if: ${{ inputs.minimal != true }} needs: [set_matrix] runs-on: ${{ matrix.os }} strategy: @@ -107,6 +141,7 @@ jobs: test_cpp_windows: name: C++ tests on Windows + if: ${{ inputs.minimal != true }} runs-on: windows-latest env: CONDA_PKGS_DIRS: ${{ github.workspace }}\conda_pkgs @@ -157,7 +192,7 @@ jobs: run: ctest --output-on-failure --parallel build_macos_ubuntu_wheels: - name: ${{ matrix.os }} Python-${{ matrix.python-version }} wheels + name: ${{ matrix.os }} Python-${{ matrix.python-version }} wheels needs: [set_matrix] runs-on: ${{ matrix.os }} strategy: @@ -168,6 +203,8 @@ jobs: steps: - uses: actions/checkout@v5 + with: + ref: ${{ inputs.ref || github.ref }} - name: Cache cibuildwheel + pip + Homebrew uses: actions/cache@v5 with: @@ -176,7 +213,8 @@ jobs: ~/.cache/cibuildwheel ~/Library/Caches/Homebrew /tmp/boost_1_90_0.tar.bz2 - /tmp/eigenpy-3.11.0.tar.gz + /tmp/eigen-3.4.0.tar.gz + /tmp/eigenpy-3.12.0.tar.gz key: ${{ runner.os }}-cibw-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml', 'python/pyproject.toml', 'CMakeLists.txt', 'core/CMakeLists.txt', '.github/workflows/build_and_test.yml') }} restore-keys: | ${{ runner.os }}-cibw-${{ matrix.python-version }}- @@ -193,7 +231,7 @@ jobs: run: | SW_VERS=$(sw_vers -productVersion | cut -d. -f1) echo "MACOSX_DEPLOYMENT_TARGET=${SW_VERS}.0" >> $GITHUB_ENV - - uses: pypa/cibuildwheel@v2.23 + - uses: pypa/cibuildwheel@v3.4.1 env: # Build cp39 through cp313 for both Linux (manylinux) and macOS. # Boost.Python and eigenpy are rebuilt per target Python in BEFORE_BUILD @@ -207,9 +245,13 @@ jobs: # against the manylinux2014 system python3 produces a libboost_python39 that # all five wheels would then bundle, breaking import on cp310/311/312/313. CIBW_BEFORE_ALL_LINUX: > - yum install -y wget gmp-devel mpfr-devel libmpc-devel eigen3-devel libtool && + yum install -y wget gmp-devel mpfr-devel libmpc-devel libtool && cd /tmp && - { [ -f eigenpy-3.11.0.tar.gz ] || wget -q https://github.com/stack-of-tasks/eigenpy/releases/download/v3.11.0/eigenpy-3.11.0.tar.gz ; } + { [ -f eigen-3.4.0.tar.gz ] || wget -q https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz ; } && + rm -rf eigen-3.4.0 && tar xzf eigen-3.4.0.tar.gz && + cmake -S eigen-3.4.0 -B eigen-3.4.0/bld -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Release && + cmake --install eigen-3.4.0/bld && + { [ -f eigenpy-3.12.0.tar.gz ] || wget -q https://github.com/stack-of-tasks/eigenpy/releases/download/v3.12.0/eigenpy-3.12.0.tar.gz ; } # On macOS, Homebrew's boost-python3 / eigenpy bottles track the current # Homebrew default Python (now 3.14), so a cp313 wheel that bundles them # imports a libboost_python314.dylib into a 3.13 interpreter and segfaults. @@ -218,8 +260,8 @@ jobs: CIBW_BEFORE_ALL_MACOS: > brew install gmp mpfr libmpc eigen@3 && cd /tmp && - { [ -f eigenpy-3.11.0.tar.gz ] || curl -fsSL -o eigenpy-3.11.0.tar.gz https://github.com/stack-of-tasks/eigenpy/releases/download/v3.11.0/eigenpy-3.11.0.tar.gz ; } - + { [ -f eigenpy-3.12.0.tar.gz ] || curl -fsSL -o eigenpy-3.12.0.tar.gz https://github.com/stack-of-tasks/eigenpy/releases/download/v3.12.0/eigenpy-3.12.0.tar.gz ; } + # Build Boost and eigenpy fresh against the active per-Python interpreter # so each wheel bundles a matching libboost_python3X. CIBW_BEFORE_BUILD_LINUX: > @@ -236,8 +278,8 @@ jobs: printf 'using python : %s : %s : %s : %s ;\n' "$PY_VER" "$(which python)" "$PY_INC" "$PY_LIB" > user-config.jam && ./b2 install -j$(nproc) --user-config=user-config.jam python=$PY_VER && cd /tmp && - rm -rf eigenpy-3.11.0 && tar zxf eigenpy-3.11.0.tar.gz && - cd eigenpy-3.11.0 && mkdir -p bld && cd bld && + rm -rf eigenpy-3.12.0 && tar zxf eigenpy-3.12.0.tar.gz && + cd eigenpy-3.12.0 && mkdir -p bld && cd bld && cmake .. -DCMAKE_PREFIX_PATH=/tmp/deps-py -DCMAKE_INSTALL_PREFIX=/tmp/deps-py -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DPython3_EXECUTABLE=$(which python) -DPython3_NumPy_INCLUDE_DIR=$(python -c "import numpy; print(numpy.get_include())") -DBUILD_TESTING=OFF -DCMAKE_INSTALL_DO_STRIP=ON && make -j2 install && find /tmp/deps-py -name '*.so*' -type f | while read f; do @@ -260,8 +302,8 @@ jobs: printf 'using python : %s : %s : %s : %s ;\n' "$PY_VER" "$(which python)" "$PY_INC" "$PY_LIB" > user-config.jam && ./b2 install -j$(sysctl -n hw.ncpu) --user-config=user-config.jam python=$PY_VER hardcode-dll-paths=true dll-path=/tmp/deps-py/lib && cd /tmp && - rm -rf eigenpy-3.11.0 && tar zxf eigenpy-3.11.0.tar.gz && - cd eigenpy-3.11.0 && mkdir -p bld && cd bld && + rm -rf eigenpy-3.12.0 && tar zxf eigenpy-3.12.0.tar.gz && + cd eigenpy-3.12.0 && mkdir -p bld && cd bld && cmake .. -DCMAKE_PREFIX_PATH="/tmp/deps-py;/opt/homebrew" -DCMAKE_INSTALL_PREFIX=/tmp/deps-py -DPython3_EXECUTABLE=$(which python) -DPython3_NumPy_INCLUDE_DIR=$(python -c "import numpy; print(numpy.get_include())") -DBUILD_TESTING=OFF && make -j2 install CIBW_BEFORE_BUILD: "pip install scikit-build-core numpy" @@ -275,14 +317,15 @@ jobs: if-no-files-found: error build_windows_wheels: - name: Windows Python-${{ matrix.python-version }} wheels + name: Windows Python-${{ matrix.python-version }} wheels + if: ${{ inputs.minimal != true }} runs-on: windows-latest env: CONDA_PKGS_DIRS: ${{ github.workspace }}\conda_pkgs strategy: fail-fast: false matrix: - python-version: ['3.9', '3.10', '3.11'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] steps: - uses: actions/checkout@v5 with: @@ -338,6 +381,7 @@ jobs: test_wheels_linux_macos: name: Test wheels on ${{ matrix.os }} / py${{ matrix.python-version }} + if: ${{ inputs.minimal != true }} needs: [set_matrix, build_macos_ubuntu_wheels] runs-on: ${{ matrix.os }} strategy: @@ -371,12 +415,13 @@ jobs: test_wheels_windows: name: Test wheel on windows-${{ matrix.python-version }} + if: ${{ inputs.minimal != true }} needs: [build_windows_wheels] runs-on: windows-latest strategy: fail-fast: false matrix: - python-version: ['3.9', '3.10', '3.11'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] steps: - uses: actions/checkout@v5 @@ -403,4 +448,4 @@ jobs: $py = "C:\Miniconda\envs\b2-windows\python.exe" & $py -m pip install --no-index --find-links dist/ bertini2 & $py -m pip install pytest - & $py -m pytest python/test/ -v \ No newline at end of file + & $py -m pytest python/test/ -v diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml new file mode 100644 index 000000000..059c0746e --- /dev/null +++ b/.github/workflows/build_docs.yml @@ -0,0 +1,159 @@ +name: Build and deploy documentation 📝 + +on: + workflow_call: + # When called from publish.yml, the caller's build_and_test job has + # already produced the wheel artifact this workflow needs. The internal + # build_and_test job below is skipped in that case. + inputs: + deploy: + description: 'Deploy to GitHub Pages after building' + required: false + type: boolean + default: true + workflow_dispatch: + inputs: + deploy: + description: 'Deploy to GitHub Pages after building' + required: false + type: boolean + default: true + ref: + description: 'Branch, tag, or SHA to build docs for (defaults to the dispatched ref).' + required: false + type: string + default: '' + +concurrency: + group: docs-${{ github.ref }} + cancel-in-progress: true + +jobs: + build_and_test: + name: Build wheel (for docs) + # Only run when triggered manually. workflow_call invocations assume the + # caller already ran build_and_test in the same workflow run, so the + # wheel artifact is already available. + if: github.event_name == 'workflow_dispatch' + uses: ./.github/workflows/build_and_test.yml + with: + # Docs only need the ubuntu-latest / python-3.11 wheel; skip the full + # OS/Python matrix and the wheel/C++ test jobs. + minimal: true + ref: ${{ inputs.ref }} + + build_docs: + name: Build docs + needs: [build_and_test] + # `build_and_test` is skipped when invoked via workflow_call; treat that + # as success so build_docs runs in both modes. + if: | + always() && + (needs.build_and_test.result == 'success' || needs.build_and_test.result == 'skipped') + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + ref: ${{ inputs.ref || github.ref }} + # gitpython (used by python/docs/source/conf.py to derive version) + # needs the full history; the default depth=1 leaves it unable to + # resolve HEAD's commit object on some refs. + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Compute build metadata + id: meta + run: | + SHA=$(git rev-parse HEAD) + SHORT=$(git rev-parse --short HEAD) + DATE=$(date -u +'%Y-%m-%d %H:%M UTC') + echo "sha=$SHA" >> "$GITHUB_OUTPUT" + echo "short=$SHORT" >> "$GITHUB_OUTPUT" + echo "date=$DATE" >> "$GITHUB_OUTPUT" + echo "Build metadata: $SHORT ($SHA) at $DATE" + + - name: Install system dependencies (Doxygen) + run: | + sudo apt-get update + sudo apt-get install -y doxygen graphviz + + - name: Fetch doxygen-awesome-css + run: | + curl -sSL https://github.com/jothepro/doxygen-awesome-css/archive/refs/tags/v2.3.4.tar.gz | tar -xz + mv doxygen-awesome-css-2.3.4 doxygen-awesome-css + + - name: Build C++ docs (Doxygen) + env: + PROJECT_NUMBER: "${{ steps.meta.outputs.short }} (${{ steps.meta.outputs.date }})" + run: | + mkdir -p build/docs/cpp site + # Append PROJECT_NUMBER override via stdin; Doxygen reads stdin + # config when invoked with `-` and merges with the file. + (cat Doxyfile; echo "PROJECT_NUMBER = $PROJECT_NUMBER") | doxygen - + mv build/docs/cpp site/cpp + + - name: Install Python deps for Sphinx + # The bertini2 wheel bundles the eigenpy C++ libraries it links + # against; no Python `eigenpy` install is required to import bertini + # for sphinx autodoc. + run: | + python -m pip install --upgrade pip + pip install \ + sphinx sphinx-rtd-theme sphinxcontrib-bibtex gitpython \ + scikit-build-core build numpy + + - name: Download built wheel + uses: actions/download-artifact@v5 + with: + name: wheels-ubuntu-latest-3.11 + path: dist/ + + - name: Install bertini from built wheel + run: pip install --no-index --find-links dist/ bertini2 + + - name: Build Python docs (Sphinx) + working-directory: python/docs + env: + BERTINI_GIT_SHA: ${{ steps.meta.outputs.sha }} + BERTINI_BUILD_DATE: ${{ steps.meta.outputs.date }} + run: | + sphinx-build -b html -W --keep-going source ../../site/python + + - name: Add landing page + env: + COMMIT_SHA: ${{ steps.meta.outputs.sha }} + COMMIT_SHORT: ${{ steps.meta.outputs.short }} + BUILD_DATE: ${{ steps.meta.outputs.date }} + run: | + sed \ + -e "s|__COMMIT_SHA__|${COMMIT_SHA}|g" \ + -e "s|__COMMIT_SHORT__|${COMMIT_SHORT}|g" \ + -e "s|__BUILD_DATE__|${BUILD_DATE}|g" \ + doc_resources/landing/index.html > site/index.html + cp doc_resources/landing/style.css site/style.css + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: site + + deploy_docs: + name: Deploy to GitHub Pages + needs: + - build_docs + if: needs.build_docs.result == 'success' && inputs.deploy + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/github-gitlab-sync.yml b/.github/workflows/github-gitlab-sync.yml index 1a7c3cfe1..9af179e61 100644 --- a/.github/workflows/github-gitlab-sync.yml +++ b/.github/workflows/github-gitlab-sync.yml @@ -3,7 +3,7 @@ on: push jobs: sync: - if: github.repository == 'bertiniteam/b2' + if: github.repository == 'bertiniteam/b2' #only on official runs-on: ubuntu-latest steps: - name: Sync to GitLab @@ -19,4 +19,4 @@ jobs: gitlab_pat: ${{ secrets.GITLAB_PAT }} # Whether to force push to GitLab. Defaults to false. - #force_push: # optional, default is false + force_push: true # optional, default is false diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e5fdde3a2..e4c602956 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -143,109 +143,12 @@ jobs: files: | dist/*.* - build_docs: - name: Build docs + build_and_deploy_docs: + name: Build and deploy docs if: needs.check_version.outputs.is_prerelease == 'false' needs: [check_version, build_and_test] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - with: - # gitpython (used by python/docs/source/conf.py to derive version) - # needs the full history; the default depth=1 leaves it unable to - # resolve HEAD's commit object on some refs. - fetch-depth: 0 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: Compute build metadata - id: meta - run: | - SHA=$(git rev-parse HEAD) - SHORT=$(git rev-parse --short HEAD) - DATE=$(date -u +'%Y-%m-%d %H:%M UTC') - echo "sha=$SHA" >> "$GITHUB_OUTPUT" - echo "short=$SHORT" >> "$GITHUB_OUTPUT" - echo "date=$DATE" >> "$GITHUB_OUTPUT" - echo "Build metadata: $SHORT ($SHA) at $DATE" - - - name: Install system dependencies (Doxygen) - run: | - sudo apt-get update - sudo apt-get install -y doxygen graphviz - - - name: Fetch doxygen-awesome-css - run: | - curl -sSL https://github.com/jothepro/doxygen-awesome-css/archive/refs/tags/v2.3.4.tar.gz | tar -xz - mv doxygen-awesome-css-2.3.4 doxygen-awesome-css - - - name: Build C++ docs (Doxygen) - env: - PROJECT_NUMBER: "${{ steps.meta.outputs.short }} (${{ steps.meta.outputs.date }})" - run: | - mkdir -p build/docs/cpp site - # Append PROJECT_NUMBER override via stdin; Doxygen reads stdin - # config when invoked with `-` and merges with the file. - (cat Doxyfile; echo "PROJECT_NUMBER = $PROJECT_NUMBER") | doxygen - - mv build/docs/cpp site/cpp - - - name: Install Python deps for Sphinx - run: | - python -m pip install --upgrade pip - pip install \ - sphinx sphinx-rtd-theme sphinxcontrib-bibtex gitpython \ - scikit-build-core build numpy eigenpy==3.11.0 - - - name: Download built wheel - uses: actions/download-artifact@v5 - with: - name: wheels-ubuntu-latest-3.11 - path: dist/ - - - name: Install bertini from built wheel - run: pip install --no-index --find-links dist/ bertini2 - - - name: Build Python docs (Sphinx) - working-directory: python/docs - env: - BERTINI_GIT_SHA: ${{ steps.meta.outputs.sha }} - BERTINI_BUILD_DATE: ${{ steps.meta.outputs.date }} - run: | - sphinx-build -b html -W --keep-going source ../../site/python - - - name: Add landing page - env: - COMMIT_SHA: ${{ steps.meta.outputs.sha }} - COMMIT_SHORT: ${{ steps.meta.outputs.short }} - BUILD_DATE: ${{ steps.meta.outputs.date }} - run: | - sed \ - -e "s|__COMMIT_SHA__|${COMMIT_SHA}|g" \ - -e "s|__COMMIT_SHORT__|${COMMIT_SHORT}|g" \ - -e "s|__BUILD_DATE__|${BUILD_DATE}|g" \ - doc_resources/landing/index.html > site/index.html - cp doc_resources/landing/style.css site/style.css - - - name: Upload Pages artifact - uses: actions/upload-pages-artifact@v3 - with: - path: site - - deploy_docs: - name: Deploy to GitHub Pages - needs: - - build_docs - runs-on: ubuntu-latest + uses: ./.github/workflows/build_docs.yml permissions: + contents: read pages: write - id-token: write - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - steps: - - name: Deploy - id: deployment - uses: actions/deploy-pages@v4 \ No newline at end of file + id-token: write \ No newline at end of file diff --git a/README.md b/README.md index ca8d579b9..417df8f8c 100644 --- a/README.md +++ b/README.md @@ -57,10 +57,10 @@ pip install bertini2 Once it's installed, you `import bertini` -* Linux: Python 3.9-3.13 -* MacOS (Apple Silicon): Python 3.9-3.13 +* Linux: Python 3.9-3.14 +* MacOS (Apple Silicon): Python 3.9-3.14 * MacOS (Intel): not supported -* Windows: Python 3.9-3.11 +* Windows: Python 3.9-3.14 ## Building from source diff --git a/doc_resources/landing/index.html b/doc_resources/landing/index.html index 44e6f5b4d..d6d41793c 100644 --- a/doc_resources/landing/index.html +++ b/doc_resources/landing/index.html @@ -32,7 +32,7 @@

C++