Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
497 changes: 345 additions & 152 deletions .github/workflows/build-wheel.yml

Large diffs are not rendered by default.

255 changes: 138 additions & 117 deletions .github/workflows/ci.yml

Large diffs are not rendered by default.

73 changes: 47 additions & 26 deletions .github/workflows/test-sdist-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ on:
host-platform:
required: true
type: string
cuda-version:
bindings-package:
description: Normalized CUDA bindings package JSON.
required: true
type: string
workplan:
description: JSON workplan. An empty value builds everything.
required: false
default: ""
description: JSON workplan.
required: true
type: string

defaults:
Expand All @@ -27,13 +27,17 @@ permissions:

jobs:
test-sdist:
name: Test sdist builds
if: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).jobs.sdist_tests }}
name: Sdist ${{ fromJSON(inputs.workplan).labels.sdist[fromJSON(inputs.bindings-package).package_root] }}
if: ${{ fromJSON(inputs.workplan).jobs.sdist_package_roots[fromJSON(inputs.bindings-package).package_root] }}
env:
BUILD_PATHFINDER: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.pathfinder.needs_build }}
BUILD_BINDINGS: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.bindings.needs_build }}
BUILD_CORE: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.core.needs_build }}
BUILD_PYTHON: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.python.needs_build }}
BINDINGS_ROOT: ${{ fromJSON(inputs.bindings-package).package_root }}
CUDA_BUILD_VERSION: ${{ fromJSON(inputs.bindings-package).toolkit_version }}
CUDA_PYTHON_BUILD_MAJOR: ${{ fromJSON(inputs.bindings-package).cuda_major }}
BUILD_PATHFINDER: ${{ fromJSON(inputs.workplan).modules.pathfinder.needs_build }}
BUILD_BINDINGS: ${{ fromJSON(inputs.workplan).modules.bindings.package_roots[fromJSON(inputs.bindings-package).package_root].needs_build }}
BUILD_CORE: ${{ fromJSON(inputs.workplan).modules.core.cuda_majors[fromJSON(inputs.bindings-package).cuda_variant].needs_build }}
BUILD_CUDA_PYTHON: ${{ fromJSON(inputs.workplan).modules.python.package_roots[fromJSON(inputs.bindings-package).package_root].needs_build }}
PATHFINDER_SOURCE: ${{ fromJSON(inputs.workplan).sources.pathfinder }}
timeout-minutes: 60
runs-on: linux-amd64-cpu8
steps:
Expand All @@ -51,8 +55,14 @@ jobs:
with:
python-version: "3.12"

- name: Install build tools
run: python -m pip install "pip>=25.3" build
- name: Install build and CI tools
run: python -m pip install "pip>=25.3" build -e ./ci

- name: Prepare local maintenance SCM milestone
if: ${{ fromJSON(inputs.bindings-package).release_status == 'maintenance' }}
run: |
python -m ci.tools.bindings_scm_version \
--package-root "${BINDINGS_ROOT}" --sha "${{ github.sha }}"

# Pure Python packages -- no CTK needed.
- name: Build cuda.pathfinder sdist and wheel-from-sdist
Expand All @@ -62,13 +72,14 @@ jobs:
pip wheel --no-deps --wheel-dir cuda_pathfinder/dist cuda_pathfinder/dist/*.tar.gz

- name: Build cuda-python sdist and wheel-from-sdist
if: ${{ env.BUILD_PYTHON == 'true' }}
if: ${{ env.BUILD_CUDA_PYTHON == 'true' }}
run: |
python -m build --sdist cuda_python/
pip wheel --no-deps --wheel-dir cuda_python/dist cuda_python/dist/*.tar.gz

- name: Download cuda.pathfinder wheel
if: ${{ env.BUILD_PATHFINDER != 'true' && (env.BUILD_BINDINGS == 'true' || env.BUILD_CORE == 'true') }}
if: ${{ env.BUILD_PATHFINDER != 'true' && (env.BUILD_BINDINGS == 'true' || env.BUILD_CORE == 'true') &&
env.PATHFINDER_SOURCE == 'artifact' }}
uses: ./.github/actions/download-artifact-retry
with:
name: cuda-pathfinder-wheel
Expand All @@ -78,11 +89,21 @@ jobs:
if: ${{ env.BUILD_BINDINGS == 'true' }}
run: |
pathfinder_wheels=(cuda_pathfinder/dist/cuda_pathfinder-*.whl)
test "${#pathfinder_wheels[@]}" -eq 1
test -f "${pathfinder_wheels[0]}"
mkdir -p wheel-constraints
pathfinder_uri="file://$(realpath "${pathfinder_wheels[0]}")"
printf 'cuda-pathfinder @ %s\n' "${pathfinder_uri}" | tee wheel-constraints/cuda-bindings.txt
if [[ "${PATHFINDER_SOURCE}" == "artifact" ]]; then
if [[ "${#pathfinder_wheels[@]}" -ne 1 || ! -f "${pathfinder_wheels[0]}" ]]; then
echo "Expected exactly one cuda-pathfinder wheel in cuda_pathfinder/dist" >&2
exit 1
fi
pathfinder_uri="file://$(realpath "${pathfinder_wheels[0]}")"
printf 'cuda-pathfinder @ %s\n' "${pathfinder_uri}" > wheel-constraints/cuda-bindings.txt
elif [[ "${PATHFINDER_SOURCE}" == "published" ]]; then
: > wheel-constraints/cuda-bindings.txt
else
echo "Error: PATHFINDER_SOURCE must be artifact or published, got ${PATHFINDER_SOURCE}" >&2
exit 1
fi
cat wheel-constraints/cuda-bindings.txt

# Cython packages need CTK + sccache.
# The env vars ACTIONS_CACHE_SERVICE_V2, ACTIONS_RESULTS_URL, and ACTIONS_RUNTIME_TOKEN
Expand All @@ -107,7 +128,7 @@ jobs:
continue-on-error: false
with:
host-platform: ${{ inputs.host-platform }}
cuda-version: ${{ inputs.cuda-version }}
cuda-version: ${{ fromJSON(inputs.bindings-package).toolkit_version }}

# cuda_bindings_13/setup.py parses CUDA headers at import time, so CUDA_PATH
# (set by fetch_ctk) must be available for both sdist and wheel builds.
Expand All @@ -119,22 +140,22 @@ jobs:
export CXX="sccache c++"
export PIP_BUILD_CONSTRAINT="$(pwd)/wheel-constraints/cuda-bindings.txt"
export PIP_CONSTRAINT="${PIP_BUILD_CONSTRAINT}"
python -m build --sdist cuda_bindings_13/
pip wheel --no-deps --wheel-dir cuda_bindings_13/dist cuda_bindings_13/dist/*.tar.gz
python -m build --sdist "${BINDINGS_ROOT}/"
pip wheel --no-deps --wheel-dir "${BINDINGS_ROOT}/dist" "${BINDINGS_ROOT}"/dist/*.tar.gz

- name: Download cuda.bindings wheel
if: ${{ env.BUILD_BINDINGS != 'true' && env.BUILD_CORE == 'true' }}
uses: ./.github/actions/download-artifact-retry
with:
name: cuda-bindings-python312-cuda${{ inputs.cuda-version }}-${{ inputs.host-platform }}-${{ github.sha }}
path: cuda_bindings_13/dist
name: cuda-bindings-python312-cuda${{ fromJSON(inputs.bindings-package).toolkit_version }}-${{ inputs.host-platform }}-${{ github.sha }}
path: ${{ env.BINDINGS_ROOT }}/dist

- name: Constrain cuda.core to the local cuda.bindings wheel
if: ${{ env.BUILD_CORE == 'true' }}
run: |
CUDA_MAJOR="$(echo '${{ inputs.cuda-version }}' | cut -d. -f1)"
CUDA_MAJOR='${{ fromJSON(inputs.bindings-package).cuda_major }}'
pathfinder_wheels=(cuda_pathfinder/dist/cuda_pathfinder-*.whl)
bindings_wheels=(cuda_bindings_13/dist/cuda_bindings-"${CUDA_MAJOR}".*.whl)
bindings_wheels=("${BINDINGS_ROOT}"/dist/cuda_bindings-"${CUDA_MAJOR}".*.whl)
test "${#pathfinder_wheels[@]}" -eq 1
test "${#bindings_wheels[@]}" -eq 1
test -f "${pathfinder_wheels[0]}"
Expand All @@ -154,7 +175,7 @@ jobs:
if: ${{ env.BUILD_CORE == 'true' }}
run: |
export CUDA_PYTHON_PARALLEL_LEVEL=$(nproc)
export CUDA_CORE_BUILD_MAJOR="$(echo '${{ inputs.cuda-version }}' | cut -d. -f1)"
export CUDA_CORE_BUILD_MAJOR='${{ fromJSON(inputs.bindings-package).cuda_major }}'
export CC="sccache cc"
export CXX="sccache c++"
export PIP_BUILD_CONSTRAINT="$(pwd)/wheel-constraints/cuda-core.txt"
Expand Down
74 changes: 48 additions & 26 deletions .github/workflows/test-sdist-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ on:
host-platform:
required: true
type: string
cuda-version:
bindings-package:
description: Normalized CUDA bindings package JSON.
required: true
type: string
workplan:
description: JSON workplan. An empty value builds everything.
required: false
default: ""
description: JSON workplan.
required: true
type: string

defaults:
Expand All @@ -33,13 +33,17 @@ permissions:

jobs:
test-sdist:
name: Test sdist builds
if: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).jobs.sdist_tests }}
name: Sdist ${{ fromJSON(inputs.workplan).labels.sdist[fromJSON(inputs.bindings-package).package_root] }}
if: ${{ fromJSON(inputs.workplan).jobs.sdist_package_roots[fromJSON(inputs.bindings-package).package_root] }}
env:
BUILD_PATHFINDER: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.pathfinder.needs_build }}
BUILD_BINDINGS: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.bindings.needs_build }}
BUILD_CORE: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.core.needs_build }}
BUILD_PYTHON: ${{ inputs.workplan == '' || fromJSON(inputs.workplan).modules.python.needs_build }}
BINDINGS_ROOT: ${{ fromJSON(inputs.bindings-package).package_root }}
CUDA_BUILD_VERSION: ${{ fromJSON(inputs.bindings-package).toolkit_version }}
CUDA_PYTHON_BUILD_MAJOR: ${{ fromJSON(inputs.bindings-package).cuda_major }}
BUILD_PATHFINDER: ${{ fromJSON(inputs.workplan).modules.pathfinder.needs_build }}
BUILD_BINDINGS: ${{ fromJSON(inputs.workplan).modules.bindings.package_roots[fromJSON(inputs.bindings-package).package_root].needs_build }}
BUILD_CORE: ${{ fromJSON(inputs.workplan).modules.core.cuda_majors[fromJSON(inputs.bindings-package).cuda_variant].needs_build }}
BUILD_CUDA_PYTHON: ${{ fromJSON(inputs.workplan).modules.python.package_roots[fromJSON(inputs.bindings-package).package_root].needs_build }}
PATHFINDER_SOURCE: ${{ fromJSON(inputs.workplan).sources.pathfinder }}
timeout-minutes: 60
runs-on: windows-2022
steps:
Expand All @@ -64,8 +68,15 @@ jobs:
if: ${{ env.BUILD_BINDINGS == 'true' || env.BUILD_CORE == 'true' }}
uses: step-security/msvc-dev-cmd@22c98154b708dbd743e6f27a933cf6ceba3305c4 # v1.13.1

- name: Install build tools
run: python -m pip install "pip>=25.3" build
- name: Install build and CI tools
run: python -m pip install "pip>=25.3" build -e ./ci

- name: Prepare local maintenance SCM milestone
if: ${{ fromJSON(inputs.bindings-package).release_status == 'maintenance' }}
shell: bash --noprofile --norc -xeuo pipefail {0}
run: |
python -m ci.tools.bindings_scm_version \
--package-root "${BINDINGS_ROOT}" --sha "${{ github.sha }}"

# Pure Python packages -- no CTK needed.
- name: Build cuda.pathfinder sdist and wheel-from-sdist
Expand All @@ -75,13 +86,14 @@ jobs:
pip wheel --no-deps --wheel-dir cuda_pathfinder/dist cuda_pathfinder/dist/*.tar.gz

- name: Build cuda-python sdist and wheel-from-sdist
if: ${{ env.BUILD_PYTHON == 'true' }}
if: ${{ env.BUILD_CUDA_PYTHON == 'true' }}
run: |
python -m build --sdist cuda_python/
pip wheel --no-deps --wheel-dir cuda_python/dist cuda_python/dist/*.tar.gz

- name: Download cuda.pathfinder wheel
if: ${{ env.BUILD_PATHFINDER != 'true' && (env.BUILD_BINDINGS == 'true' || env.BUILD_CORE == 'true') }}
if: ${{ env.BUILD_PATHFINDER != 'true' && (env.BUILD_BINDINGS == 'true' || env.BUILD_CORE == 'true') &&
env.PATHFINDER_SOURCE == 'artifact' }}
uses: ./.github/actions/download-artifact-retry
with:
name: cuda-pathfinder-wheel
Expand All @@ -91,11 +103,21 @@ jobs:
if: ${{ env.BUILD_BINDINGS == 'true' }}
run: |
pathfinder_wheels=(cuda_pathfinder/dist/cuda_pathfinder-*.whl)
test "${#pathfinder_wheels[@]}" -eq 1
test -f "${pathfinder_wheels[0]}"
mkdir -p wheel-constraints
pathfinder_uri="file:///$(cygpath -am "${pathfinder_wheels[0]}")"
printf 'cuda-pathfinder @ %s\n' "${pathfinder_uri}" | tee wheel-constraints/cuda-bindings.txt
if [[ "${PATHFINDER_SOURCE}" == "artifact" ]]; then
if [[ "${#pathfinder_wheels[@]}" -ne 1 || ! -f "${pathfinder_wheels[0]}" ]]; then
echo "Expected exactly one cuda-pathfinder wheel in cuda_pathfinder/dist" >&2
exit 1
fi
pathfinder_uri="file:///$(cygpath -am "${pathfinder_wheels[0]}")"
printf 'cuda-pathfinder @ %s\n' "${pathfinder_uri}" > wheel-constraints/cuda-bindings.txt
elif [[ "${PATHFINDER_SOURCE}" == "published" ]]; then
: > wheel-constraints/cuda-bindings.txt
else
echo "Error: PATHFINDER_SOURCE must be artifact or published, got ${PATHFINDER_SOURCE}" >&2
exit 1
fi
cat wheel-constraints/cuda-bindings.txt

# Cython packages need CTK. No sccache on Windows (this is a correctness
# smoke test, not a production build; see build-wheel.yml which also
Expand All @@ -106,7 +128,7 @@ jobs:
continue-on-error: false
with:
host-platform: ${{ inputs.host-platform }}
cuda-version: ${{ inputs.cuda-version }}
cuda-version: ${{ fromJSON(inputs.bindings-package).toolkit_version }}

# cuda_bindings_13/setup.py parses CUDA headers at import time, so CUDA_PATH
# (set by fetch_ctk) must be available for both sdist and wheel builds.
Expand All @@ -118,22 +140,22 @@ jobs:
export CUDA_PYTHON_PARALLEL_LEVEL=$(nproc)
export PIP_BUILD_CONSTRAINT="$(cygpath -w "$(pwd)/wheel-constraints/cuda-bindings.txt")"
export PIP_CONSTRAINT="${PIP_BUILD_CONSTRAINT}"
python -m build --sdist cuda_bindings_13/
pip wheel --no-deps --wheel-dir cuda_bindings_13/dist cuda_bindings_13/dist/*.tar.gz
python -m build --sdist "${BINDINGS_ROOT}/"
pip wheel --no-deps --wheel-dir "${BINDINGS_ROOT}/dist" "${BINDINGS_ROOT}"/dist/*.tar.gz

- name: Download cuda.bindings wheel
if: ${{ env.BUILD_BINDINGS != 'true' && env.BUILD_CORE == 'true' }}
uses: ./.github/actions/download-artifact-retry
with:
name: cuda-bindings-python312-cuda${{ inputs.cuda-version }}-${{ inputs.host-platform }}-${{ github.sha }}
path: cuda_bindings_13/dist
name: cuda-bindings-python312-cuda${{ fromJSON(inputs.bindings-package).toolkit_version }}-${{ inputs.host-platform }}-${{ github.sha }}
path: ${{ env.BINDINGS_ROOT }}/dist

- name: Constrain cuda.core to the local cuda.bindings wheel
if: ${{ env.BUILD_CORE == 'true' }}
run: |
CUDA_MAJOR="$(echo '${{ inputs.cuda-version }}' | cut -d. -f1)"
CUDA_MAJOR='${{ fromJSON(inputs.bindings-package).cuda_major }}'
pathfinder_wheels=(cuda_pathfinder/dist/cuda_pathfinder-*.whl)
bindings_wheels=(cuda_bindings_13/dist/cuda_bindings-"${CUDA_MAJOR}".*.whl)
bindings_wheels=("${BINDINGS_ROOT}"/dist/cuda_bindings-"${CUDA_MAJOR}".*.whl)
test "${#pathfinder_wheels[@]}" -eq 1
test "${#bindings_wheels[@]}" -eq 1
test -f "${pathfinder_wheels[0]}"
Expand All @@ -153,7 +175,7 @@ jobs:
if: ${{ env.BUILD_CORE == 'true' }}
run: |
export CUDA_PYTHON_PARALLEL_LEVEL=$(nproc)
export CUDA_CORE_BUILD_MAJOR="$(echo '${{ inputs.cuda-version }}' | cut -d. -f1)"
export CUDA_CORE_BUILD_MAJOR='${{ fromJSON(inputs.bindings-package).cuda_major }}'
export PIP_BUILD_CONSTRAINT="$(cygpath -w "$(pwd)/wheel-constraints/cuda-core.txt")"
export PIP_CONSTRAINT="${PIP_BUILD_CONSTRAINT}"
python -m build --sdist cuda_core/
Expand Down
22 changes: 12 additions & 10 deletions ci/ci-pipeline.mmd
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@ config:
flowchart TB
subgraph TRIGGER["TRIGGER EVENTS"]
direction LR
T1["Push to main branch"] ~~~ T2["Pull request"] ~~~ T3["Manual workflow dispatch"]
T1["Main or approved pull request"] ~~~ T2["Immutable package tag"] ~~~ T3["Manual workflow dispatch"]
end

PLAN["Select affected packages and dependencies<br/>A package tag selects its release line<br/>Registry: ci/versions.yml"]

subgraph BUILD["BUILD STAGE"]
direction TB
subgraph BUILD_PLATFORMS["Parallel Platform Builds"]
direction LR
B1["linux-64<br/>(Self-hosted)"] ~~~ B2["linux-aarch64<br/>(Self-hosted)"] ~~~ B3["win-64<br/>(GitHub-hosted)"]
B1["Linux x86_64<br/>(Self-hosted)"] ~~~ B2["Linux ARM64<br/>(Self-hosted)"] ~~~ B3["Windows x86_64 / ARM64<br/>(GitHub-hosted)"]
end
BUILD_DETAILS["Python versions: 3.11, 3.12, 3.13, 3.14, 3.15<br/>CUDA version: 13.0.0 (build-time)<br/>Components: cuda-core, cuda-bindings,<br/>cuda-pathfinder, cuda-python"]
BUILD_DETAILS["Python and platform matrices: ci.yml<br/>Bindings toolkits and roots: registry<br/>Build selected bindings, Core,<br/>Pathfinder and metapackage artifacts"]
end

subgraph ARTIFACTS["ARTIFACT STORAGE"]
Expand All @@ -51,22 +53,22 @@ flowchart TB
direction TB
subgraph TEST_PLATFORMS["Parallel Platform Tests"]
direction LR
TS1["linux-64<br/>(Self-hosted)"] ~~~ TS2["linux-aarch64<br/>(Self-hosted)"] ~~~ TS3["win-64<br/>(GitHub-hosted)"]
TS1["linux-64<br/>(Self-hosted)"] ~~~ TS2["linux-aarch64<br/>(Self-hosted)"] ~~~ TS3["win-64<br/>(Self-hosted GPU)"]
end
TEST_DETAILS["Download wheels from artifacts<br/>Test against multiple CUDA runtime versions<br/>Run Python unit tests, Cython tests, and examples"]
ARTIFACT_FLOWS["Artifact Flows:<br/>cuda-pathfinder: main to backport<br/>cuda-bindings: backport to main"]
TEST_DETAILS["Test sources match wheel build revision<br/>Test against multiple CUDA runtime versions<br/>Run Python unit tests, Cython tests, and examples"]
ARTIFACT_FLOWS["Both bindings roots build from this source tree<br/>Reuse validated baseline for unaffected packages<br/>Bindings tag: selected line and published Pathfinder<br/>Core older-toolkit tests: published bindings floor"]
end

subgraph RELEASE["RELEASE PIPELINE"]
direction TB
subgraph RELEASE_STAGES["Sequential Release Steps"]
direction LR
R1["Validation<br/>Artifact integrity<br/>Git tag verification"] --> R2["Publishing<br/>PyPI/TestPyPI<br/>Component or all releases"] --> R3["Documentation<br/>GitHub Pages<br/>Release notes"]
R1["Validation<br/>Artifact integrity<br/>Git tag verification"] --> R2["Publishing<br/>PyPI/TestPyPI<br/>Selected component"] --> R3["Documentation<br/>GitHub Pages<br/>Release notes"]
end
RELEASE_DETAILS["Manual workflow dispatch with run ID<br/>Supports individual component or full releases"]
RELEASE_DETAILS["Manual dry run for exact tag and successful CI run<br/>Explicit publication for selected component<br/>Bindings release does not require a Core release"]
end

TRIGGER --> BUILD
TRIGGER --> PLAN --> BUILD
BUILD -. "wheel upload" .-> ARTIFACTS
ARTIFACTS --> TEST
TEST --> RELEASE
Expand All @@ -90,7 +92,7 @@ flowchart TB
class TRIGGER triggerStyle
class T1,T2,T3 triggerNodeStyle
class BUILD,BUILD_PLATFORMS buildStyle
class B1,B2,B3,BUILD_DETAILS buildNodeStyle
class PLAN,B1,B2,B3,BUILD_DETAILS buildNodeStyle
class ARTIFACTS,GITHUB_ARTIFACTS,GITHUB_CACHE artifactStyle
class GA1,GC1 artifactNodeStyle
class TEST,TEST_PLATFORMS testStyle
Expand Down
Loading
Loading