diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index b5e77cc..b7901ba 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -26,6 +26,8 @@ jobs: run: python tools/build_docs.py - name: Build the site (broken links fail) run: mkdocs build --strict + - name: Every page is rendered, not raw Markdown + run: python tools/check_site.py - uses: actions/upload-pages-artifact@v3 if: github.event_name == 'push' with: diff --git a/mkdocs.yml b/mkdocs.yml index 5c25314..c144e86 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -20,6 +20,8 @@ plugins: markdown_extensions: - admonition + - attr_list + - md_in_html - tables - toc: permalink: true diff --git a/tools/check_site.py b/tools/check_site.py new file mode 100644 index 0000000..bf03c36 --- /dev/null +++ b/tools/check_site.py @@ -0,0 +1,37 @@ +"""Fail if a built page still shows Markdown source, which means it was not rendered. + + python tools/check_site.py # after `mkdocs build` +""" + +from __future__ import annotations + +import re +import sys +from pathlib import Path + +SITE = Path(__file__).resolve().parents[1] / "build" / "site" + +#: Markdown that survives only when a page was left unprocessed. +RAW_MARKDOWN = ("| --- |", "](") +CODE = re.compile(r"<(pre|code)\b.*?", re.S) +TAG = re.compile(r"<[^>]+>") + + +def unrendered(page: Path) -> list[str]: + text = TAG.sub("", CODE.sub("", page.read_text())) + return [marker for marker in RAW_MARKDOWN if marker in text] + + +def main() -> int: + pages = sorted(SITE.rglob("index.html")) + if not pages: + sys.exit(f"no pages under {SITE}; run mkdocs build first") + bad = {str(page.relative_to(SITE)): found for page in pages if (found := unrendered(page))} + for page, found in bad.items(): + print(f"unrendered Markdown {found} in {page}") + print(f"checked {len(pages)} pages, {len(bad)} unrendered") + return 1 if bad else 0 + + +if __name__ == "__main__": + sys.exit(main())