|
| 1 | +name: Markdown Link Sanity |
| 2 | + |
| 3 | +on: |
| 4 | + push: |
| 5 | + branches: [master] |
| 6 | + pull_request: |
| 7 | + workflow_dispatch: |
| 8 | + |
| 9 | +permissions: |
| 10 | + contents: read |
| 11 | + |
| 12 | +jobs: |
| 13 | + markdown-links: |
| 14 | + name: Check relative markdown links resolve |
| 15 | + runs-on: ubuntu-latest |
| 16 | + timeout-minutes: 5 |
| 17 | + |
| 18 | + steps: |
| 19 | + - name: Checkout |
| 20 | + uses: actions/checkout@v6 |
| 21 | + |
| 22 | + - name: Check relative links in markdown files |
| 23 | + shell: bash |
| 24 | + run: | |
| 25 | + set -euo pipefail |
| 26 | + python3 - <<'PYEOF' |
| 27 | + import re, sys, os, glob |
| 28 | +
|
| 29 | + link_re = re.compile(r'\[[^\]]*\]\(([^)]+)\)') |
| 30 | + broken = [] |
| 31 | + checkout_root = os.path.abspath(os.getcwd()) |
| 32 | +
|
| 33 | + for md_file in glob.glob('**/*.md', recursive=True): |
| 34 | + # Skip vendored plugin docs: their links target the upstream |
| 35 | + # repo layout, not ours. |
| 36 | + if md_file.startswith(('.git/', 'Plugins/')): |
| 37 | + continue |
| 38 | + base_dir = os.path.dirname(md_file) |
| 39 | + with open(md_file, encoding='utf-8') as f: |
| 40 | + content = f.read() |
| 41 | + for match in link_re.finditer(content): |
| 42 | + target = match.group(1).strip() |
| 43 | + if target.startswith(('http://', 'https://', 'mailto:', '#')): |
| 44 | + continue |
| 45 | + target_path = target.split('#')[0] |
| 46 | + if not target_path: |
| 47 | + continue |
| 48 | + resolved = os.path.abspath(os.path.join(base_dir, target_path)) |
| 49 | + if os.path.commonpath([checkout_root, resolved]) != checkout_root: |
| 50 | + continue |
| 51 | + if not os.path.exists(resolved): |
| 52 | + broken.append(f'{md_file}: {target}') |
| 53 | +
|
| 54 | + if broken: |
| 55 | + print('::error::Broken relative markdown links found:') |
| 56 | + for b in broken: |
| 57 | + print(f' {b}') |
| 58 | + sys.exit(1) |
| 59 | +
|
| 60 | + print('All relative markdown links resolve.') |
| 61 | + PYEOF |
0 commit comments