-
Notifications
You must be signed in to change notification settings - Fork 1
593 lines (509 loc) · 19.2 KB
/
ci-docs.yml
File metadata and controls
593 lines (509 loc) · 19.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
name: CI - Documentation
on:
push:
branches: [main]
paths:
- '**.md'
- '**.rs'
- 'docs/**'
- 'wiki/**'
- 'scripts/**'
- '.markdownlint.json'
- '.markdown-link-check.json'
- '.lychee.toml'
- '.vale.ini'
- '.vale/**'
- '.github/workflows/ci-docs.yml'
pull_request:
branches: [main]
paths:
- '**.md'
- '**.rs'
- 'docs/**'
- 'wiki/**'
- 'scripts/**'
- '.markdownlint.json'
- '.markdown-link-check.json'
- '.lychee.toml'
- '.vale.ini'
- '.vale/**'
- '.github/workflows/ci-docs.yml'
workflow_dispatch:
jobs:
# ============================================================================
# VALE PROSE LINT - Check documentation prose quality
# ============================================================================
# Note: Uses Vale CLI directly instead of errata-ai/vale-action to avoid
# reviewdog's dependency on GitHub's Pull Request diff API, which fails
# with HTTP 406 when PRs exceed GitHub's diff line limit (~3,000 lines).
# See: https://github.com/reviewdog/reviewdog/issues/1696
# ============================================================================
vale-lint:
name: Vale Prose Lint
runs-on: ubuntu-latest
continue-on-error: true # Advisory, not blocking initially
steps:
- uses: actions/checkout@v6
- name: Cache Vale styles
uses: actions/cache@v5
with:
path: .vale/styles
key: vale-styles-${{ hashFiles('.vale.ini') }}
restore-keys: |
vale-styles-
- name: Install Vale CLI
run: |
# Pin to specific version for reproducibility
VALE_VERSION="3.9.0"
curl -sfL "https://github.com/errata-ai/vale/releases/download/v${VALE_VERSION}/vale_${VALE_VERSION}_Linux_64-bit.tar.gz" \
| sudo tar xz -C /usr/local/bin vale
vale --version
- name: Sync Vale styles
run: vale sync
- name: Run Vale prose linter
id: vale
run: |
{
echo "## Vale Prose Lint Results"
echo ""
} >> "$GITHUB_STEP_SUMMARY"
# Check if docs/ directory exists
if [ ! -d docs/ ]; then
echo "⚠️ docs/ directory not found, skipping Vale lint" >> "$GITHUB_STEP_SUMMARY"
touch vale-output.txt
exit 0
fi
# Run vale with line output format
# Note: Vale returns 0 for suggestions/warnings, non-zero for errors/config issues
# We check output file content to determine if issues were found
set +e
vale --output=line docs/ 2>&1 | tee vale-output.txt
EXIT_CODE=$?
set -e
# Check for configuration errors (exit code >= 2)
if [ $EXIT_CODE -ge 2 ]; then
{
echo "⚠️ Vale configuration error (exit code: $EXIT_CODE)"
echo ""
echo "\`\`\`"
cat vale-output.txt
echo "\`\`\`"
} >> "$GITHUB_STEP_SUMMARY"
exit 0 # Don't fail since continue-on-error: true handles this
fi
# Check if any issues were found by examining output file content
if [ ! -s vale-output.txt ]; then
echo "✅ No prose issues found in docs/" >> "$GITHUB_STEP_SUMMARY"
else
ISSUE_COUNT=$(wc -l < vale-output.txt | tr -d ' ')
{
echo "### Issues Found: ${ISSUE_COUNT}"
echo ""
echo "These are advisory suggestions to improve prose quality."
echo ""
echo "\`\`\`"
head -100 vale-output.txt
if [ "$ISSUE_COUNT" -gt 100 ]; then
echo "... (truncated, see artifact for full report)"
fi
echo "\`\`\`"
} >> "$GITHUB_STEP_SUMMARY"
# Emit GitHub annotations from vale output (limit to 50 to avoid noise)
# Vale --output=line format: filepath:line:col:rule:message (5 colon-separated fields)
# Example: docs/guide.md:15:1:write-good.Weasel:'few' is a weasel word!
head -50 vale-output.txt | while IFS=: read -r file line col rule message; do
[ -z "$file" ] && continue
# All Vale findings in this config are advisory (suggestions/warnings)
# Map to GitHub notice level for non-blocking visibility
level="notice"
# Emit GitHub annotation
echo "::${level} file=${file},line=${line},col=${col}::[${rule}] ${message}"
done
fi
- name: Upload Vale report
uses: actions/upload-artifact@v7
if: always()
with:
name: vale-report
path: vale-output.txt
retention-days: 7
# ============================================================================
# WIKI CONSISTENCY - Validate wiki links and structure
# ============================================================================
wiki-consistency:
name: Wiki Consistency
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.12'
- name: Validate wiki consistency
run: python scripts/docs/check-wiki-consistency.py
# ============================================================================
# SCRIPT TESTS & WIKI DRY-RUN - Run all script tests and validate wiki generation
# ============================================================================
wiki-sync-dry-run:
name: Script Tests & Wiki Dry-Run
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.12'
- name: Install test dependencies
run: pip install pytest pyyaml
- name: Run script tests
run: python -m pytest scripts/tests/ -v
- name: Generate wiki (dry-run)
run: python scripts/docs/sync-wiki.py --dest wiki-test-output
- name: Validate generated wiki format
run: python scripts/docs/validate-wiki-output.py --wiki-dir wiki-test-output
markdown-lint:
name: Markdown Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
- name: Install markdownlint-cli
run: npm install -g markdownlint-cli
- name: Run markdownlint
run: markdownlint '**/*.md' --config .markdownlint.json --ignore 'target/**' --ignore 'fuzz/target/**' --ignore 'loom-tests/target/**' --ignore 'progress/**' --ignore 'PLAN.md'
# ============================================================================
# CODE FENCE SYNTAX - Detect rustdoc-style attributes in markdown
# ============================================================================
code-fence-syntax:
name: Code Fence Syntax
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Check for rustdoc-style code fence attributes
run: |
{
echo "## Code Fence Syntax Check"
echo ""
echo "Checking for rustdoc-style code fence attributes (e.g., \`\`\`rust,ignore)..."
echo ""
} >> "$GITHUB_STEP_SUMMARY"
if ./scripts/docs/check-code-fence-syntax.sh docs/ 2>&1 | tee code-fence-output.txt; then
echo "✅ No rustdoc-style code fence attributes found" >> "$GITHUB_STEP_SUMMARY"
else
{
echo "❌ Found rustdoc-style code fence attributes:"
echo ""
echo "These attributes are only valid in Rust doc comments, not markdown files."
echo "Use plain \`\`\`rust instead."
echo ""
echo "\`\`\`"
cat code-fence-output.txt
echo "\`\`\`"
} >> "$GITHUB_STEP_SUMMARY"
exit 1
fi
- name: Upload code fence report
uses: actions/upload-artifact@v7
if: always()
with:
name: code-fence-report
path: code-fence-output.txt
retention-days: 7
link-check:
name: Link Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
- name: Install markdown-link-check
run: npm install -g markdown-link-check
- name: Check markdown links (external)
run: |
find . -name "*.md" \
-not -path "./target/*" \
-not -path "./fuzz/target/*" \
-not -path "./loom-tests/target/*" \
-exec markdown-link-check --config .markdown-link-check.json {} \;
continue-on-error: true # External links may have rate limits
- name: Check local file links
run: ./scripts/docs/check-links.sh
# ============================================================================
# LYCHEE LINK CHECK - Fast link checking with caching
# ============================================================================
lychee-link-check:
name: Lychee Link Check
runs-on: ubuntu-latest
continue-on-error: true # Advisory initially, may find different issues
steps:
- uses: actions/checkout@v6
- name: Restore lychee cache
uses: actions/cache@v5
with:
path: .lycheecache
key: lychee-cache-${{ github.sha }}
restore-keys: |
lychee-cache-
- name: Run lychee link checker
uses: lycheeverse/lychee-action@v2
with:
# Check docs and top-level markdown files
args: >-
--config .lychee.toml
--cache
--no-progress
'docs/**/*.md'
'README.md'
'CHANGELOG.md'
'CONTRIBUTING.md'
'LICENSE*'
'*.md'
output: lychee-report.md
fail: false # Don't fail the workflow on broken links initially
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload lychee report
uses: actions/upload-artifact@v7
if: always()
with:
name: lychee-report
path: lychee-report.md
retention-days: 7
rustdoc-links:
name: Rustdoc Link Check
runs-on: ubuntu-latest
# Note: We intentionally don't use sccache for doc builds because:
# 1. Doc builds are fast and don't benefit much from compilation caching
# 2. sccache can cause transient CI failures when GitHub Actions cache service is unavailable
# 3. The complexity of sccache error handling outweighs any benefit for this job
steps:
- uses: actions/checkout@v6
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- name: Cache cargo registry and build
uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: docs-${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
docs-${{ runner.os }}-cargo-
- name: Check for broken intra-doc links
run: |
# Clean any stale doc artifacts that might cause issues
rm -rf target/doc
# Run with comprehensive RUSTDOCFLAGS for strict documentation validation
# All rustdoc-specific lints are enforced as errors
RUSTDOCFLAGS="\
-D warnings \
-D rustdoc::broken_intra_doc_links \
-D rustdoc::private_intra_doc_links \
-D rustdoc::invalid_codeblock_attributes \
-D rustdoc::invalid_html_tags \
-D rustdoc::bare_urls" \
cargo doc --no-deps
# ============================================================================
# RUSTDOC DEAD LINKS - Check for broken links in generated HTML
# ============================================================================
rustdoc-deadlinks:
name: Rustdoc Dead Links
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Install cargo-deadlinks
uses: ./.github/actions/install-cargo-tool
with:
tool: cargo-deadlinks
- name: Cache cargo registry and build
uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: deadlinks-${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
deadlinks-${{ runner.os }}-cargo-
- name: Build documentation
run: cargo doc --no-deps
- name: Check for dead links in rustdoc HTML
run: |
{
echo "## Rustdoc Dead Links Check"
echo ""
echo "Checking generated documentation for broken links..."
echo ""
} >> "$GITHUB_STEP_SUMMARY"
# Check for dead links (file:// links only, HTTP would be too slow)
if cargo deadlinks 2>&1 | tee deadlinks-output.txt; then
echo "✅ No dead links found in documentation" >> "$GITHUB_STEP_SUMMARY"
else
{
echo "⚠️ Dead links detected:"
echo ""
echo "\`\`\`"
head -50 deadlinks-output.txt
echo "\`\`\`"
} >> "$GITHUB_STEP_SUMMARY"
exit 1
fi
- name: Upload deadlinks report
uses: actions/upload-artifact@v7
if: always()
with:
name: deadlinks-report
path: deadlinks-output.txt
retention-days: 7
# ============================================================================
# DOC TESTS - Verify all documentation examples compile and run
# ============================================================================
doc-tests:
name: Documentation Examples
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry and build
uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: doctests-${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
doctests-${{ runner.os }}-cargo-
- name: Run documentation tests
run: |
{
echo "## Documentation Example Tests"
echo ""
echo "Compiling and running all code examples in documentation..."
echo ""
} >> "$GITHUB_STEP_SUMMARY"
if cargo test --doc 2>&1 | tee doctest-output.txt; then
# Count passed tests
PASSED=$(grep -oP '\d+ passed' doctest-output.txt | head -1 || echo "0 passed")
echo "✅ All doc tests passed ($PASSED)" >> "$GITHUB_STEP_SUMMARY"
else
{
echo "❌ Some doc tests failed:"
echo ""
echo "\`\`\`"
tail -50 doctest-output.txt
echo "\`\`\`"
} >> "$GITHUB_STEP_SUMMARY"
exit 1
fi
- name: Upload doctest report
uses: actions/upload-artifact@v7
if: always()
with:
name: doctest-report
path: doctest-output.txt
retention-days: 7
# ============================================================================
# DOC COVERAGE - Measure documentation coverage percentage
# ============================================================================
doc-coverage:
name: Documentation Coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Rust nightly
uses: dtolnay/rust-toolchain@nightly
- name: Measure documentation coverage
run: |
{
echo "## Documentation Coverage Report"
echo ""
} >> "$GITHUB_STEP_SUMMARY"
# Generate coverage report
RUSTDOCFLAGS="-Z unstable-options --show-coverage" \
cargo +nightly doc --no-deps 2>&1 | tee doc-coverage.txt
# Extract and display coverage table
{
echo "\`\`\`"
cat doc-coverage.txt
echo "\`\`\`"
echo ""
} >> "$GITHUB_STEP_SUMMARY"
# Check for minimum coverage (advisory, doesn't fail build)
if grep -q "Total" doc-coverage.txt; then
COVERAGE=$(grep "Total" doc-coverage.txt | awk '{print $NF}' | tr -d '%')
echo "**Total Documentation Coverage: ${COVERAGE}%**" >> "$GITHUB_STEP_SUMMARY"
# Advisory warning if below 90%
if [ -n "$COVERAGE" ] && [ "$(echo "$COVERAGE < 90" | bc -l 2>/dev/null || echo 0)" -eq 1 ]; then
echo "⚠️ Coverage is below 90% target" >> "$GITHUB_STEP_SUMMARY"
else
echo "✅ Coverage meets or exceeds 90% target" >> "$GITHUB_STEP_SUMMARY"
fi
fi
continue-on-error: true # Nightly features may break, don't fail CI
- name: Upload coverage report
uses: actions/upload-artifact@v7
if: always()
with:
name: doc-coverage-report
path: doc-coverage.txt
retention-days: 30
# ============================================================================
# MARKDOWN CODE VERIFY - Verify code samples in markdown docs compile
# ============================================================================
markdown-code-verify:
name: Markdown Code Samples
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry and build
uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: markdown-code-${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
markdown-code-${{ runner.os }}-cargo-
- name: Verify markdown code samples
run: |
{
echo "## Markdown Code Sample Verification"
echo ""
echo "Verifying Rust code samples in docs/ directory compile..."
echo ""
} >> "$GITHUB_STEP_SUMMARY"
# Run verification on docs/ directory with fail-fast for CI
if ./scripts/docs/verify-markdown-code.sh --fail-fast docs/ 2>&1 | tee markdown-code-output.txt; then
echo "✅ All markdown code samples compile successfully" >> "$GITHUB_STEP_SUMMARY"
else
{
echo "❌ Some markdown code samples failed to compile:"
echo ""
echo "\`\`\`"
tail -100 markdown-code-output.txt
echo "\`\`\`"
} >> "$GITHUB_STEP_SUMMARY"
exit 1
fi
- name: Upload verification report
uses: actions/upload-artifact@v7
if: always()
with:
name: markdown-code-report
path: markdown-code-output.txt
retention-days: 7