Skip to content

Build docs in strict mode in CI - #1489

Merged
cristianrgreco merged 1 commit into
mainfrom
claude/docs-strict-build-f25e61
Oct 11, 2026
Merged

cristianrgreco merged 1 commit into
mainfrom
claude/docs-strict-build-f25e61

Conversation

@cristianrgreco

Copy link
Copy Markdown
Collaborator

Summary

No workflow builds the docs, and Checks ignores docs/** and mkdocs.yml. Netlify deploy previews run a plain mkdocs build, which only fails when a file is missing outright. Broken links, broken anchors and inside_block markers that no longer match all get through.

This PR:

  • Adds a Docs workflow (.github/workflows/docs.yml) that runs mkdocs build --strict on every pull request and push to main.
    • It runs for all paths, not only docs/**. Module docs pull snippets from packages/**/*.test.ts with codeinclude, so renaming a test block can break the docs. The job installs Python and pip packages only, so it takes well under a minute.
    • Python comes from runtime.txt via setup-python's python-version-file. Netlify reads the same file when it deploys the docs (the site is served from Netlify Edge).
    • It follows the existing workflow conventions: major-tag action pins, permissions: contents: read, and the same concurrency group as Checks.
  • Turns on MkDocs link validation at warn level so --strict fails on unrecognized links, missing anchors, absolute links and doc files left out of nav. MkDocs 1.6 reports most of these at info by default, which --strict ignores.
  • Sets codeinclude's block_throw: true (see the experiment below).
  • Fixes the 3 links MkDocs could not validate in docs/features/containers.md.
  • Adds /site/ (MkDocs output) to .gitignore, a line in CONTRIBUTING.md about running the strict build locally, and an AGENTS.md note on how inside_block matching works.

Findings on main

mkdocs build --strict on main passes (exit 0). The only problems are reported at INFO level:

INFO    -  Doc file 'features/containers.md' contains an unrecognized relative link '../containers#with-filesdirectoriescontent', it was left as is. Did you mean '#with-filesdirectoriescontent'?
INFO    -  Doc file 'features/containers.md' contains an unrecognized relative link '../networking#network-aliases', it was left as is. Did you mean 'networking.md#network-aliases'?
INFO    -  Doc file 'features/containers.md' contains an unrecognized relative link '../wait-strategies#log-output', it was left as is. Did you mean 'wait-strategies.md#log-output'?
INFO    -  Documentation built in 1.51 seconds

With the validation settings from this PR, the same tree fails (red):

WARNING -  Doc file 'features/containers.md' contains an unrecognized relative link '../containers#with-filesdirectoriescontent', it was left as is. Did you mean '#with-filesdirectoriescontent'?
WARNING -  Doc file 'features/containers.md' contains an unrecognized relative link '../networking#network-aliases', it was left as is. Did you mean 'networking.md#network-aliases'?
WARNING -  Doc file 'features/containers.md' contains an unrecognized relative link '../wait-strategies#log-output', it was left as is. Did you mean 'wait-strategies.md#log-output'?

Aborted with 3 warnings in strict mode!

These links work on the live site only because of directory URLs. MkDocs leaves them unchecked, so a typo in the target page or anchor would not be caught. They now use .md links, which MkDocs resolves and checks.

No other problems were found. Every page is in nav, there are no absolute links, and every codeinclude file and inside_block marker resolves.

Broken-include experiment

Results of breaking things on purpose, using main's mkdocs.yml and then this PR's:

Breakage main config, --strict This PR, --strict
Renamed the // kafkaLatestConnect { marker in kafka-container-latest.test.ts ✅ exit 0. The Kafka page silently included the whole test file (imports, describe(...), everything) ❌ exit 1: ValueError: Block kafkaLatestConnect not found to inject from ../../packages/modules/kafka/src/kafka-container-latest.test.ts
Pointed a codeinclude at a non-existent test file ❌ exit 1: FileNotFoundError ❌ exit 1: FileNotFoundError
Link with a broken anchor, ../networking#network-alias (main style) or networking.md#network-alias (this PR) ✅ exit 0 (only an INFO line) ❌ exit 1: ... does not contain an anchor '#network-alias'

So strict mode alone does not catch a stale inside_block marker, because codeinclude falls back to the whole file when a block is missing. block_throw: true is the plugin's built-in switch for this, so no extra script is needed.

One gap remains: inside_block:<name> matches the first line containing <name> as a substring. My first try renamed the marker to kafkaLatestConnectRenamed, which still matched, and the build passed. I added a note to AGENTS.md for this. I also checked every current marker, and none of them picks up an earlier, unrelated line.

After the fixes (green)

$ mkdocs build --strict
INFO    -  Cleaning site directory
INFO    -  Building documentation to directory: .../site
INFO    -  Documentation built in 1.23 seconds
$ echo $?
0

Verification

python3.11 -m venv venv && venv/bin/pip install -r requirements.txt   # Python 3.11, matching runtime.txt
venv/bin/mkdocs build --strict                                         # red with the validation settings on main's tree, green on this branch
docker run --rm -v "$PWD:/repo" -w /repo rhysd/actionlint:1.7.7 -no-color .github/workflows/docs.yml   # passes
  • I ran the broken-include experiments above by editing locally and restoring afterwards. None of those edits are in the diff.
  • Biome ignores every file this PR touches (docs, Markdown, YAML), so npm run format and npm run lint don't apply.

Not breaking

Patch. No package source or public API changes. The diff touches CI, MkDocs config, three doc links, .gitignore, CONTRIBUTING.md and AGENTS.md. The rendered site is the same apart from the three link hrefs, which now point at the canonical page URLs.

Add a Docs workflow that runs `mkdocs build --strict` on every pull
request and push to main, using the Python version from runtime.txt
(the one Netlify deploys with). It runs for all paths because module
docs include snippets from packages/**/*.test.ts.

Strict mode alone passes on main, so also:
- enable MkDocs link validation (unrecognized links, anchors, absolute
  links, files missing from nav) at warn level so strict mode fails on it
- set codeinclude `block_throw: true`; without it a missing
  `inside_block` marker silently includes the whole test file
- fix the three relative links in features/containers.md that MkDocs
  could not validate
@cristianrgreco cristianrgreco added maintenance Improvements that do not change functionality patch Backward compatible bug fix labels Oct 9, 2026
@netlify

netlify Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for testcontainers-node ready!

Name Link
🔨 Latest commit 8d429c4
🔍 Latest deploy log https://app.netlify.com/projects/testcontainers-node/deploys/6ac8bce078fd9100084c6382
😎 Deploy Preview https://deploy-preview-1489--testcontainers-node.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@cristianrgreco
cristianrgreco marked this pull request as ready for review October 11, 2026 17:58
@cristianrgreco
cristianrgreco merged commit 72569b8 into main Oct 11, 2026
15 checks passed
@cristianrgreco
cristianrgreco deleted the claude/docs-strict-build-f25e61 branch October 11, 2026 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintenance Improvements that do not change functionality patch Backward compatible bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant