CI: Coverage #128
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
| # | |
| # SPDX-License-Identifier: Apache-2.0 | |
| name: "CI: Coverage" | |
| on: | |
| schedule: | |
| - cron: '0 0 * * *' # This runs the workflow every day at 12:00 AM UTC | |
| workflow_dispatch: {} | |
| env: | |
| PY_VER: "3.14" | |
| LOCAL_CTK: "1" | |
| GPU: "a100" | |
| DRIVER: "latest" | |
| jobs: | |
| coverage-vars: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| CUDA_VER: ${{ steps.get-vars.outputs.cuda_ver }} | |
| steps: | |
| - name: Checkout ${{ github.event.repository.name }} | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Get CUDA version | |
| id: get-vars | |
| run: | | |
| cuda_ver=$(yq '.cuda.build.version' ci/versions.yml) | |
| echo "cuda_ver=$cuda_ver" >> $GITHUB_OUTPUT | |
| coverage-linux: | |
| name: Coverage (Linux) | |
| needs: [coverage-vars] | |
| runs-on: "linux-amd64-gpu-a100-latest-1" | |
| permissions: | |
| id-token: write | |
| contents: write | |
| defaults: | |
| run: | |
| shell: bash --noprofile --norc -xeuo pipefail {0} | |
| env: | |
| HOST_PLATFORM: "linux-64" | |
| ARCH: "x86_64" | |
| CUDA_VER: ${{ needs.coverage-vars.outputs.CUDA_VER }} | |
| # Our self-hosted runners require a container | |
| # TODO: use a different (nvidia?) container | |
| container: | |
| options: -u root --security-opt seccomp=unconfined --shm-size 16g | |
| image: ubuntu:22.04 | |
| env: | |
| NVIDIA_VISIBLE_DEVICES: ${{ env.NVIDIA_VISIBLE_DEVICES }} | |
| steps: | |
| - name: Ensure GPU is working | |
| run: nvidia-smi | |
| # We have to install git before checking out the repo (so that we can | |
| # deploy the docs at the end). This means we can't use install_unix_deps | |
| # action so install the git package. | |
| - name: Install git | |
| run: | | |
| apt-get update | |
| apt-get install -y git | |
| - name: Checkout ${{ github.event.repository.name }} | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install dependencies | |
| uses: ./.github/actions/install_unix_deps | |
| continue-on-error: false | |
| with: | |
| dependencies: "tree rsync libsqlite3-0 g++ jq wget libgl1 libegl1" | |
| dependent_exes: "tree rsync libsqlite3-0 g++ jq wget libgl1 libegl1" | |
| - name: Setup proxy cache | |
| uses: nv-gha-runners/setup-proxy-cache@main | |
| continue-on-error: true | |
| - name: Set environment variables | |
| env: | |
| BUILD_CUDA_VER: ${{ env.CUDA_VER }} | |
| CUDA_VER: ${{ env.CUDA_VER }} | |
| HOST_PLATFORM: ${{ env.HOST_PLATFORM }} | |
| LOCAL_CTK: ${{ env.LOCAL_CTK }} | |
| PY_VER: ${{ env.PY_VER }} | |
| SHA: ${{ github.sha }} | |
| run: | | |
| ./ci/tools/env-vars test | |
| echo "CUDA_PYTHON_COVERAGE=1" >> $GITHUB_ENV | |
| - name: Set up Python | |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 | |
| with: | |
| python-version: ${{ env.PY_VER }} | |
| env: | |
| # we use self-hosted runners on which setup-python behaves weirdly... | |
| AGENT_TOOLSDIRECTORY: "/opt/hostedtoolcache" | |
| - name: Set up mini CTK | |
| if: ${{ env.LOCAL_CTK == '1' }} | |
| uses: ./.github/actions/fetch_ctk | |
| continue-on-error: false | |
| with: | |
| host-platform: ${{ env.HOST_PLATFORM }} | |
| cuda-version: ${{ env.CUDA_VER }} | |
| - name: Create venv | |
| run: | | |
| python -m venv .venv | |
| - name: Build cuda-pathfinder | |
| run: | | |
| cd cuda_pathfinder | |
| ../.venv/bin/pip install -v . --group test | |
| - name: Build cuda-bindings | |
| run: | | |
| cd cuda_bindings | |
| ../.venv/bin/pip install -v . --group test | |
| - name: Build cuda-core | |
| run: | | |
| cd cuda_core | |
| ../.venv/bin/pip install -v . --group test | |
| - name: Install coverage tools | |
| run: | | |
| .venv/bin/pip install coverage pytest-cov Cython | |
| - name: Set cuda package install root | |
| run: | | |
| echo "INSTALL_ROOT=$(.venv/bin/python -c 'import cuda; import os; print(os.path.dirname(cuda.__path__[0]))')" >> $GITHUB_ENV | |
| echo "REPO_ROOT=$(pwd)" >> $GITHUB_ENV | |
| - name: Run cuda.pathfinder tests | |
| continue-on-error: true | |
| run: | | |
| cd $INSTALL_ROOT | |
| $REPO_ROOT/.venv/bin/pytest -v --cov=./cuda --cov-append --cov-context=test --cov-config=$REPO_ROOT/.coveragerc $REPO_ROOT/cuda_pathfinder/tests | |
| - name: Run cuda.bindings tests | |
| continue-on-error: true | |
| run: | | |
| cd $INSTALL_ROOT | |
| $REPO_ROOT/.venv/bin/pytest -v --cov=./cuda --cov-append --cov-context=test --cov-config=$REPO_ROOT/.coveragerc $REPO_ROOT/cuda_bindings/tests | |
| - name: Run cuda.core tests | |
| continue-on-error: true | |
| run: | | |
| cd $INSTALL_ROOT | |
| $REPO_ROOT/.venv/bin/pytest -v --cov=./cuda --cov-append --cov-context=test --cov-config=$REPO_ROOT/.coveragerc $REPO_ROOT/cuda_core/tests | |
| - name: Copy Linux coverage file to workspace | |
| run: | | |
| cp $INSTALL_ROOT/.coverage $REPO_ROOT/.coverage.linux | |
| echo "Copied .coverage.linux to $REPO_ROOT" | |
| ls -lh $REPO_ROOT/.coverage.linux | |
| - name: Upload Linux coverage data | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: coverage-data-linux | |
| path: .coverage.linux | |
| retention-days: 7 | |
| include-hidden-files: true | |
| if-no-files-found: error | |
| - name: Upload cuda source code for coverage mapping | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: cuda-source-linux | |
| path: ${{ env.INSTALL_ROOT }}/cuda/ | |
| retention-days: 7 | |
| if-no-files-found: error | |
| # Build Windows wheels on GitHub-hosted runner (has VS, no GPU) | |
| build-wheel-windows: | |
| name: Build Wheels (Windows) | |
| needs: [coverage-vars] | |
| runs-on: windows-2022 | |
| permissions: | |
| contents: read | |
| defaults: | |
| run: | |
| shell: bash --noprofile --norc -xeuo pipefail {0} | |
| env: | |
| HOST_PLATFORM: "win-64" | |
| CUDA_PYTHON_COVERAGE: "1" | |
| CUDA_VER: ${{ needs.coverage-vars.outputs.CUDA_VER }} | |
| steps: | |
| - name: Checkout ${{ github.event.repository.name }} | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Python | |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 | |
| with: | |
| python-version: ${{ env.PY_VER }} | |
| - name: Set up MSVC | |
| uses: ilammy/msvc-dev-cmd@v1 | |
| - name: Set up mini CTK | |
| uses: ./.github/actions/fetch_ctk | |
| continue-on-error: false | |
| with: | |
| host-platform: win-64 | |
| cuda-version: ${{ env.CUDA_VER }} | |
| - name: Create venv | |
| run: | | |
| python -m venv .venv | |
| - name: Build and install cuda.pathfinder | |
| run: | | |
| .venv/Scripts/pip install wheel setuptools Cython | |
| .venv/Scripts/pip wheel -v --no-deps ./cuda_pathfinder -w ./wheels/ | |
| - name: Build cuda.bindings wheel | |
| run: | | |
| cd cuda_bindings | |
| ../.venv/Scripts/pip wheel -v --no-deps . -w ../wheels/ | |
| - name: Build cuda.core wheel | |
| run: | | |
| export PIP_FIND_LINKS="$(pwd)/wheels" | |
| export PIP_PRE=1 | |
| cd cuda_core | |
| ../.venv/Scripts/pip wheel -v --no-deps . -w ../wheels/ | |
| - name: List wheel artifacts | |
| run: | | |
| echo "=== Windows wheel artifacts ===" | |
| ls -lahR ./wheels/ | |
| - name: Upload Windows wheel artifacts | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: coverage-windows-wheels | |
| path: ./wheels/*.whl | |
| retention-days: 1 | |
| if-no-files-found: error | |
| # Run coverage tests on self-hosted GPU runner (no VS needed, installs pre-built wheels) | |
| coverage-windows: | |
| name: Coverage (Windows) | |
| needs: [coverage-vars, build-wheel-windows] | |
| runs-on: "windows-amd64-gpu-a100-latest-1" | |
| permissions: | |
| id-token: write | |
| contents: write | |
| env: | |
| HOST_PLATFORM: "win-64" | |
| ARCH: "amd64" | |
| CUDA_PYTHON_COVERAGE: "1" | |
| CUDA_VER: ${{ needs.coverage-vars.outputs.CUDA_VER }} | |
| defaults: | |
| run: | |
| shell: bash --noprofile --norc -xeuo pipefail {0} | |
| steps: | |
| - name: Checkout ${{ github.event.repository.name }} | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup proxy cache | |
| uses: nv-gha-runners/setup-proxy-cache@main | |
| continue-on-error: true | |
| - name: Update driver | |
| shell: powershell | |
| env: | |
| DRIVER_MODE: "TCC" | |
| GPU_TYPE: "a100" | |
| run: | | |
| ci/tools/install_gpu_driver.ps1 | |
| - name: Ensure GPU is working | |
| run: | | |
| nvidia-smi | |
| - name: Set up Python | |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 | |
| with: | |
| python-version: ${{ env.PY_VER }} | |
| - name: Set up mini CTK | |
| uses: ./.github/actions/fetch_ctk | |
| continue-on-error: false | |
| with: | |
| host-platform: win-64 | |
| cuda-version: ${{ env.CUDA_VER }} | |
| - name: Download Windows wheel artifacts | |
| uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 | |
| with: | |
| name: coverage-windows-wheels | |
| path: ./wheels/ | |
| - name: List downloaded wheel artifacts | |
| run: | | |
| echo "=== Downloaded wheel artifacts ===" | |
| ls -lahR ./wheels/ | |
| - name: Create venv | |
| run: | | |
| python -m venv .venv | |
| - name: Install wheels from build job | |
| run: | | |
| .venv/Scripts/pip install ./wheels/cuda_pathfinder*.whl | |
| echo "Installed cuda.pathfinder" | |
| .venv/Scripts/pip install ./wheels/cuda_bindings*.whl | |
| echo "Installed cuda.bindings" | |
| .venv/Scripts/pip install ./wheels/cuda_core*.whl | |
| echo "Installed cuda.core" | |
| - name: Install test dependencies and coverage tools | |
| run: | | |
| .venv/Scripts/pip install -v ./cuda_python_test_helpers | |
| .venv/Scripts/pip install coverage pytest-cov Cython | |
| .venv/Scripts/pip install --group ./cuda_pathfinder/pyproject.toml:test | |
| .venv/Scripts/pip install --group ./cuda_bindings/pyproject.toml:test | |
| .venv/Scripts/pip install --group ./cuda_core/pyproject.toml:test | |
| - name: Get install root | |
| id: install-root | |
| run: | | |
| INSTALL_ROOT=$(.venv/Scripts/python -c 'import cuda; import os; print(os.path.dirname(cuda.__path__[0]))') | |
| echo "INSTALL_ROOT=$INSTALL_ROOT" >> $GITHUB_OUTPUT | |
| echo "Install root: $INSTALL_ROOT" | |
| - name: Run cuda.pathfinder tests | |
| continue-on-error: true | |
| run: | | |
| cd "${{ steps.install-root.outputs.INSTALL_ROOT }}" | |
| "$GITHUB_WORKSPACE/.venv/Scripts/pytest" -v --cov=./cuda --cov-append --cov-context=test --cov-config="$GITHUB_WORKSPACE/.coveragerc" "$GITHUB_WORKSPACE/cuda_pathfinder/tests" | |
| - name: Run cuda.bindings tests (with 8MB stack) | |
| continue-on-error: true | |
| run: | | |
| cd "${{ steps.install-root.outputs.INSTALL_ROOT }}" | |
| # Run pytest in 8MB stack thread (Cython linetrace requirement) | |
| "$GITHUB_WORKSPACE/.venv/Scripts/python" << PYTEST_EOF | |
| import os | |
| import sys | |
| import threading | |
| import pytest | |
| os.chdir(r'${{ steps.install-root.outputs.INSTALL_ROOT }}') | |
| threading.stack_size(8 * 1024 * 1024) | |
| result = {'code': 1} | |
| def _run(): | |
| workspace = os.environ['GITHUB_WORKSPACE'] | |
| result['code'] = pytest.main([ | |
| '-v', | |
| '--cov=./cuda', | |
| '--cov-append', | |
| '--cov-context=test', | |
| f'--cov-config={workspace}/.coveragerc', | |
| f'{workspace}/cuda_bindings/tests' | |
| ]) | |
| t = threading.Thread(target=_run) | |
| t.start() | |
| t.join() | |
| print(f'Bindings tests exit code: {result["code"]}') | |
| # Exit with actual code (continue-on-error handles it) | |
| sys.exit(result['code']) | |
| PYTEST_EOF | |
| - name: Run cuda.core tests | |
| continue-on-error: true | |
| run: | | |
| cd "${{ steps.install-root.outputs.INSTALL_ROOT }}" | |
| "$GITHUB_WORKSPACE/.venv/Scripts/pytest" -v --cov=./cuda --cov-append --cov-context=test --cov-config="$GITHUB_WORKSPACE/.coveragerc" "$GITHUB_WORKSPACE/cuda_core/tests" | |
| - name: Copy Windows coverage file to workspace | |
| run: | | |
| cp "${{ steps.install-root.outputs.INSTALL_ROOT }}/.coverage" "$GITHUB_WORKSPACE/.coverage.windows" | |
| echo "Copied .coverage.windows to $GITHUB_WORKSPACE" | |
| ls -lh "$GITHUB_WORKSPACE/.coverage.windows" | |
| - name: Upload Windows coverage data | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: coverage-data-windows | |
| path: .coverage.windows | |
| retention-days: 7 | |
| include-hidden-files: true | |
| if-no-files-found: error | |
| combine-and-deploy: | |
| name: Combine Coverage and Deploy | |
| needs: [coverage-linux, coverage-windows] | |
| runs-on: ubuntu-latest | |
| if: always() | |
| permissions: | |
| id-token: write | |
| contents: write | |
| steps: | |
| - name: Checkout ${{ github.event.repository.name }} | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Set up Python | |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 | |
| with: | |
| python-version: ${{ env.PY_VER }} | |
| - name: Install coverage | |
| run: | | |
| # .coveragerc enables Cython.Coverage plugin; ensure it's available here too. | |
| pip install coverage[toml] Cython | |
| - name: Download Linux coverage data | |
| uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 | |
| with: | |
| name: coverage-data-linux | |
| path: ./ | |
| - name: Download cuda source code | |
| uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 | |
| with: | |
| name: cuda-source-linux | |
| path: ./cuda/ | |
| - name: Download Windows coverage data | |
| uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 | |
| with: | |
| name: coverage-data-windows | |
| path: ./ | |
| - name: Combine coverage data | |
| run: | | |
| echo "=== Working directory ===" | |
| pwd | |
| echo "" | |
| echo "=== All files in root ===" | |
| ls -la | |
| echo "" | |
| # Verify both Linux and Windows coverage files exist | |
| echo "=== Checking coverage files ===" | |
| if [ ! -f ".coverage.linux" ]; then | |
| echo "[ERROR] .coverage.linux not found!" | |
| exit 1 | |
| fi | |
| echo "[OK] Found .coverage.linux" | |
| if [ ! -f ".coverage.windows" ]; then | |
| echo "[ERROR] .coverage.windows not found!" | |
| exit 1 | |
| fi | |
| echo "[OK] Found .coverage.windows" | |
| echo "=== Available coverage files ===" | |
| ls -lh .coverage.* | |
| echo "=== Cuda source structure ===" | |
| find ./cuda -type d || { | |
| echo "[ERROR] No cuda source directory!" | |
| exit 1 | |
| } | |
| # Combine all .coverage.* files | |
| echo "" | |
| echo "=== Combining coverage data ===" | |
| coverage combine --rcfile=./.coveragerc --keep .coverage.* | |
| # Generate reports | |
| echo "" | |
| echo "=== Generating HTML, XML, and text reports ===" | |
| coverage html --rcfile=./.coveragerc | |
| coverage xml --rcfile=./.coveragerc -o coverage.xml | |
| coverage report --rcfile=./.coveragerc | |
| # Prepare for upload | |
| mkdir -p ./docs/coverage | |
| mv htmlcov/* ./docs/coverage/ | |
| mv coverage.xml ./docs/coverage/ | |
| echo "" | |
| echo "[SUCCESS] Coverage reports generated successfully" | |
| - name: Archive combined coverage results | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: coverage-combined | |
| path: docs/coverage/ | |
| retention-days: 7 | |
| include-hidden-files: true | |
| - name: Deploy to gh-pages | |
| uses: JamesIves/github-pages-deploy-action@d92aa235d04922e8f08b40ce78cc5442fcfbfa2f # v4.8.0 | |
| with: | |
| git-config-name: cuda-python-bot | |
| git-config-email: cuda-python-bot@users.noreply.github.com | |
| folder: docs/ | |
| target-folder: docs/ | |
| commit-message: "Deploy combined coverage (Linux + Windows): ${{ github.sha }}" | |
| clean: false |