Skip to content

Commit bdb3299

Browse files
committed
ci: run documentation link checks through pre-commit
Signed-off-by: Ralf W. Grosse-Kunstleve <[email protected]>
1 parent 2b394fb commit bdb3299

16 files changed

Lines changed: 923 additions & 320 deletions

‎.github/actions/check-doc-links/action.yml‎

Lines changed: 0 additions & 114 deletions
This file was deleted.

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

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -284,21 +284,47 @@ jobs:
284284
fi
285285
mv ${COMPONENT}/docs/build/html/* artifacts/docs/${TARGET}
286286
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
287+
# Authored sources are checked by the ordinary Linux/Windows pre-commit
288+
# jobs. Generated HTML and anchors need this completed documentation build.
289+
- name: Install pre-commit for rendered link checks
290290
if: ${{ !inputs.is-release && startsWith(github.ref_name, 'pull-request/') }}
291-
timeout-minutes: 60
292-
uses: ./.github/actions/check-doc-links
291+
run: |
292+
echo "PRE_COMMIT_HOME=${RUNNER_TEMP}/pre-commit" >> "${GITHUB_ENV}"
293+
echo "LYCHEE_CACHE_DIR=${RUNNER_TEMP}/lychee-rendered" >> "${GITHUB_ENV}"
294+
python -m pip install pre-commit
295+
296+
- name: Describe the rendered link cache
297+
if: ${{ !inputs.is-release && startsWith(github.ref_name, 'pull-request/') }}
298+
id: lychee-cache
299+
run: python ci/tools/lychee_cache.py rendered --github-output "${GITHUB_OUTPUT}"
300+
301+
- name: Restore successful rendered link checks
302+
if: ${{ !inputs.is-release && startsWith(github.ref_name, 'pull-request/') }}
303+
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
293304
with:
294-
kind: authored
305+
path: ${{ steps.lychee-cache.outputs.path }}
306+
key: ${{ steps.lychee-cache.outputs.key }}
307+
restore-keys: ${{ steps.lychee-cache.outputs.prefix }}
308+
enableCrossOsArchive: true
295309

296-
- name: Check rendered documentation links
310+
- name: Check rendered documentation links through pre-commit
297311
if: ${{ !inputs.is-release && startsWith(github.ref_name, 'pull-request/') }}
298312
timeout-minutes: 60
299-
uses: ./.github/actions/check-doc-links
313+
env:
314+
GITHUB_TOKEN: ${{ github.token }}
315+
run: >-
316+
python ci/tools/run_lychee_precommit.py rendered
317+
--policy check --max-attempts 3
318+
--report "${RUNNER_TEMP}/lychee-reports/lychee-rendered.json"
319+
320+
- name: Upload rendered link-check reports
321+
if: ${{ always() && !inputs.is-release && startsWith(github.ref_name, 'pull-request/') }}
322+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
300323
with:
301-
kind: rendered
324+
name: lychee-rendered-${{ github.run_id }}-${{ github.run_attempt }}
325+
path: ${{ runner.temp }}/lychee-reports/
326+
if-no-files-found: ignore
327+
retention-days: 7
302328

303329
- name: Upload docs GitHub Pages artifact
304330
if: ${{ inputs.deploy-docs }}

‎.github/workflows/lychee.yml‎

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
#
33
# SPDX-License-Identifier: Apache-2.0
44

5-
# Build documentation nightly and warm the link cache, reporting unresolved links
6-
# as warnings. Full PR CI reuses successful checks in build-docs.yml.
7-
# Ordinary PR updates run pre-commit without Lychee and do not build docs here.
5+
# Warm authored and rendered link caches through the configured pre-commit
6+
# hooks. Ordinary PRs reuse authored results; full docs CI reuses rendered
7+
# results. Nightly starts afresh and reports unresolved links as warnings.
88

99
name: "CI: Documentation links"
1010

@@ -50,6 +50,8 @@ jobs:
5050
fail-fast: false
5151
matrix:
5252
kind: [authored, rendered]
53+
env:
54+
PYTHONUTF8: "1"
5355
steps:
5456
- name: Checkout checked revision
5557
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -62,10 +64,26 @@ jobs:
6264
submodules: ${{ matrix.kind == 'rendered' }}
6365

6466
- name: Set up Python
67+
id: python
6568
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
6669
with:
6770
python-version: "3.14"
6871

72+
- name: Set link-check cache locations
73+
run: |
74+
echo "PRE_COMMIT_HOME=${RUNNER_TEMP}/pre-commit" >> "${GITHUB_ENV}"
75+
echo "LYCHEE_CACHE_DIR=${RUNNER_TEMP}/lychee-rendered" >> "${GITHUB_ENV}"
76+
77+
- name: Restore pre-commit environments
78+
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
79+
with:
80+
path: ${{ env.PRE_COMMIT_HOME }}
81+
key: pre-commit-${{ runner.os }}-py${{ steps.python.outputs.python-version }}-${{ hashFiles('.pre-commit-config.yaml') }}
82+
restore-keys: pre-commit-${{ runner.os }}-py3.14
83+
84+
- name: Install pre-commit
85+
run: python -m pip install pre-commit
86+
6987
- name: Setup pixi
7088
if: ${{ matrix.kind == 'rendered' }}
7189
uses: ./.github/actions/setup-pixi
@@ -74,9 +92,42 @@ jobs:
7492
if: ${{ matrix.kind == 'rendered' }}
7593
run: pixi run --manifest-path cuda_core/pixi.toml -e docs docs-build-all-latest
7694

77-
- name: Check documentation links
78-
uses: ./.github/actions/check-doc-links
95+
- name: Describe the link cache
96+
id: lychee-cache
97+
run: python ci/tools/lychee_cache.py "${{ matrix.kind }}" --github-output "${GITHUB_OUTPUT}"
98+
99+
- name: Restore successful link checks
100+
# Refresh mode deliberately skips yesterday's URL results.
101+
if: ${{ !inputs.refresh-cache }}
102+
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
103+
with:
104+
path: ${{ steps.lychee-cache.outputs.path }}
105+
key: ${{ steps.lychee-cache.outputs.key }}
106+
restore-keys: ${{ steps.lychee-cache.outputs.prefix }}
107+
enableCrossOsArchive: true
108+
109+
- name: Check documentation links through pre-commit
110+
env:
111+
GITHUB_TOKEN: ${{ github.token }}
112+
run: >-
113+
python ci/tools/run_lychee_precommit.py "${{ matrix.kind }}"
114+
--policy "${{ inputs.refresh-cache && 'cache-warm' || 'check' }}"
115+
--max-attempts 3
116+
--report "${RUNNER_TEMP}/lychee-reports/lychee-${{ matrix.kind }}.json"
117+
118+
- name: Publish fresh successful link checks
119+
if: ${{ !cancelled() && inputs.refresh-cache && steps.lychee-cache.outputs.key != '' }}
120+
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
121+
with:
122+
path: ${{ steps.lychee-cache.outputs.path }}
123+
key: ${{ steps.lychee-cache.outputs.key }}
124+
enableCrossOsArchive: true
125+
126+
- name: Upload link-check reports
127+
if: ${{ always() }}
128+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
79129
with:
80-
kind: ${{ matrix.kind }}
81-
refresh-cache: ${{ inputs.refresh-cache || false }}
82-
failure-policy: ${{ inputs.refresh-cache && 'cache-warm' || 'check' }}
130+
name: lychee-${{ matrix.kind }}-${{ github.run_id }}-${{ github.run_attempt }}
131+
path: ${{ runner.temp }}/lychee-reports/
132+
if-no-files-found: ignore
133+
retention-days: 7

‎.github/workflows/pre-commit.yml‎

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ jobs:
4141
- name: Windows
4242
os: windows-latest
4343
env:
44-
# Full-CI docs builds and nightly check links. The installation reminder
45-
# is for developer machines; CI does not install a Git commit hook.
46-
SKIP: lychee,check-precommit-installed
44+
# The installation reminder is for developer machines; CI does not
45+
# install a Git commit hook. All other hooks, including Lychee, run.
46+
SKIP: check-precommit-installed
47+
PYTHONUTF8: "1"
4748
# Minor version used by setup-python and as the cache restore-key prefix.
4849
PYTHON_VERSION: "3.14"
4950
steps:
@@ -138,9 +139,53 @@ jobs:
138139
LYCHEE_SMOKE_DIR: ${{ steps.lychee-smoke.outputs.directory }}
139140
run: python ci/tools/smoke_test_lychee_precommit.py --cleanup "$LYCHEE_SMOKE_DIR"
140141

142+
- name: Describe the authored link cache
143+
id: lychee-cache
144+
run: python ci/tools/lychee_cache.py authored --github-output "${GITHUB_OUTPUT}"
145+
146+
- name: Restore successful link checks from the shared baseline
147+
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
148+
with:
149+
path: ${{ steps.lychee-cache.outputs.path }}
150+
key: ${{ steps.lychee-cache.outputs.key }}
151+
restore-keys: ${{ steps.lychee-cache.outputs.prefix }}
152+
enableCrossOsArchive: true
153+
154+
# Warm only Lychee, retaining successful checks between attempts. The
155+
# full suite below runs once: formatter changes must remain failures.
156+
# A missing baseline is supported; the first pass then checks afresh.
157+
- name: Warm the Lychee cache with up to three hook attempts
158+
env:
159+
GITHUB_TOKEN: ${{ github.token }}
160+
run: >-
161+
python ci/tools/run_lychee_precommit.py authored
162+
--policy cache-warm --max-attempts 3
163+
--report "${RUNNER_TEMP}/lychee-reports/lychee-authored.json"
164+
141165
- name: Run pre-commit
166+
env:
167+
GITHUB_TOKEN: ${{ github.token }}
142168
run: pre-commit run --all-files --show-diff-on-failure
143169

170+
- name: Save successful authored link checks from main
171+
# Nightly and main pushes supply the shared baseline. PR runs only
172+
# restore it; saving preserves timestamps and never caches failures.
173+
if: ${{ !cancelled() && runner.os == 'Linux' && github.ref_name == github.event.repository.default_branch && steps.lychee-cache.outputs.key != '' }}
174+
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
175+
with:
176+
path: ${{ steps.lychee-cache.outputs.path }}
177+
key: ${{ steps.lychee-cache.outputs.key }}
178+
enableCrossOsArchive: true
179+
180+
- name: Upload Lychee warm-up reports
181+
if: ${{ always() }}
182+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
183+
with:
184+
name: lychee-precommit-${{ runner.os }}-${{ github.run_id }}-${{ github.run_attempt }}
185+
path: ${{ runner.temp }}/lychee-reports/
186+
if-no-files-found: ignore
187+
retention-days: 7
188+
144189
- name: Save pre-commit cache
145190
# Only the default branch saves, so per-PR merge refs don't store their
146191
# own duplicate copies. !cancelled() keeps a push that fails lint from

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ __pycache__/
1111
.cython-stdlib
1212
.cython-bindings
1313
.lycheecache
14+
.lychee-rendered/
1415
.pytest_cache/
1516
.benchmarks/
1617
*.cpp

‎.pre-commit-config.yaml‎

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,18 +111,39 @@ repos:
111111
name: lychee
112112
entry: python ./ci/tools/run_lychee.py
113113
language: python
114-
additional_dependencies:
115-
- lychee-bin==0.24.2 # Must match check-doc-links/action.yml
114+
additional_dependencies: &lychee_dependencies
115+
- lychee-bin==0.24.2
116116
types: [text]
117117
require_serial: true
118118
args:
119119
- --cache
120+
- --max-cache-age=1d
120121
- --max-concurrency=4
121122
- --max-retries=3
122123
- --no-progress
123124
files: '\.(md|rst)$'
124125
exclude: ^qa/
125126

127+
# Generated HTML is checked explicitly after the documentation build.
128+
- id: lychee-rendered
129+
name: lychee (rendered documentation)
130+
entry: python ./ci/tools/run_lychee.py --rendered
131+
language: python
132+
additional_dependencies: *lychee_dependencies
133+
stages: [manual]
134+
pass_filenames: false
135+
always_run: true
136+
args:
137+
- --cache
138+
- --max-cache-age=1d
139+
- --max-concurrency=16
140+
- --host-concurrency=2
141+
- --host-request-interval=250ms
142+
- --max-retries=3
143+
- --retry-wait-time=5
144+
- --timeout=30
145+
- --no-progress
146+
126147
# Standard hooks
127148
- repo: https://github.com/pre-commit/pre-commit-hooks
128149
rev: "3e8a8703264a2f4a69428a0aa4dcb512790b2c8c" # frozen: v6.0.0

0 commit comments

Comments
 (0)