Skip to content

Commit a3f52f4

Browse files
Add GH action to check broken links
1 parent 998295d commit a3f52f4

10 files changed

Lines changed: 92438 additions & 68876 deletions

File tree

.github/workflows/ci.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
test-and-validate:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- name: Check out repository
13+
uses: actions/checkout@v4
14+
with:
15+
fetch-depth: 0
16+
17+
- name: Set up Python
18+
uses: actions/setup-python@v5
19+
with:
20+
python-version: "3.11"
21+
22+
- name: Install dependencies
23+
run: |
24+
python -m pip install --upgrade pip
25+
python -m pip install -r src/main/requirements.txt
26+
27+
- name: Run unit tests
28+
run: python -m unittest discover -s src/test -p "test_*.py"
29+
30+
- name: Check internal broken links in changed HTML files
31+
env:
32+
GITHUB_DIFF_RANGE: ${{ github.event_name == 'pull_request' && format('{0}...{1}', github.event.pull_request.base.sha, github.sha) || format('{0}...{1}', github.event.before, github.sha) }}
33+
run: python src/main/ci_internal_links.py

blog/index.html

Lines changed: 92097 additions & 68680 deletions
Large diffs are not rendered by default.

src/main/ci_internal_links.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/usr/bin/env python3
2+
#
3+
# SPDX-FileCopyrightText: 2026 John Samuel <johnsamuelwrites@gmail.com>
4+
#
5+
# SPDX-License-Identifier: GPL-3.0-or-later
6+
#
7+
8+
import argparse
9+
import os
10+
import subprocess
11+
import sys
12+
from pathlib import Path
13+
from typing import List
14+
15+
from links import LinkChecker, print_results
16+
17+
18+
def resolve_changed_html_files(diff_range: str) -> List[str]:
19+
"""Return changed HTML files from a git diff range."""
20+
repo_root = Path.cwd().resolve()
21+
repo_root_for_git = repo_root.as_posix()
22+
zero_sha = "0" * 40
23+
if diff_range.startswith(f"{zero_sha}..."):
24+
diff_range = "HEAD^...HEAD"
25+
26+
try:
27+
completed = subprocess.run(
28+
[
29+
"git",
30+
f"-c",
31+
f"safe.directory={repo_root_for_git}",
32+
"diff",
33+
"--name-only",
34+
diff_range,
35+
"--",
36+
"*.html",
37+
"*.htm",
38+
"*.xhtml",
39+
],
40+
check=True,
41+
capture_output=True,
42+
text=True,
43+
)
44+
except subprocess.CalledProcessError as error:
45+
print(f"Unable to resolve changed HTML files for diff range {diff_range!r}.")
46+
if error.stderr:
47+
print(error.stderr.strip())
48+
return []
49+
html_files = []
50+
for line in completed.stdout.splitlines():
51+
if not line.strip():
52+
continue
53+
candidate = (repo_root / line.strip()).resolve()
54+
if candidate.is_file():
55+
html_files.append(str(candidate))
56+
return sorted(set(html_files))
57+
58+
59+
def parse_args() -> argparse.Namespace:
60+
parser = argparse.ArgumentParser(
61+
description="Run internal broken-link checks for changed HTML files in CI."
62+
)
63+
parser.add_argument(
64+
"--diff-range",
65+
default=os.environ.get("GITHUB_DIFF_RANGE"),
66+
help="Git diff range to inspect, for example BASE_SHA...HEAD_SHA.",
67+
)
68+
return parser.parse_args()
69+
70+
71+
def main() -> int:
72+
args = parse_args()
73+
if not args.diff_range:
74+
print("No diff range supplied; skipping internal broken-link CI check.")
75+
return 0
76+
77+
html_files = resolve_changed_html_files(args.diff_range)
78+
if not html_files:
79+
print("No changed HTML files found in the selected diff range.")
80+
return 0
81+
82+
checker = LinkChecker(
83+
check_external=False,
84+
check_internal=True,
85+
check_favicon=False,
86+
check_styles=False,
87+
check_scripts=False,
88+
)
89+
results = checker.check_files(html_files)
90+
print_results(
91+
results,
92+
show_external=False,
93+
show_internal=True,
94+
show_favicon=False,
95+
show_styles=False,
96+
show_scripts=False,
97+
)
98+
return 1 if results else 0
99+
100+
101+
if __name__ == "__main__":
102+
sys.exit(main())

0 commit comments

Comments
 (0)