Skip to content

Commit 774e988

Browse files
rparolinclaude
andauthored
ci: validate pixi run test source-build (PR smoke + nightly GPU) (#2185)
* Fix cuda-version pin lag breaking local pixi run test The bindings were regenerated against CUDA 13.3.0 (cc50515), adding NVRTC symbols (NVRTC_ERROR_BUSY, nvrtcBundledHeadersInfo, nvrtcGetBundledHeadersInfo), but the pixi cuda-version pins stayed at 13.2 in cuda_bindings/pixi.toml and cuda_core/pixi.toml. `pixi run test` then built 13.3-referencing Cython code against a 13.2 nvrtc.h and failed with "'nvrtcBundledHeadersInfo' was not declared in this scope". CI was unaffected because it builds wheels from ci/versions.yml (13.3.0) rather than via pixi run test. Bump the cuda-version pins (build-variants + feature.cu13) from 13.2.* to 13.3.* in both packages so the local toolkit matches the regenerated sources and ci/versions.yml. Re-solved pixi.lock files accordingly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Place cython-test .so in tests/cython regardless of cwd tests/cython/build_tests.py runs `build_ext --inplace`, which writes the compiled .so relative to the current working directory. pixi runs the build-cython-tests task from the project root, so the .so landed in the package root instead of tests/cython/, where pytest imports it by bare module name. The test only passed previously because a correctly-placed .so from an earlier build persisted (gitignored); a clean checkout fails with ModuleNotFoundError. chdir to the script directory before build_ext --inplace so the .so lands next to its .pyx in both cuda_bindings and cuda_core (kept aligned per #1978). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci: validate pixi run test source-build (PR smoke + nightly GPU) Main CI tests prebuilt wheels and never exercises the pixi source build, so that developer path rots silently on CUDA-pin / generated-source / conda-forge / cython-build drift (#2182, #2183). Add a workflow that runs the pixi source build: - build-smoke (PRs touching the at-risk files): CPU-only. Source-builds bindings + core, imports them, builds the cython test extensions and checks placement. Catches the compile / ABI / .so-placement regressions without a GPU. - full-test (nightly + manual): GPU runner, full `pixi run test`. Shared pixi install factored into a composite action with an explicit, asserted version pin. Relates to #2183 (validate the source-build path over time); the regressions this guards against are #2182, fixed by #2180. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci: declare linux-amd64-gpu-l4-latest-1 self-hosted runner label for actionlint actionlint validates static runner labels against its known set; the new full-test job uses a literal GPU label (existing GPU jobs dodge this by building the label from a matrix expression). Declare it so pre-commit's actionlint hook passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci: checkout full history + tags so setuptools-scm derives the real version A shallow checkout has no tags, so the source-built packages get setuptools-scm's 0.1.dev1 fallback. cuda.core's import-time guard then rejects cuda.bindings ("12.x or 13.x must be installed"). Use fetch-depth: 0 in both jobs so the build resolves the real 13.x version. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci: use pinned prefix-dev/setup-pixi instead of curl|bash installer Addresses review (@mdboom): the composite action shelled out to `curl -fsSL https://pixi.sh/install.sh | bash`, an unverified installer (the codecov.io supply-chain failure mode). Replace it with prefix-dev/setup-pixi pinned to a commit SHA (v0.9.6) — its install logic is auditable and pinned — and delete the composite action file. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci: switch workflow to pinned prefix-dev/setup-pixi (fixup) The prior commit only removed the composite action file; this commits the workflow change that actually uses prefix-dev/setup-pixi@<sha> in both jobs (and drops the now-unneeded curl from the container apt install). Without this the workflow referenced the deleted ./.github/actions/setup-pixi. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 6df4e75 commit 774e988

2 files changed

Lines changed: 150 additions & 0 deletions

File tree

.github/actionlint.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
self-hosted-runner:
88
labels:
99
- linux-amd64-cpu8
10+
- linux-amd64-gpu-l4-latest-1
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
# Validates the `pixi run test` developer workflow (source build + Cython
6+
# codegen + test suite via the pixi-managed environment).
7+
#
8+
# WHY THIS EXISTS: the main CI (ci.yml / test-wheel-*.yml) tests prebuilt
9+
# *wheels*; it never exercises the pixi *source build*. That path rots silently
10+
# whenever the CUDA pin, generated bindings, conda-forge packages, or the
11+
# cython-test build mechanics drift (see #2182, #2183). This workflow is the
12+
# only thing that runs the pixi source build end to end.
13+
#
14+
# Two tiers, to spend GPU minutes deliberately (GPUs are scarce):
15+
# - build-smoke (PRs): CPU-only. Source-builds bindings + core, imports them,
16+
# builds the cython test extensions and checks placement. Catches the
17+
# compile / ABI / .so-placement regressions WITHOUT a GPU.
18+
# - full-test (nightly + manual): GPU runner, full `pixi run test`.
19+
20+
name: "CI: pixi run test (source build)"
21+
22+
concurrency:
23+
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
24+
cancel-in-progress: true
25+
26+
on:
27+
schedule:
28+
# 2:37 AM UTC daily — offset from ci-nightly.yml (2:17) to avoid contending
29+
# for the same scheduled-workflow window.
30+
- cron: "37 2 * * *"
31+
pull_request:
32+
# Only the files that can break the source-build path (see #2182/#2183).
33+
paths:
34+
- "**/pixi.toml"
35+
- "**/pixi.lock"
36+
- "cuda_bindings/build_hooks.py"
37+
- "cuda_core/build_hooks.py"
38+
- "cuda_bindings/cuda/bindings/**" # generated bindings sources
39+
- "cuda_bindings/tests/cython/**"
40+
- "cuda_core/tests/cython/**"
41+
- "ci/versions.yml"
42+
- ".github/workflows/ci-pixi-source-test.yml"
43+
workflow_dispatch:
44+
inputs:
45+
cuda-env:
46+
description: "pixi environment to test (cu13 or cu12)."
47+
type: string
48+
default: "cu13"
49+
50+
defaults:
51+
run:
52+
shell: bash --noprofile --norc -xeuo pipefail {0}
53+
54+
env:
55+
PIXI_VERSION: "v0.66.0" # keep in sync with the version developers run locally
56+
57+
jobs:
58+
# ── PR guard: CPU-only build + import + placement smoke ──
59+
build-smoke:
60+
name: "build smoke (cu13, linux-64, CPU)"
61+
if: ${{ github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' }}
62+
runs-on: ubuntu-latest
63+
timeout-minutes: 45
64+
steps:
65+
- name: Checkout ${{ github.event.repository.name }}
66+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
67+
with:
68+
# Full history + tags so setuptools-scm derives the real (13.x)
69+
# package version; a shallow checkout yields 0.1.dev1, which trips
70+
# cuda.core's "cuda.bindings 12.x or 13.x must be installed" guard.
71+
fetch-depth: 0
72+
73+
- name: Setup pixi
74+
# Pinned to a commit SHA; install logic lives in the action and is
75+
# auditable/pinned (vs. a curl|bash of an unverified installer).
76+
uses: prefix-dev/setup-pixi@5185adfbffb4bd703da3010310260805d89ebb11 # v0.9.6
77+
with:
78+
pixi-version: ${{ env.PIXI_VERSION }}
79+
run-install: false
80+
81+
- name: Source-build + import + cython-placement smoke
82+
env:
83+
CUDA_ENV: ${{ inputs.cuda-env || 'cu13' }}
84+
run: |
85+
# pathfinder: pure-Python, no GPU.
86+
pixi run -e "${CUDA_ENV}" test-pathfinder
87+
88+
# bindings + core: force the source build (catches nvrtc/driver
89+
# compile errors like #2182) and import them (catches ABI mismatches).
90+
pixi run --manifest-path cuda_bindings -e "${CUDA_ENV}" \
91+
python -c "import cuda.bindings.driver, cuda.bindings.nvrtc, cuda.bindings.runtime; print('bindings import OK')"
92+
pixi run --manifest-path cuda_core -e "${CUDA_ENV}" \
93+
python -c "import cuda.core; print('core import OK')"
94+
95+
# cython test extensions: build them and confirm each .so landed next
96+
# to its .pyx in tests/cython (catches the placement regression #2180).
97+
pixi run --manifest-path cuda_bindings -e "${CUDA_ENV}" build-cython-tests
98+
pixi run --manifest-path cuda_core -e "${CUDA_ENV}" build-cython-tests
99+
for d in cuda_bindings/tests/cython cuda_core/tests/cython; do
100+
if ! compgen -G "${d}/*.cpython-*.so" > /dev/null; then
101+
echo "::error::no compiled cython test .so in ${d} (placement regression)"
102+
exit 1
103+
fi
104+
done
105+
echo "cython test extensions placed correctly"
106+
107+
# ── Nightly: full `pixi run test` on a GPU runner ──
108+
full-test:
109+
name: "pixi run test (${{ inputs.cuda-env || 'cu13' }}, linux-64, GPU)"
110+
if: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && github.repository_owner == 'nvidia' }}
111+
runs-on: "linux-amd64-gpu-l4-latest-1" # same label scheme as test-wheel-linux.yml
112+
timeout-minutes: 90
113+
container:
114+
options: -u root --security-opt seccomp=unconfined --shm-size 16g
115+
image: ubuntu:22.04
116+
steps:
117+
- name: Ensure GPU is working
118+
run: nvidia-smi
119+
120+
- name: Install system packages
121+
run: |
122+
apt-get update
123+
# ca-certificates + git for checkout; libgl1/libegl1 for pyglet
124+
# (pulled in by the test env). pixi itself is installed by setup-pixi.
125+
apt-get install -y --no-install-recommends \
126+
ca-certificates git libgl1 libegl1
127+
128+
- name: Checkout ${{ github.event.repository.name }}
129+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
130+
with:
131+
# Full history + tags so setuptools-scm derives the real (13.x)
132+
# package version; a shallow checkout yields 0.1.dev1, which trips
133+
# cuda.core's "cuda.bindings 12.x or 13.x must be installed" guard.
134+
fetch-depth: 0
135+
136+
- name: Setup proxy cache
137+
uses: nv-gha-runners/setup-proxy-cache@main
138+
continue-on-error: true
139+
140+
- name: Setup pixi
141+
# Pinned to a commit SHA; install logic lives in the action and is
142+
# auditable/pinned (vs. a curl|bash of an unverified installer).
143+
uses: prefix-dev/setup-pixi@5185adfbffb4bd703da3010310260805d89ebb11 # v0.9.6
144+
with:
145+
pixi-version: ${{ env.PIXI_VERSION }}
146+
run-install: false
147+
148+
- name: pixi run test
149+
run: pixi run -e "${{ inputs.cuda-env || 'cu13' }}" test

0 commit comments

Comments
 (0)