diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index baee1975..5c7966cc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -210,6 +210,8 @@ jobs: package: name: native distributions + # Qualify packages once, on the same vetted source as the GPU checks. + if: github.event_name == 'push' && github.repository == 'NVIDIA/cuPhoton' uses: ./.github/workflows/wheels.yml conda: @@ -217,7 +219,7 @@ jobs: uses: ./.github/workflows/conda.yml ci-required: - # PR checks do not satisfy the merge gate before GPU qualification. + # PR checks do not satisfy the merge gate before package and GPU qualification. name: ${{ github.event_name == 'pull_request' && 'ci-pr-checks' || 'ci-required' }} needs: [lint, test-cpu, test-gpu, package, conda] if: ${{ always() }} @@ -229,15 +231,17 @@ jobs: LINT_RESULT: ${{ needs.lint.result }} CPU_RESULT: ${{ needs.test-cpu.result }} GPU_RESULT: ${{ needs.test-gpu.result }} - REQUIRE_GPU: ${{ github.event_name == 'push' && github.repository == 'NVIDIA/cuPhoton' }} + REQUIRE_FULL_CI: ${{ github.event_name == 'push' && github.repository == 'NVIDIA/cuPhoton' }} PACKAGE_RESULT: ${{ needs.package.result }} CONDA_RESULT: ${{ needs.conda.result }} run: | - for result in "${LINT_RESULT}" "${CPU_RESULT}" "${PACKAGE_RESULT}" "${CONDA_RESULT}"; do + for result in "${LINT_RESULT}" "${CPU_RESULT}" "${CONDA_RESULT}"; do test "${result}" = success || exit 1 done - if [ "${REQUIRE_GPU}" = true ]; then + if [ "${REQUIRE_FULL_CI}" = true ]; then test "${GPU_RESULT}" = success || exit 1 + test "${PACKAGE_RESULT}" = success || exit 1 else test "${GPU_RESULT}" = skipped || exit 1 + test "${PACKAGE_RESULT}" = skipped || exit 1 fi diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 2513c329..32f08929 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -89,23 +89,27 @@ jobs: if-no-files-found: error install: - name: installed wheel / py${{ matrix.python.version }} / ${{ matrix.platform.arch }} + name: installed wheel and runtimes / py${{ matrix.python.version }} / ${{ matrix.platform.arch }} needs: wheels strategy: fail-fast: false matrix: python: - version: "3.12" + dragon: true image: public.ecr.aws/docker/library/python:3.12-slim-bookworm@sha256:392307d22300de8b5986851a12d9176dfc0fc073e65bf6523ebd7dcbeb23564e - version: "3.13" + dragon: true image: public.ecr.aws/docker/library/python:3.13-slim-bookworm@sha256:2325bb286ec344af3e5898cc224b5844e2707ac6e26b1632516fd3edc84a5e26 + # Dragon 0.14.2 has no Python 3.14 wheel or source distribution. - version: "3.14" + dragon: false image: public.ecr.aws/docker/library/python:3.14-slim-bookworm@sha256:82bc3c539b8813ada9d68c63b40158fa002f7f33de9bf3312a3dfdc0620dff56 platform: - {runner: ubuntu-24.04, arch: x86_64} - {runner: ubuntu-24.04-arm, arch: aarch64} runs-on: ${{ matrix.platform.runner }} - timeout-minutes: 20 + timeout-minutes: 45 steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: @@ -115,12 +119,26 @@ jobs: with: name: cuphoton-wheels-${{ matrix.platform.arch }} path: wheelhouse + - name: Pull the pinned Python image + timeout-minutes: 8 + env: + PYTHON_IMAGE: ${{ matrix.python.image }} + run: | + # Retry image delivery only; installation and test failures are final. + for delay in 0 15 30; do + sleep "$delay" + if timeout --kill-after=10s 120s docker pull "$PYTHON_IMAGE"; then + exit 0 + fi + done + echo "Unable to pull the pinned Python image after three attempts" >&2 + exit 1 - name: Install without a compiler, toolkit, or system CFITSIO env: PYTHON_VERSION: ${{ matrix.python.version }} PYTHON_IMAGE: ${{ matrix.python.image }} run: | - docker run --rm \ + docker run --pull=never --rm \ -e WHEEL_ABI="cp${PYTHON_VERSION/./}" \ -v "$PWD/wheelhouse:/wheels:ro" \ -v "$PWD/scripts/wheels:/checks:ro" \ @@ -135,37 +153,6 @@ jobs: python -I /checks/test_installed.py --mode native ' - runtimes: - name: installed runtimes / py${{ matrix.python.version }} / ${{ matrix.platform.arch }} - needs: wheels - strategy: - fail-fast: false - matrix: - python: - - version: "3.12" - dragon: true - image: public.ecr.aws/docker/library/python:3.12-slim-bookworm@sha256:392307d22300de8b5986851a12d9176dfc0fc073e65bf6523ebd7dcbeb23564e - - version: "3.13" - dragon: true - image: public.ecr.aws/docker/library/python:3.13-slim-bookworm@sha256:2325bb286ec344af3e5898cc224b5844e2707ac6e26b1632516fd3edc84a5e26 - # Dragon 0.14.2 has no Python 3.14 wheel or source distribution. - - version: "3.14" - dragon: false - image: public.ecr.aws/docker/library/python:3.14-slim-bookworm@sha256:82bc3c539b8813ada9d68c63b40158fa002f7f33de9bf3312a3dfdc0620dff56 - platform: - - {runner: ubuntu-24.04, arch: x86_64} - - {runner: ubuntu-24.04-arm, arch: aarch64} - runs-on: ${{ matrix.platform.runner }} - timeout-minutes: 25 - steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - with: - persist-credentials: false - ref: ${{ inputs.source-ref || github.sha }} - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: cuphoton-wheels-${{ matrix.platform.arch }} - path: wheelhouse - name: Exercise installed cuTile imports and distributed CPU runtimes env: PYTHON_VERSION: ${{ matrix.python.version }} @@ -173,7 +160,7 @@ jobs: WITH_DRAGON: ${{ matrix.python.dragon }} run: | mkdir -p stack-reports - docker run --rm --shm-size=2g \ + docker run --pull=never --rm --shm-size=2g \ -e WHEEL_ABI="cp${PYTHON_VERSION/./}" \ -e WITH_DRAGON \ -e OMPI_ALLOW_RUN_AS_ROOT=1 \ @@ -223,7 +210,7 @@ jobs: if-no-files-found: error distributions: - needs: [sdist, wheels, install, runtimes] + needs: [sdist, wheels, install] runs-on: ubuntu-24.04 timeout-minutes: 10 steps: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 57767921..1e597343 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -106,10 +106,11 @@ Use `make format` for Python fixes and `make ci-lint` for the complete checks. Validation logs should be clean. If warnings are expected, describe them in the pull request. -### GPU CI +### Package and GPU CI -Pull requests first run CPU and package checks on GitHub-hosted runners. -GPU CI starts when `copy-pr-bot` copies a vetted revision to +Pull requests first run lint, CPU, and conda checks on GitHub-hosted runners. +Native wheel builds, installed-wheel/runtime checks, and GPU CI start when +`copy-pr-bot` copies a vetted revision to `pull-request/` in this repository. Ready PRs from verified NVIDIA contributors with signed commits sync automatically. Draft PRs need an explicit maintainer trigger; each new external contribution revision needs @@ -123,7 +124,12 @@ not qualify new changes. The required `ci-required` check combines CPU, package, and GPU results for that revision. The initial `ci-pr-checks` result does not satisfy the merge -gate. Pushes to `main` and `0.1.x` also run the GPU checks. +gate. Pushes to `main` and `0.1.x` also run the full package and GPU checks. + +Installed-wheel and runtime checks cover Python 3.12–3.14 on x86-64 and +arm64. Each matrix job pulls its pinned Python image once and runs both +checks in separate fresh containers. Image pulls have bounded retries; +installation and test failures fail the job without retrying. The GPU job uses one L40G with Python 3.12 and the locked CUDA 13 dependencies. It checks CuPy/PyTorch execution, runs six xFit GPU parity cases, and runs