Install was at line 517 of 969, under the boot sequence, the snapshot lifecycle and the release process. Someone deciding whether to trust this with their backups should not have to scroll past any of that. README is now 211 lines: what it does, the minimum version, install, the support matrix, updating, uninstall. Everything else moved to docs/ (nested snapshots, how it works, recovery, CLI, releasing). A test enforces it: every internal link resolves, Install stays near the top, and the README does not grow back. Moving Markdown breaks cross-references -- it broke eight of them here, including one in a recovery doc, where the person following the link is by definition already having a bad day.
97 lines
3.5 KiB
Python
97 lines
3.5 KiB
Python
"""The docs must not lie about themselves.
|
|
|
|
The README was 969 lines with the install instructions at line 517. Splitting it into
|
|
docs/ fixed that and broke every cross-reference in the process -- which is the normal
|
|
outcome of moving Markdown around, and exactly why this is a test rather than a
|
|
careful afternoon.
|
|
|
|
A dead link in a recovery doc is worse than a dead link anywhere else: the person
|
|
following it is, by definition, already having a bad day.
|
|
"""
|
|
|
|
import os
|
|
import re
|
|
|
|
import pytest
|
|
|
|
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
DOCS = os.path.join(ROOT, "docs")
|
|
|
|
LINK_RE = re.compile(r"\[([^\]]+)\]\(([^)]+)\)")
|
|
HEADING_RE = re.compile(r"^#{1,6}\s+(.*)$", re.M)
|
|
|
|
|
|
def markdown_files():
|
|
files = [os.path.join(ROOT, "README.md"), os.path.join(ROOT, "CHANGELOG.md")]
|
|
if os.path.isdir(DOCS):
|
|
files += [os.path.join(DOCS, f) for f in sorted(os.listdir(DOCS))
|
|
if f.endswith(".md")]
|
|
return files
|
|
|
|
|
|
def anchors(text):
|
|
"""GitHub/Gitea slugs for every heading in `text`."""
|
|
out = set()
|
|
for h in HEADING_RE.findall(text):
|
|
slug = re.sub(r"[^a-z0-9 -]", "", h.lower()).replace(" ", "-")
|
|
out.add(slug)
|
|
return out
|
|
|
|
|
|
@pytest.mark.parametrize("path", markdown_files(), ids=os.path.basename)
|
|
def test_every_internal_link_resolves(path):
|
|
with open(path, encoding="utf-8") as fh:
|
|
text = fh.read()
|
|
here = anchors(text)
|
|
base = os.path.dirname(path)
|
|
|
|
broken = []
|
|
for label, target in LINK_RE.findall(text):
|
|
if target.startswith(("http://", "https://", "mailto:")):
|
|
continue
|
|
rel, _, anchor = target.partition("#")
|
|
|
|
if not rel: # same-file anchor
|
|
if anchor and anchor not in here:
|
|
broken.append(f"[{label}](#{anchor}) — no such heading here")
|
|
continue
|
|
|
|
dest = os.path.normpath(os.path.join(base, rel))
|
|
if not os.path.exists(dest):
|
|
broken.append(f"[{label}]({target}) — file does not exist")
|
|
continue
|
|
|
|
if anchor and dest.endswith(".md"):
|
|
with open(dest, encoding="utf-8") as fh:
|
|
if anchor not in anchors(fh.read()):
|
|
broken.append(f"[{label}]({target}) — no such heading there")
|
|
|
|
assert not broken, "broken links in {}:\n {}".format(
|
|
os.path.basename(path), "\n ".join(broken)
|
|
)
|
|
|
|
|
|
class TestTheReadmeStaysAReadme:
|
|
def test_install_is_near_the_top(self):
|
|
# It was at line 517 of 969, under a wall of internals. Somebody deciding
|
|
# whether to use this should not have to scroll past the boot sequence.
|
|
with open(os.path.join(ROOT, "README.md"), encoding="utf-8") as fh:
|
|
lines = fh.read().splitlines()
|
|
install = next(i for i, ln in enumerate(lines, 1) if ln.startswith("## Install"))
|
|
assert install < 40, f"## Install is at line {install}"
|
|
|
|
def test_the_readme_does_not_grow_back(self):
|
|
with open(os.path.join(ROOT, "README.md"), encoding="utf-8") as fh:
|
|
n = len(fh.read().splitlines())
|
|
assert n < 300, (
|
|
f"README is {n} lines. Detail belongs in docs/ — the README is what "
|
|
f"someone reads before they trust this with their backups."
|
|
)
|
|
|
|
def test_the_minimum_version_is_stated_before_the_install_command(self):
|
|
with open(os.path.join(ROOT, "README.md"), encoding="utf-8") as fh:
|
|
text = fh.read()
|
|
assert "24.10" in text[:text.index("## Install")], (
|
|
"the minimum TrueNAS version must be visible above the install steps"
|
|
)
|