Skip to content

Commit 03277fa

Browse files
committed
Merge remote-tracking branch 'upstream/main' into annotation-typing
2 parents 0d06b66 + 1cd41ea commit 03277fa

378 files changed

Lines changed: 38239 additions & 11069 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
name: Check documentation links
6+
description: Check authored or rendered documentation with shared nightly caches and bounded retries
7+
8+
inputs:
9+
kind:
10+
description: "Input kind: authored or rendered"
11+
required: true
12+
refresh-cache:
13+
description: Check links afresh and publish a new cache baseline
14+
default: "false"
15+
failure-policy:
16+
description: "check allows up to 10 rate-limited URLs; cache-warm warns on all link failures"
17+
default: check
18+
19+
# Callers provide Python 3.10+ on PATH; the helpers use only its standard library.
20+
runs:
21+
using: composite
22+
steps:
23+
- name: Prepare link-check inputs and cache policy
24+
id: inputs
25+
shell: bash --noprofile --norc -euo pipefail {0}
26+
env:
27+
KIND: ${{ inputs.kind }}
28+
LYCHEE_VERSION: v0.24.2 # Must match the pinned rev in .pre-commit-config.yaml
29+
POLICY_HASH: ${{ hashFiles('lychee.toml', '.github/actions/check-doc-links/action.yml', 'ci/tools/prepare_lychee_inputs.py', 'ci/tools/retry_lychee.py') }}
30+
# The first pass and all retries use the same inputs and cache policy.
31+
LYCHEE_ARGS: >-
32+
--files-from "${{ github.workspace }}/lychee-${{ inputs.kind }}-files.txt"
33+
${{ inputs.kind == 'rendered' && '--include-fragments=full' || '' }}
34+
--cache
35+
--max-cache-age 1d
36+
--max-concurrency 16
37+
--host-concurrency 2
38+
--host-request-interval 250ms
39+
--max-retries 3
40+
--retry-wait-time 5
41+
--timeout 30
42+
--no-progress
43+
--config "${{ github.workspace }}/lychee.toml"
44+
run: |
45+
python "${GITHUB_WORKSPACE}/ci/tools/prepare_lychee_inputs.py" "${KIND}" \
46+
--output "${GITHUB_WORKSPACE}/lychee-${KIND}-files.txt"
47+
# Keep authored checks separate from rendered checks, which also
48+
# validate fragments. Both callers must use the same cache paths.
49+
mkdir -p "${RUNNER_TEMP}/lychee-${KIND}"
50+
prefix="lychee-v1-${LYCHEE_VERSION}-${KIND}-${POLICY_HASH}-baseline-"
51+
echo "prefix=${prefix}" >> "${GITHUB_OUTPUT}"
52+
echo "key=${prefix}${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "${GITHUB_OUTPUT}"
53+
echo "version=${LYCHEE_VERSION}" >> "${GITHUB_OUTPUT}"
54+
echo "args=${LYCHEE_ARGS}" >> "${GITHUB_OUTPUT}"
55+
56+
- name: Restore successful checks from the nightly baseline
57+
if: ${{ inputs.refresh-cache != 'true' }}
58+
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
59+
with:
60+
path: ${{ runner.temp }}/lychee-${{ inputs.kind }}/.lycheecache
61+
key: ${{ steps.inputs.outputs.key }}
62+
restore-keys: ${{ steps.inputs.outputs.prefix }}
63+
64+
- name: Check documentation links
65+
id: lychee
66+
uses: lycheeverse/lychee-action@6da1d14f3a43098a294b7696d93d938aa8d20fc0 # supports v0.24.x archive layout
67+
with:
68+
args: ${{ steps.inputs.outputs.args }}
69+
# The next step owns bounded retries and the final success gate.
70+
fail: false
71+
# The action's empty-report guard only understands Markdown.
72+
# Our helper validates the JSON report and rejects zero checked links.
73+
failIfEmpty: false
74+
format: json
75+
jobSummary: false
76+
lycheeVersion: ${{ steps.inputs.outputs.version }}
77+
workingDirectory: ${{ runner.temp }}/lychee-${{ inputs.kind }}
78+
output: ${{ github.workspace }}/lychee-${{ inputs.kind }}.json
79+
token: ${{ github.token }}
80+
81+
- name: Retry transient link failures using cached successful checks
82+
if: ${{ steps.lychee.outcome == 'success' }}
83+
shell: bash --noprofile --norc -euo pipefail {0}
84+
working-directory: ${{ runner.temp }}/lychee-${{ inputs.kind }}
85+
env:
86+
EXIT_CODE: ${{ steps.lychee.outputs.exit_code }}
87+
REPORT: ${{ github.workspace }}/lychee-${{ inputs.kind }}.json
88+
LYCHEE_ARGS: ${{ steps.inputs.outputs.args }}
89+
FAILURE_POLICY: ${{ inputs.failure-policy }}
90+
GITHUB_TOKEN: ${{ github.token }}
91+
run: |
92+
python "${GITHUB_WORKSPACE}/ci/tools/retry_lychee.py" \
93+
--initial-exit-code "${EXIT_CODE}" --report "${REPORT}" \
94+
--max-attempts 3 --policy "${FAILURE_POLICY}"
95+
96+
- name: Publish fresh successful checks
97+
# Manual branch tests publish isolated branch caches. Nightly callers
98+
# on the default branch publish the baseline that all PRs can restore.
99+
if: ${{ always() && inputs.refresh-cache == 'true' && steps.inputs.outputs.key != '' }}
100+
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
101+
with:
102+
path: ${{ runner.temp }}/lychee-${{ inputs.kind }}/.lycheecache
103+
key: ${{ steps.inputs.outputs.key }}
104+
105+
- name: Upload link-check report
106+
if: ${{ always() }}
107+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
108+
with:
109+
name: lychee-${{ inputs.kind }}-${{ github.run_id }}-${{ github.run_attempt }}
110+
path: |
111+
${{ github.workspace }}/lychee-${{ inputs.kind }}*.json
112+
${{ github.workspace }}/lychee-${{ inputs.kind }}*.md
113+
if-no-files-found: ignore
114+
retention-days: 7
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
name: Download artifact (with retry)
6+
7+
description: >-
8+
Wrapper around actions/download-artifact that retries once after a short
9+
delay when the first attempt fails. Designed to absorb transient
10+
infrastructure flakes such as "other side closed" without failing the job.
11+
12+
inputs:
13+
name:
14+
description: "Name of the artifact to download"
15+
required: true
16+
path:
17+
description: "Destination path for the downloaded artifact"
18+
required: true
19+
run-id:
20+
description: >-
21+
The run ID of the workflow run that uploaded the artifact. Only used
22+
together with github-token; leave empty to download from the current run.
23+
required: false
24+
default: ""
25+
github-token:
26+
description: >-
27+
Token used to download from another run or repository. Leave empty (the
28+
default) to download from the current run, which uses
29+
actions/download-artifact's internal download path. That path is not the
30+
same as the one used when a token is given, so do not default this to
31+
github.token.
32+
required: false
33+
default: ""
34+
retry-delay-seconds:
35+
description: "Seconds to wait between the first failure and the retry"
36+
required: false
37+
default: "15"
38+
39+
runs:
40+
using: composite
41+
steps:
42+
- name: Download artifact (attempt 1)
43+
id: attempt1
44+
continue-on-error: true
45+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
46+
with:
47+
name: ${{ inputs.name }}
48+
path: ${{ inputs.path }}
49+
run-id: ${{ inputs.run-id }}
50+
github-token: ${{ inputs.github-token }}
51+
52+
- name: Wait before retry
53+
if: ${{ steps.attempt1.outcome == 'failure' }}
54+
shell: bash --noprofile --norc -euo pipefail {0}
55+
env:
56+
# Pass through env instead of interpolating the input into the shell
57+
# script, so a non-numeric value cannot inject commands.
58+
RETRY_DELAY_SECONDS: ${{ inputs.retry-delay-seconds }}
59+
run: |
60+
echo "::warning::Artifact download failed (attempt 1); retrying in ${RETRY_DELAY_SECONDS}s"
61+
sleep "$RETRY_DELAY_SECONDS"
62+
63+
- name: Download artifact (attempt 2)
64+
if: ${{ steps.attempt1.outcome == 'failure' }}
65+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
66+
with:
67+
name: ${{ inputs.name }}
68+
path: ${{ inputs.path }}
69+
run-id: ${{ inputs.run-id }}
70+
github-token: ${{ inputs.github-token }}

‎.github/dependabot.yml‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@ updates:
4848

4949
labels: [CI/CD, dependencies]
5050

51+
# CCCL submodule on main.
52+
- package-ecosystem: gitsubmodule
53+
directory: /
54+
schedule:
55+
interval: "monthly"
56+
time: "09:00"
57+
timezone: "America/Los_Angeles"
58+
open-pull-requests-limit: 1
59+
5160
# GitHub Actions updates targeting the 12.9.x branch
5261
- package-ecosystem: github-actions
5362
directory: /

‎.github/labeler.yml‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@
77

88
cuda.bindings:
99
- changed-files:
10-
- any-glob-to-any-file: 'cuda_bindings/**'
10+
- any-glob-to-any-file:
11+
- 'cuda_bindings/**'
12+
- 'samples/cuda_bindings/**'
1113

1214
cuda.core:
1315
- changed-files:
14-
- any-glob-to-any-file: 'cuda_core/**'
16+
- any-glob-to-any-file:
17+
- 'cuda_core/**'
18+
- 'samples/cuda_core/**'
1519

1620
cuda.pathfinder:
1721
- changed-files:

‎.github/workflows/bandit.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
2727

2828
- name: Install uv
29-
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
29+
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
3030
with:
3131
enable-cache: false
3232

@@ -45,6 +45,6 @@ jobs:
4545
with:
4646
args: "check --select S --ignore ${{ steps.ignore-codes.outputs.codes }} --output-format sarif --output-file results.sarif"
4747
- name: Upload SARIF file
48-
uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
48+
uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
4949
with:
5050
sarif_file: results.sarif

‎.github/workflows/build-docs.yml‎

Lines changed: 19 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ jobs:
133133
echo "CUDA_BINDINGS_ARTIFACTS_DIR=$(realpath "$REPO_DIR/cuda_bindings/dist")" >> $GITHUB_ENV
134134
135135
- name: Download cuda-python build artifacts
136-
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
136+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
137137
with:
138138
name: cuda-python-wheel
139139
path: .
@@ -146,7 +146,7 @@ jobs:
146146
ls -lahR .
147147
148148
- name: Download cuda-pathfinder build artifacts
149-
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
149+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
150150
with:
151151
name: cuda-pathfinder-wheel
152152
path: ./cuda_pathfinder
@@ -160,14 +160,14 @@ jobs:
160160
161161
- name: Download cuda.bindings build artifacts
162162
if: ${{ !inputs.is-release }}
163-
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
163+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
164164
with:
165165
name: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }}
166166
path: ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }}
167167

168168
- name: Download cuda.bindings build artifacts
169169
if: ${{ inputs.is-release }}
170-
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
170+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
171171
with:
172172
pattern: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }}
173173
merge-multiple: true
@@ -182,14 +182,14 @@ jobs:
182182
183183
- name: Download cuda.core build artifacts
184184
if: ${{ !inputs.is-release }}
185-
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
185+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
186186
with:
187187
name: ${{ env.CUDA_CORE_ARTIFACT_NAME }}
188188
path: ${{ env.CUDA_CORE_ARTIFACTS_DIR }}
189189

190190
- name: Download cuda.core build artifacts
191191
if: ${{ inputs.is-release }}
192-
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
192+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
193193
with:
194194
pattern: ${{ env.CUDA_CORE_ARTIFACT_NAME }}
195195
merge-multiple: true
@@ -284,58 +284,21 @@ jobs:
284284
fi
285285
mv ${COMPONENT}/docs/build/html/* artifacts/docs/${TARGET}
286286
287-
- name: Write rendered docs file list
287+
# Keep link checks in the existing PR docs build, using the same revision
288+
# as its wheels. Nightly supplies shared caches for both kinds of inputs.
289+
- name: Check authored documentation links
288290
if: ${{ !inputs.is-release && startsWith(github.ref_name, 'pull-request/') }}
289-
run: |
290-
find "${GITHUB_WORKSPACE}/artifacts/docs" -type f -name '*.html' ! -path '*/_static/*' \
291-
| LC_ALL=C sort > lychee-rendered-html-files.txt
292-
if [[ ! -s lychee-rendered-html-files.txt ]]; then
293-
echo "error: no rendered HTML pages found for lychee" >&2
294-
exit 1
295-
fi
296-
wc -l lychee-rendered-html-files.txt
297-
298-
- name: Restore lychee cache
299-
if: ${{ !inputs.is-release && startsWith(github.ref_name, 'pull-request/') }}
300-
id: restore-lychee-cache
301-
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
291+
timeout-minutes: 60
292+
uses: ./.github/actions/check-doc-links
302293
with:
303-
path: .lycheecache
304-
key: docs-rendered-lychee-${{ env.PR_NUMBER }}-${{ github.sha }}
305-
restore-keys: |
306-
docs-rendered-lychee-${{ env.PR_NUMBER }}-
294+
kind: authored
307295

308-
- name: Check rendered docs links
296+
- name: Check rendered documentation links
309297
if: ${{ !inputs.is-release && startsWith(github.ref_name, 'pull-request/') }}
310-
uses: lycheeverse/lychee-action@6da1d14f3a43098a294b7696d93d938aa8d20fc0 # unreleased: supports v0.24.x archive layout
311-
with:
312-
args: >-
313-
--files-from ${{ github.workspace }}/lychee-rendered-html-files.txt
314-
--include-fragments=full
315-
--cache
316-
--max-cache-age 1d
317-
--max-concurrency 16
318-
--host-concurrency 2
319-
--host-request-interval 250ms
320-
--max-retries 3
321-
--retry-wait-time 5
322-
--timeout 30
323-
--no-progress
324-
--config ${{ github.workspace }}/lychee.toml
325-
fail: true
326-
failIfEmpty: true
327-
format: markdown
328-
jobSummary: false
329-
lycheeVersion: v0.24.2
330-
output: lychee-rendered-html.md
331-
token: ${{ github.token }}
332-
333-
- name: Save lychee cache
334-
if: ${{ always() && !inputs.is-release && startsWith(github.ref_name, 'pull-request/') && steps.restore-lychee-cache.outputs.cache-hit != 'true' && steps.restore-lychee-cache.outputs.cache-primary-key != '' }}
335-
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
298+
timeout-minutes: 60
299+
uses: ./.github/actions/check-doc-links
336300
with:
337-
path: .lycheecache
338-
key: ${{ steps.restore-lychee-cache.outputs.cache-primary-key }}
301+
kind: rendered
339302

340303
- name: Upload docs GitHub Pages artifact
341304
if: ${{ inputs.deploy-docs }}
@@ -346,7 +309,7 @@ jobs:
346309

347310
- name: Upload docs deployment payload
348311
if: ${{ inputs.deploy-docs }}
349-
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
312+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
350313
with:
351314
name: ${{ steps.deployment-metadata.outputs.deployment-artifact-name }}
352315
path: artifacts/docs/
@@ -356,7 +319,7 @@ jobs:
356319

357320
- name: Upload dry-run docs artifact
358321
if: ${{ !inputs.deploy-docs || (inputs.is-release && inputs.docs-branch != 'gh-pages') }}
359-
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
322+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
360323
with:
361324
name: release-docs-dry-run-${{ inputs.component }}-${{ inputs.git-tag }}
362325
path: artifacts/docs/
@@ -385,7 +348,7 @@ jobs:
385348
ref: ${{ inputs.git-tag }}
386349

387350
- name: Download docs deployment payload
388-
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
351+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
389352
with:
390353
name: ${{ needs.build.outputs.deployment-artifact-name }}
391354
path: artifacts/docs/

0 commit comments

Comments
 (0)