f99010fae1
Desktop Artifacts / Desktop Build (Linux) (push) Waiting to run
Desktop Artifacts / Desktop Build (Windows) (push) Waiting to run
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Waiting to run
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Waiting to run
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Waiting to run
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
97 lines
2.7 KiB
Python
97 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
from __future__ import annotations
|
|
|
|
import pathlib
|
|
import re
|
|
import sys
|
|
|
|
ROOT = pathlib.Path(__file__).resolve().parents[1]
|
|
FRONTMATTER_LIMIT = 80
|
|
ADMONITION_DIRECTIVE_RE = re.compile(
|
|
r'!!!\s+[A-Za-z][\w-]*(?:\s+"[^"]+")?\s*'
|
|
)
|
|
|
|
|
|
def public_markdown_files() -> list[pathlib.Path]:
|
|
return [
|
|
path
|
|
for path in sorted(ROOT.glob("*.md"))
|
|
if path.name != "README.md"
|
|
]
|
|
|
|
|
|
def check_frontmatter(path: pathlib.Path, lines: list[str], errors: list[str]) -> None:
|
|
if not lines or lines[0] != "---":
|
|
errors.append(f"{path.relative_to(ROOT)}: missing YAML frontmatter")
|
|
return
|
|
|
|
closing = next(
|
|
(
|
|
index
|
|
for index, line in enumerate(lines[1:FRONTMATTER_LIMIT], start=1)
|
|
if line == "---"
|
|
),
|
|
None,
|
|
)
|
|
if closing is None:
|
|
errors.append(
|
|
f"{path.relative_to(ROOT)}: missing closing YAML frontmatter delimiter"
|
|
)
|
|
return
|
|
|
|
frontmatter = "\n".join(lines[1:closing])
|
|
if not re.search(r"^title:\s+\S", frontmatter, flags=re.MULTILINE):
|
|
errors.append(f"{path.relative_to(ROOT)}: missing title in YAML frontmatter")
|
|
if not re.search(r"^description:\s+\S", frontmatter, flags=re.MULTILINE):
|
|
errors.append(
|
|
f"{path.relative_to(ROOT)}: missing description in YAML frontmatter"
|
|
)
|
|
|
|
|
|
def check_admonitions(path: pathlib.Path, lines: list[str], errors: list[str]) -> None:
|
|
for index, line in enumerate(lines):
|
|
stripped = line.strip()
|
|
if not stripped.startswith("!!! "):
|
|
continue
|
|
if ADMONITION_DIRECTIVE_RE.fullmatch(stripped) is None:
|
|
errors.append(
|
|
f"{path.relative_to(ROOT)}:{index + 1}: "
|
|
"malformed or collapsed admonition"
|
|
)
|
|
continue
|
|
|
|
following = next(
|
|
(
|
|
candidate
|
|
for candidate in lines[index + 1 :]
|
|
if candidate.strip()
|
|
),
|
|
None,
|
|
)
|
|
if following is None or not following.startswith(" "):
|
|
errors.append(
|
|
f"{path.relative_to(ROOT)}:{index + 1}: "
|
|
"admonition body must be indented"
|
|
)
|
|
|
|
|
|
def main() -> None:
|
|
errors: list[str] = []
|
|
|
|
for path in public_markdown_files():
|
|
lines = path.read_text(encoding="utf-8").splitlines()
|
|
check_frontmatter(path, lines, errors)
|
|
check_admonitions(path, lines, errors)
|
|
|
|
if errors:
|
|
print("docs markdown source check failed:", file=sys.stderr)
|
|
for error in errors:
|
|
print(f" {error}", file=sys.stderr)
|
|
raise SystemExit(1)
|
|
|
|
print("docs markdown source checks passed")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|