ci(infra): add workflow to check for RST syntax

This commit is contained in:
Mason Daugherty
2025-10-09 17:15:39 -04:00
parent 6fc21afbc9
commit 7e20678321
3 changed files with 170 additions and 0 deletions

54
.github/workflows/check_rst_syntax.yml vendored Normal file
View File

@@ -0,0 +1,54 @@
# Check for reStructuredText (RST) syntax in Python files.
#
# This project uses Markdown/MkDocs Material syntax instead of RST.
# This workflow prevents RST-specific patterns from being introduced.
name: "📝 Ensure no RST Syntax"
on:
push:
branches: [master]
pull_request:
merge_group:
# Cancel redundant workflow runs
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
check-rst-syntax:
name: "Check for RST Syntax"
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: "📋 Checkout Code"
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: "🐍 Setup Python"
uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: "📂 Get Changed Python Files"
id: changed-files
uses: tj-actions/changed-files@v47
with:
files: "**/*.py"
- name: "🔍 Check for RST Syntax in Changed Files"
if: steps.changed-files.outputs.any_changed == 'true'
run: |
echo "Checking the following files for RST syntax:"
echo "${{ steps.changed-files.outputs.all_changed_files }}"
python scripts/check_rst_syntax.py ${{ steps.changed-files.outputs.all_changed_files }}
- name: "✅ No RST Syntax Detected"
if: steps.changed-files.outputs.any_changed != 'true'
run: |
echo "No Python files changed, skipping RST syntax check."

View File

@@ -1,6 +1,12 @@
repos:
- repo: local
hooks:
- id: check-rst-syntax
name: check for RST syntax
language: system
entry: python scripts/check_rst_syntax.py
files: \.py$
types: [file]
- id: core
name: format and lint core
language: system

110
scripts/check_rst_syntax.py Executable file
View File

@@ -0,0 +1,110 @@
#!/usr/bin/env python3
"""Script to check for reStructuredText (RST) syntax in Python files.
This script checks for RST-specific syntax patterns that should not be used
in docstrings. The project uses Markdown/MkDocs Material syntax instead.
"""
import re
import sys
from pathlib import Path
from typing import List, Tuple
# RST patterns to detect (pattern, description)
RST_PATTERNS: List[Tuple[str, str]] = [
(r"\.\.\s+code-block::", "RST code-block directive (use ```language instead)"),
(r":func:`", "RST :func: role (use regular Markdown links)"),
(r":class:`", "RST :class: role (use regular Markdown links)"),
(r":meth:`", "RST :meth: role (use regular Markdown links)"),
(
r"\.\.\s+deprecated::",
"RST deprecated directive (use !!! deprecated admonition)",
),
(r"\.\.\s+dropdown::", "RST dropdown directive (use ??? admonitions)"),
(r"\.\.\s+versionadded::", "RST versionadded directive"),
(
r"\.\.\s+versionchanged::",
"RST versionchanged directive",
),
(r"\.\.\s+warning::", "RST warning directive (use !!! warning admonition)"),
(r"\.\.\s+important::", "RST important directive (use !!! important admonition)"),
(r"\.\.\s+note::", "RST note directive (use !!! note admonition)"),
(r":private:`", "RST :private: role (prefix name with underscore instead)"),
(r"`[^`]+<[^>]+>`__", "RST anonymous hyperlink (use [text](link) instead)"),
(r"`[^`]+<[^>]+>`_", "RST named hyperlink (use [text](link) instead)"),
]
def check_file_for_rst(file_path: Path) -> List[Tuple[int, str, str]]:
"""Check a single file for RST syntax patterns.
Args:
file_path: Path to the file to check.
Returns:
List of tuples containing (line_number, matched_text, description).
"""
violations: List[Tuple[int, str, str]] = []
try:
content = file_path.read_text(encoding="utf-8")
lines = content.splitlines()
for line_num, line in enumerate(lines, start=1):
for pattern, description in RST_PATTERNS:
matches = re.finditer(pattern, line)
for match in matches:
violations.append((line_num, match.group(0), description))
except (UnicodeDecodeError, PermissionError):
# Skip files that can't be read as text
pass
return violations
def main() -> int:
"""Main entry point for the script.
Returns:
Exit code: 0 if no violations found, 1 if violations detected.
"""
# Get files from command line arguments
files = sys.argv[1:]
if not files:
print("No files provided to check.", file=sys.stderr)
return 0
has_violations = False
for file_str in files:
file_path = Path(file_str)
if file_path.suffix != ".py":
# Only check Python files
continue
if not file_path.exists():
continue
violations = check_file_for_rst(file_path)
if violations:
has_violations = True
print(f"\nRST syntax detected in: {file_path}")
for line_num, matched_text, description in violations:
print(f" Line {line_num}: {matched_text}")
print(f"{description}")
if has_violations:
print(
"\nRST syntax is not allowed. Please use Markdown/MkDocs Material syntax instead."
)
return 1
return 0
if __name__ == "__main__":
sys.exit(main())