diff --git a/.github/workflows/check-removed-urls.yml b/.github/workflows/check-removed-urls.yml index b2fab02..c261aad 100644 --- a/.github/workflows/check-removed-urls.yml +++ b/.github/workflows/check-removed-urls.yml @@ -2,13 +2,6 @@ name: Check for removed URLs on: workflow_call: - inputs: - base_ref: - required: false - type: string - base_repo: - required: false - type: string pull_request: branches: [main] @@ -28,8 +21,8 @@ jobs: - name: Checkout base branch uses: actions/checkout@v5 with: - ref: ${{ inputs.base_ref || github.event.pull_request.base.ref }} - repository: ${{ inputs.base_repo || github.event.pull_request.base.repo.full_name }} + ref: ${{ github.event.pull_request.base.ref }} + repository: ${{ github.event.pull_request.base.repo.full_name }} fetch-depth: 0 path: base - uses: actions/setup-python@v6 @@ -56,83 +49,4 @@ jobs: | sort > "${urls_file}" done - name: Compare URLs - run: | - python3 - <<'PY' - from pathlib import Path - import csv - import io - - base_urls_path = Path("base/docs/urls.txt") - compare_urls_path = Path("compare/docs/urls.txt") - redirects_path = Path("compare/docs/redirects.txt") - - def read_urls(path): - return { - line.strip() - for line in path.read_text(encoding="utf-8").splitlines() - if line.strip() - } - - def read_redirect_sources(path): - sources = set() - - if not path.exists(): - return sources - - for raw_line in path.read_text(encoding="utf-8").splitlines(): - line = raw_line.strip() - if not line or line.startswith("#"): - continue - - fields = next( - csv.reader( - io.StringIO(line), - delimiter=" ", - quotechar='"', - skipinitialspace=True, - ), - [], - ) - if fields: - sources.add(fields[0]) - - return sources - - def source_candidates_for_url(url): - clean_path = url.strip() - clean_path = clean_path.removeprefix("./") - clean_path = clean_path.removeprefix("/") - clean_path = clean_path.removesuffix(".html") - clean_path = clean_path.rstrip("/") - - if not clean_path: - return {"index.md"} - - # A removed dirhtml URL can map back to either a page file or an - # index file. Directory-level redirects are stored with a trailing - # slash, so include that form too. - return { - f"{clean_path}.md", - f"{clean_path}/index.md", - f"{clean_path}/", - } - - removed_urls = sorted(read_urls(base_urls_path) - read_urls(compare_urls_path)) - redirect_sources = read_redirect_sources(redirects_path) - - missing_redirects = [ - url - for url in removed_urls - if source_candidates_for_url(url).isdisjoint(redirect_sources) - ] - - if missing_redirects: - print("The following URLs were removed without redirects:") - print("\n".join(missing_redirects)) - print("Please ensure removed pages are redirected") - raise SystemExit(1) - - if removed_urls: - print("Removed URLs have redirects:") - print("\n".join(removed_urls)) - PY + run: python3 compare/docs/_dev/check_removed_urls.py diff --git a/.github/workflows/cla-check.yml b/.github/workflows/cla-check.yml index 56b465c..7de3076 100644 --- a/.github/workflows/cla-check.yml +++ b/.github/workflows/cla-check.yml @@ -5,6 +5,10 @@ on: pull_request: branches: [main] +permissions: + contents: read + pull-requests: read + jobs: cla-check: runs-on: ubuntu-latest diff --git a/docs/_dev/check_removed_urls.py b/docs/_dev/check_removed_urls.py new file mode 100755 index 0000000..2652398 --- /dev/null +++ b/docs/_dev/check_removed_urls.py @@ -0,0 +1,98 @@ +#! /usr/bin/env python + +"""Check for removed URLs and verify if redirects exist.""" + +import csv +import io +import sys +from pathlib import Path + + +def read_urls(path): + return { + line.strip() + for line in path.read_text(encoding="utf-8").splitlines() + if line.strip() + } + + +def read_redirect_sources(path): + sources = set() + + if not path.exists(): + return sources + + for raw_line in path.read_text(encoding="utf-8").splitlines(): + line = raw_line.strip() + if not line or line.startswith("#"): + continue + + fields = next( + csv.reader( + io.StringIO(line), + delimiter=" ", + quotechar='"', + skipinitialspace=True, + ), + [], + ) + if fields: + sources.add(fields[0]) + + return sources + + +def source_candidates_for_url(url): + clean_path = url.strip() + clean_path = clean_path.removeprefix("./") + clean_path = clean_path.removeprefix("/") + clean_path = clean_path.removesuffix(".html") + clean_path = clean_path.rstrip("/") + + if not clean_path: + return {"index.md"} + + # A removed dirhtml URL can map back to either a page file or an + # index file. Directory-level redirects are stored with a trailing + # slash, so include that form too. + return { + f"{clean_path}.md", + f"{clean_path}/index.md", + f"{clean_path}/", + } + + +def main(): + base_urls = Path("base/docs/urls.txt") + compare_urls = Path("compare/docs/urls.txt") + redirects = Path("compare/docs/redirects.txt") + + if not base_urls.exists(): + print(f"Error: Base URLs file not found at {base_urls}") + sys.exit(1) + if not compare_urls.exists(): + print(f"Error: Compare URLs file not found at {compare_urls}") + sys.exit(1) + + removed_urls = sorted(read_urls(base_urls) - read_urls(compare_urls)) + redirect_sources = read_redirect_sources(redirects) + + missing_redirects = [ + url + for url in removed_urls + if source_candidates_for_url(url).isdisjoint(redirect_sources) + ] + + if missing_redirects: + print("The following URLs were removed without redirects:") + print("\n".join(missing_redirects)) + print("Please ensure removed pages are redirected") + sys.exit(1) + + if removed_urls: + print("Removed URLs have redirects:") + print("\n".join(removed_urls)) + + +if __name__ == "__main__": + main() diff --git a/docs/_dev/update_sp.py b/docs/_dev/update_sp.py index 1312921..3014a84 100755 --- a/docs/_dev/update_sp.py +++ b/docs/_dev/update_sp.py @@ -5,7 +5,7 @@ # Requires some manual intervention, but makes identifying updates and differences easier. # # For debugging, please run this script with DEBUGGING=1 -# e.g. user@device:~/git/Canonical/sphinx-stack/docs$ DEBUGGING=1 python .sphinx/update_sp.py +# e.g. user@device:~/git/Canonical/sphinx-stack/docs$ DEBUGGING=1 python _dev/update_sp.py import glob