@@ -6,9 +6,20 @@ permissions:
66on :
77 release :
88 types : [published]
9+ push :
10+ branches : [main]
11+ paths :
12+ - " buildscripts/cibuildwheel/**"
13+ - " buildscripts/modal/**"
14+ - " .github/workflows/build-upload-wheels.yml"
15+ - " src/**"
16+ - setup.py
17+ - MANIFEST.in
18+ - pyproject.toml
919 pull_request :
1020 paths :
1121 - " buildscripts/cibuildwheel/**"
22+ - " buildscripts/modal/**"
1223 - " .github/workflows/build-upload-wheels.yml"
1324 - " src/**"
1425 - setup.py
@@ -110,9 +121,61 @@ jobs:
110121 OMP_TARGET_OFFLOAD=mandatory TEST_DEVICE=host RUN_TARGET=1 \
111122 python -m numba.runtests -v -- numba.openmp.tests.test_openmp.TestOpenmpTarget
112123
124+ # Test Linux wheels on a real NVIDIA GPU. Fork PRs run after merging to main,
125+ # where Modal credentials are available to trusted code.
126+ test-modal-gpu :
127+ needs : build-wheels
128+ if : >-
129+ github.event_name != 'pull_request' ||
130+ github.event.pull_request.head.repo.full_name == github.repository
131+ runs-on : ubuntu-latest
132+ concurrency :
133+ group : modal-gpu-${{ github.workflow }}-${{ github.ref }}
134+ cancel-in-progress : true
135+ env :
136+ MODAL_TOKEN_ID : ${{ secrets.MODAL_TOKEN_ID }}
137+ MODAL_TOKEN_SECRET : ${{ secrets.MODAL_TOKEN_SECRET }}
138+ steps :
139+ - uses : actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
140+
141+ - name : Download Linux wheels
142+ uses : actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0
143+ with :
144+ pattern : cibw-wheels-ubuntu-latest-*
145+ path : dist
146+ merge-multiple : true
147+
148+ - name : Setup Python
149+ uses : actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
150+ with :
151+ python-version : " 3.12"
152+
153+ - name : Validate Modal credentials
154+ shell : bash
155+ run : |
156+ if [[ -z "$MODAL_TOKEN_ID" || -z "$MODAL_TOKEN_SECRET" ]]; then
157+ echo "::error::MODAL_TOKEN_ID and MODAL_TOKEN_SECRET must be configured"
158+ exit 1
159+ fi
160+
161+ - name : Run GPU tests on Modal
162+ run : |
163+ python -m pip install modal==1.5.3
164+ set +e
165+ timeout --signal=TERM --kill-after=30s 20m \
166+ modal run --timestamps buildscripts/modal/test_gpu.py
167+ modal_status=$?
168+ set -e
169+
170+ if [[ $modal_status -eq 124 ]]; then
171+ echo "::error::Modal GPU tests exceeded the 20-minute timeout"
172+ exit 1
173+ fi
174+ exit "$modal_status"
175+
113176 # Only on pre-release: Publish to TestPyPI for testing.
114177 publish-testpypi :
115- needs : [build-wheels, test-wheels, build-sdist]
178+ needs : [build-wheels, test-wheels, test-modal-gpu, build-sdist]
116179 if : github.event.release.prerelease
117180 runs-on : ubuntu-latest
118181 environment : testpypi
@@ -133,7 +196,7 @@ jobs:
133196
134197 # Only on full release: Publish to production PyPI.
135198 publish-pypi :
136- needs : [build-wheels, test-wheels, build-sdist]
199+ needs : [build-wheels, test-wheels, test-modal-gpu, build-sdist]
137200 if : github.event_name == 'release' && !github.event.release.prerelease
138201 runs-on : ubuntu-latest
139202 environment : pypi
0 commit comments