feat: add CI documentation rules checker and docs-verify job
CI & Release / Verify documentation (push) Skipped
CI & Release / Verify simulator (push) Skipped
CI & Release / Trivy scan (push) Skipped
CI & Release / Semantic Release (push) Skipped
CI & Release / Verify documentation (pull_request) Successful in 5s
CI & Release / Verify simulator (pull_request) Failing after 9s
CI & Release / Trivy scan (pull_request) Skipped
CI & Release / Semantic Release (pull_request) Skipped
CI & Release / Verify documentation (push) Skipped
CI & Release / Verify simulator (push) Skipped
CI & Release / Trivy scan (push) Skipped
CI & Release / Semantic Release (push) Skipped
CI & Release / Verify documentation (pull_request) Successful in 5s
CI & Release / Verify simulator (pull_request) Failing after 9s
CI & Release / Trivy scan (pull_request) Skipped
CI & Release / Semantic Release (pull_request) Skipped
Enforce link resolution, glossary anchors, and readability rules on every push and PR; docs-only pushes to main still run docs-verify while skipping the simulator gate.
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
"""Tests for scripts/check_docs.py — documentation CI rules."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
SCRIPTS = Path(__file__).resolve().parents[2] / "scripts"
|
||||
sys.path.insert(0, str(SCRIPTS))
|
||||
|
||||
from check_docs import ( # noqa: E402
|
||||
collect_anchors,
|
||||
run_checks,
|
||||
slug_heading,
|
||||
split_link_target,
|
||||
)
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
GLOSSARY = ROOT / "docs/00-glossary.md"
|
||||
|
||||
|
||||
def test_slug_heading_matches_glossary_anchors() -> None:
|
||||
assert slug_heading("T0 — hot") == "t0--hot"
|
||||
assert slug_heading("T3 — warehouse") == "t3--warehouse"
|
||||
assert slug_heading("Source of truth") == "source-of-truth"
|
||||
assert slug_heading("Data & storage") == "data--storage"
|
||||
|
||||
|
||||
def test_glossary_term_anchors_exist() -> None:
|
||||
anchors = collect_anchors(GLOSSARY)
|
||||
for term in (
|
||||
"t0--hot",
|
||||
"t1--warm",
|
||||
"t2--shared",
|
||||
"t3--warehouse",
|
||||
"t4--dev",
|
||||
"source-of-truth",
|
||||
"bulk-sync",
|
||||
"offload",
|
||||
):
|
||||
assert term in anchors, f"missing glossary anchor #{term}"
|
||||
|
||||
|
||||
def test_split_link_target() -> None:
|
||||
assert split_link_target("foo.md#bar") == ("foo.md", "bar")
|
||||
assert split_link_target("foo.md") == ("foo.md", None)
|
||||
|
||||
|
||||
def test_repo_docs_pass() -> None:
|
||||
assert run_checks() == 0
|
||||
|
||||
|
||||
def test_broken_link_detected(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
docs = tmp_path / "docs"
|
||||
docs.mkdir()
|
||||
(docs / "00-glossary.md").write_text("# Glossary\n\n## Data & storage\n")
|
||||
(docs / "bad.md").write_text("See [missing](missing.md).\n")
|
||||
rules = tmp_path / "scripts"
|
||||
rules.mkdir()
|
||||
(rules / "docs_rules.yaml").write_text(
|
||||
"markdown_paths:\n - docs/**/*.md\n"
|
||||
"glossary:\n file: docs/00-glossary.md\n"
|
||||
"banned_link_targets: []\n"
|
||||
"glossary_section_anchors: []\n"
|
||||
"preferred_term_anchors: []\n"
|
||||
"readability:\n forbid_bare_see_refs: false\n"
|
||||
)
|
||||
checker = SCRIPTS / "check_docs.py"
|
||||
monkeypatch.setattr("check_docs.ROOT", tmp_path)
|
||||
monkeypatch.setattr("check_docs.RULES_PATH", rules / "docs_rules.yaml")
|
||||
assert run_checks() == 1
|
||||
Reference in New Issue
Block a user