Skip to content

Commit d701c98

Browse files
ci: respect redirected pages in removed URL check (#612)
Co-authored-by: JJ Coldiron <jj.coldiron@canonical.com>
1 parent 8526180 commit d701c98

3 files changed

Lines changed: 112 additions & 15 deletions

File tree

.github/workflows/check-removed-urls.yml

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,17 @@ jobs:
3636
- name: Generate current URLs list
3737
run: |
3838
for dir in compare base; do
39-
pushd ${dir}/docs
40-
find ./_build/ -name '*.html' \
41-
| sed 's|/_build||;s|/index.html$|/|;s|.html$||' \
42-
| sort > urls.txt
43-
popd
39+
build_dir="${dir}/docs/_build"
40+
urls_file="${dir}/docs/urls.txt"
41+
42+
if [ ! -d "${build_dir}" ]; then
43+
echo "Expected docs build directory not found: ${build_dir}"
44+
exit 1
45+
fi
46+
47+
find "${build_dir}" -name '*.html' \
48+
| sed "s|^${build_dir}||;s|^/html||;s|/index.html$|/|;s|.html$||" \
49+
| sort > "${urls_file}"
4450
done
4551
- name: Compare URLs
46-
run: |
47-
BASE_URLS_PATH="base/docs/urls.txt"
48-
COMPARE_URLS_PATH="compare/docs/urls.txt"
49-
removed=$(comm -23 ${BASE_URLS_PATH} ${COMPARE_URLS_PATH} )
50-
if [ -n "$removed" ]; then
51-
echo "The following URLs were removed:"
52-
echo "$removed"
53-
echo "Please ensure removed pages are redirected"
54-
exit 1
55-
fi
52+
run: python3 compare/docs/_dev/check_removed_urls.py

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Upcoming
44

5+
* Make removed URL check redirect-aware and add support for reusable workflow contexts
56
* Exclude utility directories from builds and checks
67
* Update link to documentation in README
78

@@ -11,6 +12,7 @@
1112
* `docs/Makefile` [#605](https://github.com/canonical/sphinx-stack/pull/605), [#610](https://github.com/canonical/sphinx-stack/pull/610)
1213
* `README.md` [#603](https://github.com/canonical/sphinx-stack/pull/603)
1314
* `.github/workflows/cla-check.yml` [#606](https://github.com/canonical/sphinx-stack/pull/606)
15+
* `.github/workflows/check-removed-urls.yml` [#612](https://github.com/canonical/sphinx-stack/pull/#612)
1416

1517
## 2.0
1618

docs/_dev/check_removed_urls.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#! /usr/bin/env python
2+
3+
"""Check for removed URLs and verify if redirects exist."""
4+
5+
import csv
6+
import io
7+
import sys
8+
from pathlib import Path
9+
10+
11+
def read_urls(path):
12+
return {
13+
line.strip()
14+
for line in path.read_text(encoding="utf-8").splitlines()
15+
if line.strip()
16+
}
17+
18+
19+
def read_redirect_sources(path):
20+
sources = set()
21+
22+
if not path.exists():
23+
return sources
24+
25+
for raw_line in path.read_text(encoding="utf-8").splitlines():
26+
line = raw_line.strip()
27+
if not line or line.startswith("#"):
28+
continue
29+
30+
fields = next(
31+
csv.reader(
32+
io.StringIO(line),
33+
delimiter=" ",
34+
quotechar='"',
35+
skipinitialspace=True,
36+
),
37+
[],
38+
)
39+
if fields:
40+
sources.add(fields[0])
41+
42+
return sources
43+
44+
45+
def source_candidates_for_url(url):
46+
clean_path = url.strip()
47+
clean_path = clean_path.removeprefix("./")
48+
clean_path = clean_path.removeprefix("/")
49+
clean_path = clean_path.removesuffix(".html")
50+
clean_path = clean_path.rstrip("/")
51+
52+
if not clean_path:
53+
return {"index.md"}
54+
55+
# A removed dirhtml URL can map back to either a page file or an
56+
# index file. Directory-level redirects are stored with a trailing
57+
# slash, so include that form too.
58+
return {
59+
f"{clean_path}.md",
60+
f"{clean_path}/index.md",
61+
f"{clean_path}/",
62+
}
63+
64+
65+
def main():
66+
base_urls = Path("base/docs/urls.txt")
67+
compare_urls = Path("compare/docs/urls.txt")
68+
redirects = Path("compare/docs/redirects.txt")
69+
70+
if not base_urls.exists():
71+
print(f"Error: Base URLs file not found at {base_urls}")
72+
sys.exit(1)
73+
if not compare_urls.exists():
74+
print(f"Error: Compare URLs file not found at {compare_urls}")
75+
sys.exit(1)
76+
77+
removed_urls = sorted(read_urls(base_urls) - read_urls(compare_urls))
78+
redirect_sources = read_redirect_sources(redirects)
79+
80+
missing_redirects = [
81+
url
82+
for url in removed_urls
83+
if source_candidates_for_url(url).isdisjoint(redirect_sources)
84+
]
85+
86+
if missing_redirects:
87+
print("The following URLs were removed without redirects:")
88+
print("\n".join(missing_redirects))
89+
print("Please ensure removed pages are redirected")
90+
sys.exit(1)
91+
92+
if removed_urls:
93+
print("Removed URLs have redirects:")
94+
print("\n".join(removed_urls))
95+
96+
97+
if __name__ == "__main__":
98+
main()

0 commit comments

Comments
 (0)