Public Access
DEVX-99: fix: exclude .devin/.terraform dirs from lint_docs, add duplicate heading excludes
Post-merge / detect-type (push) Successful in 9s
Post-merge / validate-commit-msg (push) Successful in 8s
Post-merge / vikunja (push) Successful in 12s
Post-merge / configure-repo (push) Successful in 10s
Post-merge / sync-wiki (push) Successful in 19s
Build Images / detect-type (push) Successful in 35s
Post-merge / release (push) Successful in 25s
Post-merge / badges (push) Successful in 28s
Post-merge / publish (push) Successful in 15s
Build Images / build-and-push (push) Successful in 2m51s
Build Images / cleanup (push) Successful in 2m18s
Post-merge / detect-type (push) Successful in 9s
Post-merge / validate-commit-msg (push) Successful in 8s
Post-merge / vikunja (push) Successful in 12s
Post-merge / configure-repo (push) Successful in 10s
Post-merge / sync-wiki (push) Successful in 19s
Build Images / detect-type (push) Successful in 35s
Post-merge / release (push) Successful in 25s
Post-merge / badges (push) Successful in 28s
Post-merge / publish (push) Successful in 15s
Build Images / build-and-push (push) Successful in 2m51s
Build Images / cleanup (push) Successful in 2m18s
This commit was merged in pull request #155.
This commit is contained in:
+27
-39
@@ -49,13 +49,31 @@ REQUIRED_DOC_FILES = ["index.md"]
|
|||||||
# Maximum age for docs before they're considered stale (days)
|
# Maximum age for docs before they're considered stale (days)
|
||||||
STALE_THRESHOLD_DAYS = 180
|
STALE_THRESHOLD_DAYS = 180
|
||||||
|
|
||||||
# Files excluded from duplicate heading checks (auto-generated or structured)
|
# Files excluded from duplicate heading checks (auto-generated or structured
|
||||||
DUPLICATE_HEADING_EXCLUDES = {"CHANGELOG.md"}
|
# with repeated subsections under different parent sections)
|
||||||
|
DUPLICATE_HEADING_EXCLUDES = {
|
||||||
|
"CHANGELOG.md",
|
||||||
|
"incident-response-sso.md",
|
||||||
|
"role-sync-design.md",
|
||||||
|
}
|
||||||
|
|
||||||
# TODO/FIXME pattern — matches "TODO:" or "FIXME:" at start of line/after whitespace
|
# TODO/FIXME pattern — matches "TODO:" or "FIXME:" at start of line/after whitespace
|
||||||
# Does NOT match references to the word "TODO" in rules/documentation
|
# Does NOT match references to the word "TODO" in rules/documentation
|
||||||
_TODO_RE = re.compile(r"(?m)^\s*(?:>>>?\s*)?(TODO|FIXME|HACK|XXX)\s*:", re.IGNORECASE)
|
_TODO_RE = re.compile(r"(?m)^\s*(?:>>>?\s*)?(TODO|FIXME|HACK|XXX)\s*:", re.IGNORECASE)
|
||||||
|
|
||||||
|
# Directories excluded from markdown file scanning
|
||||||
|
_EXCLUDE_DIRS = {
|
||||||
|
".venv",
|
||||||
|
".git",
|
||||||
|
"node_modules",
|
||||||
|
"__pycache__",
|
||||||
|
".pytest_cache",
|
||||||
|
".devin",
|
||||||
|
".terraform",
|
||||||
|
"site-packages",
|
||||||
|
"dist-info",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def slugify(text: str) -> str:
|
def slugify(text: str) -> str:
|
||||||
"""Convert heading text to a GitHub-style slug."""
|
"""Convert heading text to a GitHub-style slug."""
|
||||||
@@ -155,11 +173,7 @@ def check_internal_links(root: Path, docs_dir: Path) -> list[str]:
|
|||||||
issues: list[str] = []
|
issues: list[str] = []
|
||||||
md_files = list(root.rglob("*.md"))
|
md_files = list(root.rglob("*.md"))
|
||||||
# Exclude .venv, .git, node_modules
|
# Exclude .venv, .git, node_modules
|
||||||
md_files = [
|
md_files = [f for f in md_files if not any(part in _EXCLUDE_DIRS for part in f.parts)]
|
||||||
f
|
|
||||||
for f in md_files
|
|
||||||
if not any(part in {".venv", ".git", "node_modules", "__pycache__", ".pytest_cache"} for part in f.parts)
|
|
||||||
]
|
|
||||||
|
|
||||||
# Load wiki page names from mapping.json — these are valid link targets
|
# Load wiki page names from mapping.json — these are valid link targets
|
||||||
wiki_pages: set[str] = set()
|
wiki_pages: set[str] = set()
|
||||||
@@ -216,11 +230,7 @@ def check_internal_links(root: Path, docs_dir: Path) -> list[str]:
|
|||||||
def check_heading_hierarchy(root: Path) -> list[str]:
|
def check_heading_hierarchy(root: Path) -> list[str]:
|
||||||
"""Check that headings don't skip levels."""
|
"""Check that headings don't skip levels."""
|
||||||
issues: list[str] = []
|
issues: list[str] = []
|
||||||
md_files = [
|
md_files = [f for f in root.rglob("*.md") if not any(part in _EXCLUDE_DIRS for part in f.parts)]
|
||||||
f
|
|
||||||
for f in root.rglob("*.md")
|
|
||||||
if not any(part in {".venv", ".git", "node_modules", "__pycache__", ".pytest_cache"} for part in f.parts)
|
|
||||||
]
|
|
||||||
|
|
||||||
for md_file in md_files:
|
for md_file in md_files:
|
||||||
rel_path = md_file.relative_to(root)
|
rel_path = md_file.relative_to(root)
|
||||||
@@ -242,11 +252,7 @@ def check_todo_fixme(root: Path) -> list[str]:
|
|||||||
references to the word "TODO" in rules or documentation about TODOs.
|
references to the word "TODO" in rules or documentation about TODOs.
|
||||||
"""
|
"""
|
||||||
issues: list[str] = []
|
issues: list[str] = []
|
||||||
md_files = [
|
md_files = [f for f in root.rglob("*.md") if not any(part in _EXCLUDE_DIRS for part in f.parts)]
|
||||||
f
|
|
||||||
for f in root.rglob("*.md")
|
|
||||||
if not any(part in {".venv", ".git", "node_modules", "__pycache__", ".pytest_cache"} for part in f.parts)
|
|
||||||
]
|
|
||||||
|
|
||||||
for md_file in md_files:
|
for md_file in md_files:
|
||||||
rel_path = md_file.relative_to(root)
|
rel_path = md_file.relative_to(root)
|
||||||
@@ -262,11 +268,7 @@ def check_todo_fixme(root: Path) -> list[str]:
|
|||||||
def check_trailing_whitespace(root: Path) -> list[str]:
|
def check_trailing_whitespace(root: Path) -> list[str]:
|
||||||
"""Check for trailing whitespace in markdown files."""
|
"""Check for trailing whitespace in markdown files."""
|
||||||
issues: list[str] = []
|
issues: list[str] = []
|
||||||
md_files = [
|
md_files = [f for f in root.rglob("*.md") if not any(part in _EXCLUDE_DIRS for part in f.parts)]
|
||||||
f
|
|
||||||
for f in root.rglob("*.md")
|
|
||||||
if not any(part in {".venv", ".git", "node_modules", "__pycache__", ".pytest_cache"} for part in f.parts)
|
|
||||||
]
|
|
||||||
|
|
||||||
for md_file in md_files:
|
for md_file in md_files:
|
||||||
rel_path = md_file.relative_to(root)
|
rel_path = md_file.relative_to(root)
|
||||||
@@ -282,11 +284,7 @@ def check_stale_docs(root: Path) -> list[str]:
|
|||||||
"""Check for stale documentation (not modified in >180 days)."""
|
"""Check for stale documentation (not modified in >180 days)."""
|
||||||
issues: list[str] = []
|
issues: list[str] = []
|
||||||
threshold = datetime.now() - timedelta(days=STALE_THRESHOLD_DAYS)
|
threshold = datetime.now() - timedelta(days=STALE_THRESHOLD_DAYS)
|
||||||
md_files = [
|
md_files = [f for f in root.rglob("*.md") if not any(part in _EXCLUDE_DIRS for part in f.parts)]
|
||||||
f
|
|
||||||
for f in root.rglob("*.md")
|
|
||||||
if not any(part in {".venv", ".git", "node_modules", "__pycache__", ".pytest_cache"} for part in f.parts)
|
|
||||||
]
|
|
||||||
|
|
||||||
for md_file in md_files:
|
for md_file in md_files:
|
||||||
rel_path = md_file.relative_to(root)
|
rel_path = md_file.relative_to(root)
|
||||||
@@ -301,11 +299,7 @@ def check_stale_docs(root: Path) -> list[str]:
|
|||||||
def check_duplicate_headings(root: Path) -> list[str]:
|
def check_duplicate_headings(root: Path) -> list[str]:
|
||||||
"""Check for duplicate headings within the same file."""
|
"""Check for duplicate headings within the same file."""
|
||||||
issues: list[str] = []
|
issues: list[str] = []
|
||||||
md_files = [
|
md_files = [f for f in root.rglob("*.md") if not any(part in _EXCLUDE_DIRS for part in f.parts)]
|
||||||
f
|
|
||||||
for f in root.rglob("*.md")
|
|
||||||
if not any(part in {".venv", ".git", "node_modules", "__pycache__", ".pytest_cache"} for part in f.parts)
|
|
||||||
]
|
|
||||||
|
|
||||||
for md_file in md_files:
|
for md_file in md_files:
|
||||||
rel_path = md_file.relative_to(root)
|
rel_path = md_file.relative_to(root)
|
||||||
@@ -386,13 +380,7 @@ def main(
|
|||||||
ws_issues = check_trailing_whitespace(root_path)
|
ws_issues = check_trailing_whitespace(root_path)
|
||||||
if fix and ws_issues:
|
if fix and ws_issues:
|
||||||
fixed = 0
|
fixed = 0
|
||||||
md_files = [
|
md_files = [f for f in root_path.rglob("*.md") if not any(part in _EXCLUDE_DIRS for part in f.parts)]
|
||||||
f
|
|
||||||
for f in root_path.rglob("*.md")
|
|
||||||
if not any(
|
|
||||||
part in {".venv", ".git", "node_modules", "__pycache__", ".pytest_cache"} for part in f.parts
|
|
||||||
)
|
|
||||||
]
|
|
||||||
for md_file in md_files:
|
for md_file in md_files:
|
||||||
content = md_file.read_text(encoding="utf-8")
|
content = md_file.read_text(encoding="utf-8")
|
||||||
fixed_content = _TRAILING_WS_RE.sub("", content)
|
fixed_content = _TRAILING_WS_RE.sub("", content)
|
||||||
|
|||||||
Reference in New Issue
Block a user