Skip to content

Merge pull request #124 from berkeleydb/docs/phase4-final #5

Merge pull request #124 from berkeleydb/docs/phase4-final

Merge pull request #124 from berkeleydb/docs/phase4-final #5

Workflow file for this run

# Documentation validation.
#
# Builds the modernized docs (docs-src/build.py: Markdown -> HTML + man + PDF)
# and runs the validators that lock in the reverse-DocBook migration's
# guarantees. Modeled on ci.yml/fuzz.yml conventions: hard gates block PRs,
# advisory tiers are continue-on-error, and heavy work (PDF/TeX-free but slow,
# external link check) is scheduled-only or best-effort so per-PR jobs stay
# fast.
#
# Tooling comes from the flake dev shell (nix develop) so CI matches local
# exactly -- pandoc, weasyprint, poppler-utils, mandoc, codespell, lychee and
# write-good are all pinned there.
#
# HARD gates (fail the PR): build (HTML+man), no-loss, completeness, spelling,
# internal link-check, man-lint.
# ADVISORY (continue-on-error): prose (write-good), external link-check.
# BEST-EFFORT (scheduled / continue-on-error): PDF build + validation (slow).
name: Docs
on:
push:
branches: [master]
pull_request:
paths:
- 'docs-src/**'
- '.github/workflows/docs.yml'
- 'flake.nix'
- 'dist/RELEASE'
workflow_dispatch:
schedule:
# Weekly (Mon 05:23 UTC): the full run including the slow PDF build and the
# external link check, which are best-effort/skipped on per-PR runs.
- cron: '23 5 * * 1'
concurrency:
group: docs-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
# ----------------------------------------------------------------------------
# Build HTML + man (fast, always) and run the hard gates that depend on the
# generated output. PDF is built here only on schedule/dispatch (see the
# `pdf` job) so a PR isn't gated on the ~4-minute weasyprint pass.
# ----------------------------------------------------------------------------
build:
name: build + gates (html, man, no-loss, completeness, spelling, links, man-lint)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Nix (flakes enabled)
uses: cachix/install-nix-action@v27
with:
extra_nix_config: |
experimental-features = nix-command flakes
# 1. BUILD (hard): HTML + man with 0 errors. --no-pdf keeps the PR fast;
# the PDF path is exercised by the `pdf` job (scheduled/best-effort).
- name: Build HTML + man
run: nix develop --command bash -c 'cd docs-src && python3 build.py --no-pdf'
# build.py self-check guards the md->man reshape, PDF book discovery, and
# the .md->.html link rewrite (unit-level, no external tools).
- name: build.py self-check
run: nix develop --command bash -c 'cd docs-src && python3 build.py --selfcheck'
# 2. NO-LOSS GATE (hard): every migrated tree still retains its source
# content (word-multiset retention + no code/section drop). Locks the
# "nothing lost" guarantee against future edits.
- name: No-loss gate (all trees)
run: nix develop --command bash -c 'python3 docs-src/_migrate/verify_all.py'
# 3. COMPLETENESS GATE (hard): every public db.h function is documented
# (28/28), and every uncovered method is on the frozen allowlist -- a
# NEW undocumented API fails.
- name: Completeness gate (API coverage)
run: nix develop --command bash -c 'python3 docs-src/_migrate/man_coverage.py --ci'
# 4. SPELLING (hard on NEW typos): codespell, baselined against the legacy
# typo backlog so only newly-introduced typos fail.
- name: Spelling gate (codespell, baselined)
run: nix develop --command bash -c 'python3 docs-src/_migrate/spellcheck.py'
# 6. INTERNAL LINK CHECK (hard): every link into migrated content must
# resolve. Deferred-tree + un-migrated-asset links are excluded (see
# docs-src/_migrate/lychee.toml). External links are the advisory job.
- name: Internal link check (lychee, offline)
run: |
nix develop --command bash -c \
'shopt -s globstar; lychee --offline --config docs-src/_migrate/lychee.toml --no-progress "docs-build/html/**/*.html"'
# 7. MAN-LINT (hard): 0 ERRORS from mandoc across every generated .3
# (STYLE/WARNING are fine).
- name: Man-lint (mandoc -Tlint, 0 ERRORS)
run: |
nix develop --command bash -c '
e=0
for f in docs-build/man/man3/*.3; do
if mandoc -Tlint "$f" 2>&1 | grep -q "ERROR"; then
echo "ERRORS in $f:"; mandoc -Tlint "$f" 2>&1 | grep "ERROR" | head -3
e=$((e+1))
fi
done
echo "man pages with ERRORs: $e"
test "$e" -eq 0'
# ----------------------------------------------------------------------------
# 5. PROSE (advisory): write-good passive-voice / wordiness counts. This is
# decades-old technical prose -- surface the numbers, never gate.
# ----------------------------------------------------------------------------
prose:
name: prose advisory (write-good)
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Install Nix (flakes enabled)
uses: cachix/install-nix-action@v27
with:
extra_nix_config: |
experimental-features = nix-command flakes
- name: write-good suggestion counts (per tree)
run: |
nix develop --command bash -c '
shopt -s globstar
total=0
for d in docs-src/api/* docs-src/guides/*; do
[ -d "$d" ] || continue
n=$(write-good "$d"/**/*.md 2>/dev/null | grep -c "on line" || true)
printf "%-40s %5s suggestions\n" "$d" "$n"
total=$((total+n))
done
echo "::notice title=Prose (write-good)::$total advisory suggestion(s) across docs-src"'
# ----------------------------------------------------------------------------
# PDF (best-effort / scheduled): weasyprint renders one PDF per book (~4 min
# over all 13). Not a per-PR gate -- runs on schedule/dispatch, or on a PR
# that touches build.py's PDF path. continue-on-error so a rendering hiccup
# informs without blocking.
# ----------------------------------------------------------------------------
pdf:
name: pdf build + validate (best-effort)
runs-on: ubuntu-latest
continue-on-error: true
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.event_name == 'push'
steps:
- uses: actions/checkout@v4
- name: Install Nix (flakes enabled)
uses: cachix/install-nix-action@v27
with:
extra_nix_config: |
experimental-features = nix-command flakes
- name: Build all outputs (incl. PDF)
run: nix develop --command bash -c 'cd docs-src && timeout 900 python3 build.py'
- name: Validate PDFs (non-empty, page count, title-page version)
run: nix develop --command bash -c 'python3 docs-src/_migrate/validate_pdf.py'
- name: Upload PDFs
if: always()
uses: actions/upload-artifact@v4
with:
name: docs-pdf
path: docs-build/pdf/*.pdf
if-no-files-found: ignore
# ----------------------------------------------------------------------------
# External link check (advisory / scheduled): lychee WITH network, so it
# depends on the reachability of third-party sites. Never gates; scheduled
# and dispatch only so PRs don't wait on the network.
# ----------------------------------------------------------------------------
external-links:
name: external link check (advisory)
runs-on: ubuntu-latest
continue-on-error: true
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
steps:
- uses: actions/checkout@v4
- name: Install Nix (flakes enabled)
uses: cachix/install-nix-action@v27
with:
extra_nix_config: |
experimental-features = nix-command flakes
- name: Build HTML
run: nix develop --command bash -c 'cd docs-src && python3 build.py --no-pdf'
- name: Check external links (network, advisory)
run: |
nix develop --command bash -c '
shopt -s globstar
lychee --no-progress --scheme http --scheme https \
--exclude "localhost" --max-concurrency 8 \
"docs-build/html/**/*.html" || true'