1- # SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
1+ # SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
22#
33# SPDX-License-Identifier: Apache-2.0
44
3333 required : false
3434 default : false
3535 type : boolean
36+ deploy-docs :
37+ description : " Deploy generated docs to GitHub Pages or preview branches"
38+ required : false
39+ default : true
40+ type : boolean
41+ docs-branch :
42+ description : " Branch that receives deployed docs"
43+ required : false
44+ default : " gh-pages"
45+ type : string
3646
3747jobs :
3848 build :
@@ -45,14 +55,21 @@ jobs:
4555 shell : bash -el {0}
4656 steps :
4757 - name : Checkout ${{ github.event.repository.name }}
48- uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 .0.2
58+ uses : actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 .0.0
4959 with :
50- fetch-depth : 0
60+ fetch-depth : 1
5161 ref : ${{ inputs.git-tag }}
5262
5363 - name : Read build CTK version
5464 run : |
55- BUILD_CTK_VER=$(yq '.cuda.build.version' ci/versions.yml)
65+ if [[ -f ci/versions.yml ]]; then
66+ BUILD_CTK_VER=$(yq '.cuda.build.version' ci/versions.yml)
67+ elif [[ -f ci/versions.json ]]; then
68+ BUILD_CTK_VER=$(jq -r '.cuda.build.version' ci/versions.json)
69+ else
70+ echo "error: cannot find ci/versions.yml or ci/versions.json" >&2
71+ exit 1
72+ fi
5673 if [[ ! "${BUILD_CTK_VER}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
5774 echo "error: derived CTK build version ${BUILD_CTK_VER} does not match MAJOR.MINOR.MICRO" >&2
5875 exit 1
@@ -91,15 +108,18 @@ jobs:
91108
92109 if [[ ${{ inputs.is-release }} == "true" ]]; then
93110 FILE_HASH="*"
94- COMMIT_HASH="${{ inputs.git-tag }}"
111+ DOCS_GITHUB_REF="${{ inputs.git-tag }}"
112+ if [[ -z "${DOCS_GITHUB_REF}" ]]; then
113+ DOCS_GITHUB_REF="${GITHUB_REF_NAME}"
114+ fi
95115 else
96116 FILE_HASH="${{ github.sha }}"
97- COMMIT_HASH ="${{ github.sha }}"
117+ DOCS_GITHUB_REF ="${{ github.sha }}"
98118 fi
99119
100120 # make outputs from the previous job as env vars
101121 CUDA_CORE_ARTIFACT_BASENAME="cuda-core-python${PYTHON_VERSION_FORMATTED}-linux-64"
102- echo "COMMIT_HASH =${COMMIT_HASH }" >> $GITHUB_ENV
122+ echo "CUDA_PYTHON_DOCS_GITHUB_REF =${DOCS_GITHUB_REF }" >> $GITHUB_ENV
103123 echo "CUDA_CORE_ARTIFACT_BASENAME=${CUDA_CORE_ARTIFACT_BASENAME}" >> $GITHUB_ENV
104124 echo "CUDA_CORE_ARTIFACT_NAME=${CUDA_CORE_ARTIFACT_BASENAME}-${FILE_HASH}" >> $GITHUB_ENV
105125 echo "CUDA_CORE_ARTIFACTS_DIR=$(realpath "$REPO_DIR/cuda_core/dist")" >> $GITHUB_ENV
@@ -192,7 +212,9 @@ jobs:
192212 pip install *.whl
193213 popd
194214
195- pip install cuda_python*.whl
215+ # Subpackages are already installed from CI artifacts above.
216+ # --no-deps avoids re-resolving cuda-core from PyPI during tag releases.
217+ pip install --no-deps cuda_python*.whl
196218
197219 # This step sets the PR_NUMBER/BUILD_LATEST/BUILD_PREVIEW env vars.
198220 - name : Get PR number
@@ -242,28 +264,96 @@ jobs:
242264 fi
243265 mv ${COMPONENT}/docs/build/html/* artifacts/docs/${TARGET}
244266
245- # TODO: Consider removing this step?
246- - name : Upload doc artifacts
267+ - name : Write rendered docs file list
268+ if : ${{ !inputs.is-release && github.ref_name != 'main' && !startsWith(github.ref_name, 'release/') }}
269+ run : |
270+ find "${GITHUB_WORKSPACE}/artifacts/docs" -type f -name '*.html' ! -path '*/_static/*' \
271+ | LC_ALL=C sort > lychee-rendered-html-files.txt
272+ if [[ ! -s lychee-rendered-html-files.txt ]]; then
273+ echo "error: no rendered HTML pages found for lychee" >&2
274+ exit 1
275+ fi
276+ wc -l lychee-rendered-html-files.txt
277+
278+ - name : Restore lychee cache
279+ if : ${{ !inputs.is-release && github.ref_name != 'main' && !startsWith(github.ref_name, 'release/') }}
280+ id : restore-lychee-cache
281+ uses : actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
282+ with :
283+ path : .lycheecache
284+ key : docs-rendered-lychee-${{ env.PR_NUMBER }}-${{ github.sha }}
285+ restore-keys : |
286+ docs-rendered-lychee-${{ env.PR_NUMBER }}-
287+
288+ - name : Check rendered docs links
289+ if : ${{ !inputs.is-release && github.ref_name != 'main' && !startsWith(github.ref_name, 'release/') }}
290+ uses : lycheeverse/lychee-action@6da1d14f3a43098a294b7696d93d938aa8d20fc0 # unreleased: supports v0.24.x archive layout
291+ with :
292+ # PR-preview canonical URLs are checked by the preview deployment workflow.
293+ # The cuda-bindings #id links are docutils "problematic" anchors from generated API docs.
294+ # TODO: Remove this exclusion after cybind stops emitting those problematic anchors.
295+ # Preferred Networks rejects hosted-runner GETs, but the URL is browser reachable.
296+ args : >-
297+ --files-from ${{ github.workspace }}/lychee-rendered-html-files.txt
298+ --include-fragments=full
299+ --cache
300+ --max-cache-age 1d
301+ --max-concurrency 16
302+ --host-concurrency 2
303+ --host-request-interval 250ms
304+ --max-retries 3
305+ --retry-wait-time 5
306+ --timeout 30
307+ --no-progress
308+ --exclude '^https://nvidia\.github\.io/cuda-python/pr-preview/pr-[0-9]+/'
309+ --exclude '^file://.*/cuda-bindings/latest/module/(driver|runtime)\.html#id[0-9]+$'
310+ --exclude '^https://www\.preferred\.jp/en/?$'
311+ fail : true
312+ failIfEmpty : true
313+ format : markdown
314+ jobSummary : false
315+ lycheeVersion : v0.24.2
316+ output : lychee-rendered-html.md
317+ token : ${{ github.token }}
318+
319+ - name : Save lychee cache
320+ if : ${{ always() && !inputs.is-release && github.ref_name != 'main' && !startsWith(github.ref_name, 'release/') && steps.restore-lychee-cache.outputs.cache-hit != 'true' && steps.restore-lychee-cache.outputs.cache-primary-key != '' }}
321+ uses : actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
322+ with :
323+ path : .lycheecache
324+ key : ${{ steps.restore-lychee-cache.outputs.cache-primary-key }}
325+
326+ - name : Upload docs GitHub Pages artifact
327+ if : ${{ inputs.deploy-docs }}
247328 uses : actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
248329 with :
249330 path : artifacts/
250331 retention-days : 3
251332
333+ - name : Upload dry-run docs artifact
334+ if : ${{ !inputs.deploy-docs || (inputs.is-release && inputs.docs-branch != 'gh-pages') }}
335+ uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
336+ with :
337+ name : release-docs-dry-run-${{ inputs.component }}-${{ inputs.git-tag }}
338+ path : artifacts/docs/
339+ retention-days : 3
340+
252341 - name : Deploy or clean up doc preview
253- if : ${{ !inputs.is-release }}
342+ if : ${{ inputs.deploy-docs && !inputs.is-release }}
254343 uses : ./.github/actions/doc_preview
255344 with :
256345 source-folder : ${{ (github.ref_name != 'main' && 'artifacts/docs') ||
257346 ' artifacts/empty_docs' }}
258347 pr-number : ${{ env.PR_NUMBER }}
259348
260349 - name : Deploy doc update
261- if : ${{ github.ref_name == 'main' || inputs.is-release }}
350+ if : ${{ inputs.deploy-docs && ( github.ref_name == 'main' || inputs.is-release) }}
262351 uses : JamesIves/github-pages-deploy-action@d92aa235d04922e8f08b40ce78cc5442fcfbfa2f # v4.8.0
263352 with :
264353 git-config-name : cuda-python-bot
265354 git-config-email : cuda-python-bot@users.noreply.github.com
355+ branch : ${{ inputs.docs-branch }}
266356 folder : artifacts/docs/
267357 target-folder : docs/
268- commit-message : " Deploy ${{ (inputs.is-release && 'release') || 'latest' }} docs: ${{ env.COMMIT_HASH }}"
358+ commit-message : " Deploy ${{ (inputs.is-release && 'release') || 'latest' }} docs: ${{ env.CUDA_PYTHON_DOCS_GITHUB_REF }}"
269359 clean : false
0 commit comments