From 775f5aa9c1fdc6d030148e9c2ef18f9336aa5b7c Mon Sep 17 00:00:00 2001 From: rashim27us Date: Fri, 1 May 2026 16:44:32 +0530 Subject: [PATCH 1/3] feat: add CI sanity check for cross-reference validation --- .github/workflows/ci.yml | 6 ++++ scripts/validate_cross_references.py | 54 ++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 scripts/validate_cross_references.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af54a3c..76839b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -151,6 +151,12 @@ jobs: python scripts/validate_markdown_tables.py + - name: Validate cross-references + run: | + set -euo pipefail + + python scripts/validate_cross_references.py + - name: Check internal Markdown links run: | set -euo pipefail diff --git a/scripts/validate_cross_references.py b/scripts/validate_cross_references.py new file mode 100644 index 0000000..cd4df28 --- /dev/null +++ b/scripts/validate_cross_references.py @@ -0,0 +1,54 @@ +import os +import re +import sys +from pathlib import Path + +def main(): + root_dir = Path(__file__).resolve().parent.parent + standard_dir = root_dir / 'standard' + + if not standard_dir.exists(): + print(f"Error: {standard_dir} not found.", file=sys.stderr) + sys.exit(1) + + valid_reqs = set() + req_pattern = re.compile(r'APTS-[A-Z]{2}-[0-9A-Z]{3}') + + for md_file in standard_dir.rglob('*.md'): + with open(md_file, 'r', encoding='utf-8') as f: + content = f.read() + # Match definitions like "## APTS-RP-001: Title" + defs = re.findall(r'^#{2,4}\s+(APTS-[A-Z]{2}-[0-9A-Z]{3}):', content, re.MULTILINE) + valid_reqs.update(defs) + + # Match table definitions like "| APTS-RP-001 |" + table_defs = re.findall(r'\|\s*(APTS-[A-Z]{2}-[0-9A-Z]{3})\s*\|', content) + valid_reqs.update(table_defs) + + if not valid_reqs: + print("Error: No requirements found to validate against.", file=sys.stderr) + sys.exit(1) + + failed = False + for md_file in standard_dir.rglob('*.md'): + with open(md_file, 'r', encoding='utf-8') as f: + lines = f.readlines() + + for i, line in enumerate(lines): + if '> **See also:**' in line: + refs = req_pattern.findall(line) + for ref in refs: + if ref not in valid_reqs: + print(f"Error in {md_file.relative_to(root_dir)}:{i+1}") + print(f" Invalid cross-reference: {ref} is not a known requirement.") + failed = True + + if failed: + print("Cross-reference validation failed.", file=sys.stderr) + sys.exit(1) + else: + print(f"Successfully validated cross-references against {len(valid_reqs)} known requirements.") + sys.exit(0) + +if __name__ == '__main__': + main() From 5b48e176bdbee8dfd576ce684398eae262b2a2cd Mon Sep 17 00:00:00 2001 From: rashim27us Date: Fri, 1 May 2026 23:45:31 +0530 Subject: [PATCH 2/3] implement strict cross-reference validation engine --- scripts/_ci_utils.py | 7 +++ scripts/validate_cross_references.py | 79 +++++++++++++++------------- 2 files changed, 49 insertions(+), 37 deletions(-) diff --git a/scripts/_ci_utils.py b/scripts/_ci_utils.py index 3cc3dce..e7e818e 100644 --- a/scripts/_ci_utils.py +++ b/scripts/_ci_utils.py @@ -7,6 +7,13 @@ REPO_ROOT = Path(__file__).resolve().parent.parent FENCE_OPEN_PATTERN = re.compile(r"^[ \t]{0,3}((`{3,})|(~{3,})).*$") +PLACEHOLDER_REQUIREMENT_IDS = frozenset({ + "APTS-XX-NNN", + "APTS-XX-ANN", + "APTS-SE-027", + "APTS-SE-A01", +}) + LineWithNumber = tuple[int, str] diff --git a/scripts/validate_cross_references.py b/scripts/validate_cross_references.py index cd4df28..81cff93 100644 --- a/scripts/validate_cross_references.py +++ b/scripts/validate_cross_references.py @@ -1,54 +1,59 @@ -import os +from __future__ import annotations + import re import sys from pathlib import Path -def main(): - root_dir = Path(__file__).resolve().parent.parent - standard_dir = root_dir / 'standard' - - if not standard_dir.exists(): - print(f"Error: {standard_dir} not found.", file=sys.stderr) - sys.exit(1) +from _ci_utils import ( + PLACEHOLDER_REQUIREMENT_IDS, + display_path, + git_ls_files, + read_text, +) +def main() -> int: valid_reqs = set() - req_pattern = re.compile(r'APTS-[A-Z]{2}-[0-9A-Z]{3}') + req_pattern = re.compile(r"APTS-[A-Z]{2}-[A-Z0-9]{3}") - for md_file in standard_dir.rglob('*.md'): - with open(md_file, 'r', encoding='utf-8') as f: - content = f.read() - # Match definitions like "## APTS-RP-001: Title" - defs = re.findall(r'^#{2,4}\s+(APTS-[A-Z]{2}-[0-9A-Z]{3}):', content, re.MULTILINE) - valid_reqs.update(defs) - - # Match table definitions like "| APTS-RP-001 |" - table_defs = re.findall(r'\|\s*(APTS-[A-Z]{2}-[0-9A-Z]{3})\s*\|', content) - valid_reqs.update(table_defs) + md_files = git_ls_files("*.md") + standard_md_files = [f for f in md_files if Path(f).parts[0] == "standard"] + + for md_file in standard_md_files: + content = read_text(md_file) + + # Match definitions like "## APTS-RP-001: Title" + defs = re.findall(r"^#{2,4}\s+(APTS-[A-Z]{2}-[A-Z0-9]{3}):", content, re.MULTILINE) + valid_reqs.update(defs) + + # Match table definitions like "| APTS-RP-001 |" + table_defs = re.findall(r"\|\s*(APTS-[A-Z]{2}-[A-Z0-9]{3})\s*\|", content) + valid_reqs.update(table_defs) if not valid_reqs: print("Error: No requirements found to validate against.", file=sys.stderr) - sys.exit(1) + return 1 failed = False - for md_file in standard_dir.rglob('*.md'): - with open(md_file, 'r', encoding='utf-8') as f: - lines = f.readlines() - + for md_file in md_files: + content = read_text(md_file) + lines = content.splitlines() + for i, line in enumerate(lines): - if '> **See also:**' in line: - refs = req_pattern.findall(line) - for ref in refs: - if ref not in valid_reqs: - print(f"Error in {md_file.relative_to(root_dir)}:{i+1}") - print(f" Invalid cross-reference: {ref} is not a known requirement.") - failed = True + refs = req_pattern.findall(line) + for ref in refs: + if ref in PLACEHOLDER_REQUIREMENT_IDS: + continue + if ref not in valid_reqs: + print(f"Error in {display_path(md_file)}:{i+1}") + print(f" Invalid cross-reference: {ref} is not a known requirement.") + failed = True if failed: print("Cross-reference validation failed.", file=sys.stderr) - sys.exit(1) - else: - print(f"Successfully validated cross-references against {len(valid_reqs)} known requirements.") - sys.exit(0) + return 1 + + print(f"Successfully validated cross-references against {len(valid_reqs)} known requirements.") + return 0 -if __name__ == '__main__': - main() +if __name__ == "__main__": + raise SystemExit(main()) From 12f3e9a7ce25f44f75dd67f0b5dbb4280aa70320 Mon Sep 17 00:00:00 2001 From: rashim27us Date: Sun, 3 May 2026 21:29:54 +0530 Subject: [PATCH 3/3] removed hard coded IDs --- scripts/_ci_utils.py | 7 ------- scripts/validate_cross_references.py | 5 +---- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/scripts/_ci_utils.py b/scripts/_ci_utils.py index e7e818e..3cc3dce 100644 --- a/scripts/_ci_utils.py +++ b/scripts/_ci_utils.py @@ -7,13 +7,6 @@ REPO_ROOT = Path(__file__).resolve().parent.parent FENCE_OPEN_PATTERN = re.compile(r"^[ \t]{0,3}((`{3,})|(~{3,})).*$") -PLACEHOLDER_REQUIREMENT_IDS = frozenset({ - "APTS-XX-NNN", - "APTS-XX-ANN", - "APTS-SE-027", - "APTS-SE-A01", -}) - LineWithNumber = tuple[int, str] diff --git a/scripts/validate_cross_references.py b/scripts/validate_cross_references.py index 81cff93..60281f1 100644 --- a/scripts/validate_cross_references.py +++ b/scripts/validate_cross_references.py @@ -5,7 +5,6 @@ from pathlib import Path from _ci_utils import ( - PLACEHOLDER_REQUIREMENT_IDS, display_path, git_ls_files, read_text, @@ -34,15 +33,13 @@ def main() -> int: return 1 failed = False - for md_file in md_files: + for md_file in standard_md_files: content = read_text(md_file) lines = content.splitlines() for i, line in enumerate(lines): refs = req_pattern.findall(line) for ref in refs: - if ref in PLACEHOLDER_REQUIREMENT_IDS: - continue if ref not in valid_reqs: print(f"Error in {display_path(md_file)}:{i+1}") print(f" Invalid cross-reference: {ref} is not a known requirement.")