Merge branch 'main' into fix-program-debug #5553
Workflow file for this run
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 | |
| # Note: This name is referred to in the test job, so make sure any changes are sync'd up! | |
| # Further this is referencing a run in the backport branch to fetch old bindings. | |
| name: "CI" | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} | |
| cancel-in-progress: true | |
| on: | |
| push: | |
| branches: | |
| - "pull-request/[0-9]+" | |
| - "main" | |
| tags: | |
| # Build release artifacts from tag refs so setuptools-scm resolves exact | |
| # release versions instead of .dev+local variants. | |
| - "v*" | |
| - "cuda-core-v*" | |
| - "cuda-pathfinder-v*" | |
| schedule: | |
| # every 24 hours at midnight UTC | |
| - cron: "0 0 * * *" | |
| workflow_dispatch: {} | |
| jobs: | |
| ci-vars: | |
| if: ${{ github.repository_owner == 'nvidia' }} | |
| runs-on: ubuntu-latest | |
| outputs: | |
| CUDA_BUILD_VER: ${{ steps.get-vars.outputs.cuda_build_ver }} | |
| CUDA_PREV_BUILD_VER: ${{ steps.get-vars.outputs.cuda_prev_build_ver }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| fetch-depth: 1 | |
| - name: Get CUDA build versions | |
| id: get-vars | |
| run: | | |
| cuda_build_ver=$(yq '.cuda.build.version' ci/versions.yml) | |
| echo "cuda_build_ver=$cuda_build_ver" >> $GITHUB_OUTPUT | |
| cuda_prev_build_ver=$(yq '.cuda.prev_build.version' ci/versions.yml) | |
| echo "cuda_prev_build_ver=$cuda_prev_build_ver" >> $GITHUB_OUTPUT | |
| should-skip: | |
| if: ${{ github.repository_owner == 'nvidia' }} | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| outputs: | |
| skip: ${{ steps.get-should-skip.outputs.skip }} | |
| doc-only: ${{ steps.get-should-skip.outputs.doc_only }} | |
| base-ref: ${{ steps.get-should-skip.outputs.base_ref }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - name: Compute whether to skip builds and tests | |
| id: get-should-skip | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euxo pipefail | |
| if ${{ startsWith(github.ref_name, 'pull-request/') }}; then | |
| pr_number="$(grep -Po '(\d+)$' <<< '${{ github.ref_name }}')" | |
| pr="$(gh pr view "${pr_number}" --json baseRefName,title)" | |
| pr_title="$(jq -r '.title' <<< "${pr}")" | |
| base_ref="$(jq -r '.baseRefName' <<< "${pr}")" | |
| skip="$(echo "${pr_title}" | grep -q '\[no-ci\]' && echo true || echo false)" | |
| doc_only="$(echo "${pr_title}" | grep -q '\[doc-only\]' && echo true || echo false)" | |
| else | |
| skip=false | |
| doc_only=false | |
| base_ref="" | |
| fi | |
| echo "skip=${skip}" >> "$GITHUB_OUTPUT" | |
| echo "doc_only=${doc_only}" >> "$GITHUB_OUTPUT" | |
| echo "base_ref=${base_ref}" >> "$GITHUB_OUTPUT" | |
| # Detect which packages were touched by the PR so downstream build and test | |
| # jobs can avoid rebuilding/retesting packages unaffected by the change. | |
| # See issue #299. | |
| # | |
| # Dependency graph (verified in pyproject.toml files): | |
| # cuda_pathfinder -> (no internal deps) | |
| # cuda_bindings -> cuda_pathfinder | |
| # cuda_core -> cuda_pathfinder, cuda_bindings | |
| # cuda_python -> cuda_pathfinder, cuda_bindings, cuda_core (meta package) | |
| # | |
| # A change to cuda_pathfinder (or shared infra) forces a rebuild of every | |
| # downstream module. A change to cuda_bindings forces rebuild of cuda_core. | |
| # A change to cuda_core alone skips rebuilding/retesting cuda_bindings and | |
| # cuda_pathfinder, but still retests the downstream cuda-python metapackage. | |
| # Shared build/orchestration changes run the full pipeline; test-only CI | |
| # infrastructure runs every test suite without rebuilding package wheels. | |
| # On push to main, tag refs, schedule, or workflow_dispatch events we | |
| # unconditionally run everything because there is no meaningful "changed | |
| # paths" baseline for those events. | |
| detect-changes: | |
| if: ${{ github.repository_owner == 'nvidia' }} | |
| runs-on: ubuntu-latest | |
| needs: should-skip | |
| permissions: | |
| actions: read | |
| contents: read | |
| outputs: | |
| workplan: ${{ steps.workplan.outputs.workplan }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| # Treeless clone: the commit graph is needed to resolve the PR merge | |
| # base and classify its changed paths, but historical blobs aren't. | |
| fetch-depth: 0 | |
| filter: blob:none | |
| - name: Resolve PR merge base | |
| id: merge-base | |
| if: ${{ startsWith(github.ref_name, 'pull-request/') }} | |
| env: | |
| BASE_REF: ${{ needs.should-skip.outputs.base-ref }} | |
| run: | | |
| set -euo pipefail | |
| if [[ -z "${BASE_REF}" ]]; then | |
| echo "Could not resolve PR base branch" >&2 | |
| exit 1 | |
| fi | |
| base=$(git merge-base HEAD "origin/${BASE_REF}") | |
| echo "sha=${base}" >> "$GITHUB_OUTPUT" | |
| - name: Resolve reusable base artifacts | |
| id: baseline | |
| if: ${{ startsWith(github.ref_name, 'pull-request/') }} | |
| env: | |
| BASE_REF: ${{ needs.should-skip.outputs.base-ref }} | |
| MERGE_BASE: ${{ steps.merge-base.outputs.sha }} | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -uo pipefail | |
| unavailable() { | |
| echo "No complete reusable artifact set was found; this run will build and test everything." >> "$GITHUB_STEP_SUMMARY" | |
| exit 0 | |
| } | |
| if [[ -z "${BASE_REF}" ]]; then | |
| unavailable | |
| fi | |
| merge_base="${MERGE_BASE}" | |
| if [[ -z "${merge_base}" ]]; then | |
| unavailable | |
| fi | |
| if ! runs=$(gh run list \ | |
| --repo "${{ github.repository }}" \ | |
| --branch "${BASE_REF}" \ | |
| --commit "${merge_base}" \ | |
| --event push \ | |
| --workflow ci.yml \ | |
| --status success \ | |
| --limit 1 \ | |
| --json databaseId,headSha); then | |
| unavailable | |
| fi | |
| # Reuse only artifacts produced from the exact commit used as the | |
| # PR diff base. Using the latest base-branch run is unsafe for a PR | |
| # that was opened before newer changes landed on that branch. | |
| run_id=$(jq -r '.[0].databaseId // empty' <<< "$runs") | |
| run_sha=$(jq -r '.[0].headSha // empty' <<< "$runs") | |
| if [[ -z "${run_id}" || "${run_sha}" != "${merge_base}" ]]; then | |
| unavailable | |
| fi | |
| if ! artifact_names=$(gh api \ | |
| "repos/${{ github.repository }}/actions/runs/${run_id}/artifacts?per_page=100" \ | |
| --paginate \ | |
| --jq '.artifacts[] | select(.expired == false) | .name'); then | |
| unavailable | |
| fi | |
| has_artifact() { | |
| grep -Fxq "$1" <<< "$artifact_names" | |
| } | |
| missing=() | |
| for name in cuda-pathfinder-wheel cuda-python-wheel; do | |
| has_artifact "$name" || missing+=("$name") | |
| done | |
| cuda_version=$(yq '.cuda.build.version' ci/versions.yml) | |
| if ! python_versions=$(yq -r '.jobs.build.strategy.matrix."python-version"[]' .github/workflows/build-wheel.yml); then | |
| unavailable | |
| fi | |
| if ! platforms=$(yq -r '.platforms[]' ci/test-matrix.yml); then | |
| unavailable | |
| fi | |
| if [[ -z "${python_versions}" || -z "${platforms}" ]]; then | |
| unavailable | |
| fi | |
| while IFS= read -r python_version; do | |
| python=${python_version//./} | |
| while IFS= read -r platform; do | |
| binding="cuda-bindings-python${python}-cuda${cuda_version}-${platform}-${merge_base}" | |
| core="cuda-core-python${python}-${platform}-${merge_base}" | |
| has_artifact "$binding" || missing+=("$binding") | |
| has_artifact "$core" || missing+=("$core") | |
| done <<< "${platforms}" | |
| done <<< "${python_versions}" | |
| if (( ${#missing[@]} != 0 )); then | |
| printf 'Missing reusable artifact: %s\n' "${missing[@]}" >&2 | |
| unavailable | |
| fi | |
| echo "run_id=${run_id}" >> "$GITHUB_OUTPUT" | |
| { | |
| echo | |
| echo "Reusable artifacts: run \`${run_id}\` at \`${merge_base}\` on \`${BASE_REF}\`." | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Test CI workplan planner | |
| run: python3 -m unittest ci/tools/tests/test_compute_ci_plan.py | |
| - name: Compute CI workplan | |
| id: workplan | |
| env: | |
| MERGE_BASE: ${{ steps.merge-base.outputs.sha }} | |
| BASELINE_RUN_ID: ${{ steps.baseline.outputs.run_id }} | |
| run: | | |
| set -euo pipefail | |
| workplan=$(python3 ci/tools/compute_ci_plan.py \ | |
| --merge-base "$MERGE_BASE" \ | |
| --baseline-run-id "$BASELINE_RUN_ID") | |
| echo "workplan=$workplan" >> "$GITHUB_OUTPUT" | |
| { | |
| echo | |
| echo "### CI workplan" | |
| echo '```json' | |
| jq . <<< "$workplan" | |
| echo '```' | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| api-check-core-vs-release: | |
| name: API check (cuda_core vs. latest release) | |
| if: >- | |
| ${{ !fromJSON(needs.should-skip.outputs.skip) && | |
| fromJSON(needs.detect-changes.outputs.workplan).jobs.core_api_checks }} | |
| runs-on: ubuntu-latest | |
| needs: | |
| - should-skip | |
| - detect-changes | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| fetch-depth: 1 | |
| filter: blob:none | |
| - name: Find latest release tag | |
| id: latest-tag | |
| shell: bash --noprofile --norc -euo pipefail {0} | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| # --paginate fetches all pages; jq outputs one name per line per page; | |
| # sed prints the first (newest) match while consuming all pages, so | |
| # gh can complete without SIGPIPE. Fails if no cuda-core-v* tag is found. | |
| tag="$(gh api "repos/$GITHUB_REPOSITORY/tags" --paginate \ | |
| --jq '.[] | select(.name | startswith("cuda-core-v")) | .name' \ | |
| | sed -n '1p')" | |
| if [[ -z "${tag}" ]]; then | |
| echo "::error::No cuda-core-v* tag found in the repository." >&2 | |
| exit 1 | |
| fi | |
| echo "tag=${tag}" >> "$GITHUB_OUTPUT" | |
| - name: Fetch release tag | |
| shell: bash --noprofile --norc -euo pipefail {0} | |
| run: | | |
| git fetch --depth=1 --filter=blob:none origin \ | |
| "refs/tags/${{ steps.latest-tag.outputs.tag }}:refs/tags/${{ steps.latest-tag.outputs.tag }}" | |
| - name: Check cuda_core public API | |
| id: griffe | |
| uses: ./.github/actions/griffe-api-check | |
| with: | |
| package-name: cuda.core | |
| package-dir: cuda_core | |
| merge-base: ${{ steps.latest-tag.outputs.tag }} | |
| api-check-core-vs-base: | |
| name: API check (cuda_core vs. merge base) | |
| if: >- | |
| ${{ startsWith(github.ref_name, 'pull-request/') && | |
| !fromJSON(needs.should-skip.outputs.skip) && | |
| fromJSON(needs.detect-changes.outputs.workplan).jobs.core_api_checks }} | |
| runs-on: ubuntu-latest | |
| needs: | |
| - should-skip | |
| - detect-changes | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| fetch-depth: 1 | |
| filter: blob:none | |
| - name: Fetch merge base commit | |
| shell: bash --noprofile --norc -euo pipefail {0} | |
| run: | | |
| git fetch --depth=1 --filter=blob:none origin \ | |
| "${{ fromJSON(needs.detect-changes.outputs.workplan).merge_base }}" | |
| - name: Check cuda_core public API | |
| id: griffe | |
| uses: ./.github/actions/griffe-api-check | |
| with: | |
| package-name: cuda.core | |
| package-dir: cuda_core | |
| merge-base: ${{ fromJSON(needs.detect-changes.outputs.workplan).merge_base }} | |
| # NOTE: Build jobs are intentionally split by platform rather than using a single | |
| # matrix. This lets each test job consume its platform-specific artifacts as | |
| # soon as they are ready. ARM64 and Windows tests also wait for linux-64, | |
| # which produces the universal pathfinder and cuda-python wheels. Keep these | |
| # job definitions textually identical except for: | |
| # - host-platform value | |
| # - if: condition (build-linux-64 omits doc-only check since it's needed for docs) | |
| build-linux-64: | |
| needs: | |
| - ci-vars | |
| - should-skip | |
| - detect-changes | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| host-platform: | |
| - linux-64 | |
| name: Build ${{ matrix.host-platform }}, CUDA ${{ needs.ci-vars.outputs.CUDA_BUILD_VER }} | |
| if: ${{ github.repository_owner == 'nvidia' && !fromJSON(needs.should-skip.outputs.skip) }} | |
| permissions: | |
| actions: read | |
| contents: read | |
| secrets: inherit | |
| uses: ./.github/workflows/build-wheel.yml | |
| with: | |
| host-platform: ${{ matrix.host-platform }} | |
| cuda-version: ${{ needs.ci-vars.outputs.CUDA_BUILD_VER }} | |
| prev-cuda-version: ${{ needs.ci-vars.outputs.CUDA_PREV_BUILD_VER }} | |
| workplan: ${{ needs.detect-changes.outputs.workplan }} | |
| # See build-linux-64 for why build jobs are split by platform. | |
| build-linux-aarch64: | |
| needs: | |
| - ci-vars | |
| - should-skip | |
| - detect-changes | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| host-platform: | |
| - linux-aarch64 | |
| name: Build ${{ matrix.host-platform }}, CUDA ${{ needs.ci-vars.outputs.CUDA_BUILD_VER }} | |
| if: ${{ github.repository_owner == 'nvidia' && | |
| !fromJSON(needs.should-skip.outputs.skip) && | |
| !fromJSON(needs.should-skip.outputs.doc-only) && | |
| fromJSON(needs.detect-changes.outputs.workplan).jobs.platforms.linux }} | |
| permissions: | |
| actions: read | |
| contents: read | |
| secrets: inherit | |
| uses: ./.github/workflows/build-wheel.yml | |
| with: | |
| host-platform: ${{ matrix.host-platform }} | |
| cuda-version: ${{ needs.ci-vars.outputs.CUDA_BUILD_VER }} | |
| prev-cuda-version: ${{ needs.ci-vars.outputs.CUDA_PREV_BUILD_VER }} | |
| workplan: ${{ needs.detect-changes.outputs.workplan }} | |
| # See build-linux-64 for why build jobs are split by platform. | |
| build-windows: | |
| needs: | |
| - ci-vars | |
| - should-skip | |
| - detect-changes | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| host-platform: | |
| - win-64 | |
| name: Build ${{ matrix.host-platform }}, CUDA ${{ needs.ci-vars.outputs.CUDA_BUILD_VER }} | |
| if: ${{ github.repository_owner == 'nvidia' && | |
| !fromJSON(needs.should-skip.outputs.skip) && | |
| !fromJSON(needs.should-skip.outputs.doc-only) && | |
| fromJSON(needs.detect-changes.outputs.workplan).jobs.platforms.windows }} | |
| permissions: | |
| actions: read | |
| contents: read | |
| secrets: inherit | |
| uses: ./.github/workflows/build-wheel.yml | |
| with: | |
| host-platform: ${{ matrix.host-platform }} | |
| cuda-version: ${{ needs.ci-vars.outputs.CUDA_BUILD_VER }} | |
| prev-cuda-version: ${{ needs.ci-vars.outputs.CUDA_PREV_BUILD_VER }} | |
| workplan: ${{ needs.detect-changes.outputs.workplan }} | |
| # NOTE: test-sdist jobs are split by platform (mirroring build-* and test-wheel-*) | |
| # so platform-specific sources (e.g. cuda_bindings/*_windows.pyx selected by | |
| # build_hooks.py) are exercised on their target OS. Keep these job definitions | |
| # textually identical except for: | |
| # - host-platform value | |
| # - uses: (test-sdist-linux.yml vs test-sdist-windows.yml) | |
| test-sdist-linux: | |
| needs: | |
| - ci-vars | |
| - should-skip | |
| - detect-changes | |
| - build-linux-64 | |
| name: Test sdist linux-64 | |
| if: ${{ github.repository_owner == 'nvidia' && | |
| !fromJSON(needs.should-skip.outputs.skip) && | |
| !fromJSON(needs.should-skip.outputs.doc-only) && | |
| fromJSON(needs.detect-changes.outputs.workplan).jobs.sdist_tests }} | |
| permissions: | |
| actions: read | |
| contents: read | |
| secrets: inherit | |
| uses: ./.github/workflows/test-sdist-linux.yml | |
| with: | |
| host-platform: linux-64 | |
| cuda-version: ${{ needs.ci-vars.outputs.CUDA_BUILD_VER }} | |
| workplan: ${{ needs.detect-changes.outputs.workplan }} | |
| # See test-sdist-linux for why sdist test jobs are split by platform. | |
| test-sdist-windows: | |
| needs: | |
| - ci-vars | |
| - should-skip | |
| - detect-changes | |
| - build-linux-64 | |
| - build-windows | |
| name: Test sdist win-64 | |
| if: ${{ github.repository_owner == 'nvidia' && | |
| !fromJSON(needs.should-skip.outputs.skip) && | |
| !fromJSON(needs.should-skip.outputs.doc-only) && | |
| fromJSON(needs.detect-changes.outputs.workplan).jobs.sdist_tests }} | |
| permissions: | |
| actions: read | |
| contents: read | |
| secrets: inherit | |
| uses: ./.github/workflows/test-sdist-windows.yml | |
| with: | |
| host-platform: win-64 | |
| cuda-version: ${{ needs.ci-vars.outputs.CUDA_BUILD_VER }} | |
| workplan: ${{ needs.detect-changes.outputs.workplan }} | |
| # NOTE: Test jobs are split by platform for the same reason as build jobs (see | |
| # build-linux-64). Keep these job definitions textually identical except for: | |
| # - host-platform value | |
| # - build job under needs: | |
| # - uses: (test-wheel-linux.yml vs test-wheel-windows.yml) | |
| test-linux-64: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| host-platform: | |
| - linux-64 | |
| name: Test ${{ matrix.host-platform }} | |
| if: ${{ github.repository_owner == 'nvidia' && | |
| !fromJSON(needs.should-skip.outputs.doc-only) && | |
| fromJSON(needs.detect-changes.outputs.workplan).jobs.platforms.linux }} | |
| permissions: | |
| actions: read | |
| contents: read # This is required for actions/checkout | |
| needs: | |
| - ci-vars | |
| - should-skip | |
| - detect-changes | |
| - build-linux-64 | |
| secrets: inherit | |
| uses: ./.github/workflows/test-wheel-linux.yml | |
| with: | |
| build-type: pull-request | |
| host-platform: ${{ matrix.host-platform }} | |
| build-ctk-ver: ${{ needs.ci-vars.outputs.CUDA_BUILD_VER }} | |
| nruns: ${{ (github.event_name == 'schedule' && 5) || 1}} | |
| workplan: ${{ needs.detect-changes.outputs.workplan }} | |
| # See test-linux-64 for why test jobs are split by platform. | |
| test-linux-aarch64: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| host-platform: | |
| - linux-aarch64 | |
| name: Test ${{ matrix.host-platform }} | |
| if: ${{ github.repository_owner == 'nvidia' && | |
| !fromJSON(needs.should-skip.outputs.doc-only) && | |
| fromJSON(needs.detect-changes.outputs.workplan).jobs.platforms.linux }} | |
| permissions: | |
| actions: read | |
| contents: read # This is required for actions/checkout | |
| needs: | |
| - ci-vars | |
| - should-skip | |
| - detect-changes | |
| - build-linux-64 | |
| - build-linux-aarch64 | |
| secrets: inherit | |
| uses: ./.github/workflows/test-wheel-linux.yml | |
| with: | |
| build-type: pull-request | |
| host-platform: ${{ matrix.host-platform }} | |
| build-ctk-ver: ${{ needs.ci-vars.outputs.CUDA_BUILD_VER }} | |
| nruns: ${{ (github.event_name == 'schedule' && 5) || 1}} | |
| workplan: ${{ needs.detect-changes.outputs.workplan }} | |
| # See test-linux-64 for why test jobs are split by platform. | |
| test-windows: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| host-platform: | |
| - win-64 | |
| name: Test ${{ matrix.host-platform }} | |
| if: ${{ github.repository_owner == 'nvidia' && | |
| !fromJSON(needs.should-skip.outputs.doc-only) && | |
| fromJSON(needs.detect-changes.outputs.workplan).jobs.platforms.windows }} | |
| permissions: | |
| actions: read | |
| contents: read # This is required for actions/checkout | |
| needs: | |
| - ci-vars | |
| - should-skip | |
| - detect-changes | |
| - build-linux-64 | |
| - build-windows | |
| secrets: inherit | |
| uses: ./.github/workflows/test-wheel-windows.yml | |
| with: | |
| build-type: pull-request | |
| host-platform: ${{ matrix.host-platform }} | |
| build-ctk-ver: ${{ needs.ci-vars.outputs.CUDA_BUILD_VER }} | |
| nruns: ${{ (github.event_name == 'schedule' && 5) || 1}} | |
| workplan: ${{ needs.detect-changes.outputs.workplan }} | |
| doc: | |
| name: Docs | |
| if: ${{ github.repository_owner == 'nvidia' }} | |
| # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages | |
| permissions: | |
| id-token: write | |
| contents: write | |
| pull-requests: write | |
| needs: | |
| - ci-vars | |
| - build-linux-64 | |
| secrets: inherit | |
| uses: ./.github/workflows/build-docs.yml | |
| with: | |
| is-release: ${{ github.ref_type == 'tag' }} | |
| precommit-windows: | |
| name: Pre-commit on Windows | |
| runs-on: windows-latest | |
| if: ${{ github.repository_owner == 'nvidia' && !fromJSON(needs.should-skip.outputs.skip) }} | |
| needs: | |
| - should-skip | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| fetch-depth: 1 | |
| persist-credentials: false | |
| - name: Set up Python | |
| uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 | |
| with: | |
| python-version: '3.13' | |
| - name: Install pre-commit | |
| shell: bash | |
| run: | | |
| set -euxo pipefail | |
| python -m pip install --upgrade pip pre-commit | |
| - name: Run pre-commit | |
| shell: bash | |
| run: | | |
| set -euxo pipefail | |
| SKIP=lychee pre-commit run --all-files | |
| checks: | |
| name: Check job status | |
| if: ${{ always() && github.repository_owner == 'nvidia' }} | |
| runs-on: ubuntu-latest | |
| needs: | |
| - ci-vars | |
| - should-skip | |
| - detect-changes | |
| - build-linux-64 | |
| - build-linux-aarch64 | |
| - build-windows | |
| - test-sdist-linux | |
| - test-sdist-windows | |
| - test-linux-64 | |
| - test-linux-aarch64 | |
| - test-windows | |
| - api-check-core-vs-release | |
| - api-check-core-vs-base | |
| - doc | |
| - precommit-windows | |
| steps: | |
| - name: Exit | |
| env: | |
| NEEDS_JSON: ${{ toJSON(needs) }} | |
| run: | | |
| # GitHub treats `result == 'skipped'` as success for required | |
| # status checks (see CCCL gate comment + cccl#605). The previous | |
| # `cancelled || failure` predicate let upstream build failures | |
| # propagate as `skipped` on downstream test jobs and silently | |
| # pass this aggregator. Adopt CCCL's `check_result` pattern: | |
| # require an explicit `expected` status per dependency, where | |
| # anything else (including `skipped` from a failed upstream) | |
| # fails the gate. `if: always()` on the job still ensures this | |
| # step runs even when needs are skipped. | |
| if [[ "${{ needs.should-skip.outputs.skip }}" == "true" ]]; then | |
| echo "[no-ci] - skipping aggregator checks" | |
| exit 0 | |
| fi | |
| doc_only="${{ needs.should-skip.outputs.doc-only }}" | |
| linux_selected="${{ needs.detect-changes.outputs.workplan && fromJSON(needs.detect-changes.outputs.workplan).jobs.platforms.linux || false }}" | |
| windows_selected="${{ needs.detect-changes.outputs.workplan && fromJSON(needs.detect-changes.outputs.workplan).jobs.platforms.windows || false }}" | |
| build_selected="${{ needs.detect-changes.outputs.workplan && fromJSON(needs.detect-changes.outputs.workplan).jobs.sdist_tests || false }}" | |
| run_core_api_check="${{ needs.detect-changes.outputs.workplan && fromJSON(needs.detect-changes.outputs.workplan).jobs.core_api_checks || false }}" | |
| is_pr="${{ startsWith(github.ref_name, 'pull-request/') }}" | |
| status="success" | |
| check_result() { | |
| local name=$1 expected=$2 result | |
| result=$(jq -r --arg name "$name" '.[$name].result // "missing"' <<< "$NEEDS_JSON") | |
| echo "Checking $name: result='$result' (expected '$expected')" | |
| if [[ "$result" != "$expected" ]]; then | |
| echo "::error::$name did not match expected result" | |
| status="failed" | |
| fi | |
| } | |
| # Control jobs, the universal linux build, docs, and Windows | |
| # pre-commit checks always run. | |
| check_result "ci-vars" "success" | |
| check_result "should-skip" "success" | |
| check_result "detect-changes" "success" | |
| check_result "build-linux-64" "success" | |
| check_result "doc" "success" | |
| check_result "precommit-windows" "success" | |
| # Optional platform builds and wheel tests share the platform plan. | |
| linux_expected="skipped" | |
| if [[ "$doc_only" != "true" && "$linux_selected" == "true" ]]; then | |
| linux_expected="success" | |
| fi | |
| windows_expected="skipped" | |
| if [[ "$doc_only" != "true" && "$windows_selected" == "true" ]]; then | |
| windows_expected="success" | |
| fi | |
| check_result "build-linux-aarch64" "$linux_expected" | |
| check_result "build-windows" "$windows_expected" | |
| # Sdist tests follow build selection; wheel tests follow the platform plan. | |
| expected="skipped" | |
| if [[ "$doc_only" != "true" && "$build_selected" == "true" ]]; then | |
| expected="success" | |
| fi | |
| check_result "test-sdist-linux" "$expected" | |
| check_result "test-sdist-windows" "$expected" | |
| check_result "test-linux-64" "$linux_expected" | |
| check_result "test-linux-aarch64" "$linux_expected" | |
| check_result "test-windows" "$windows_expected" | |
| # API compatibility checks run for cuda_core source changes and for | |
| # conservative full runs when reusable base artifacts are unavailable. | |
| expected="skipped" | |
| if [[ "$run_core_api_check" == "true" ]]; then expected="success"; fi | |
| check_result "api-check-core-vs-release" "$expected" | |
| expected="skipped" | |
| if [[ "$is_pr" == "true" && "$run_core_api_check" == "true" ]]; then expected="success"; fi | |
| check_result "api-check-core-vs-base" "$expected" | |
| [[ "$status" == "success" ]] |