diff --git a/.github/workflows/navigation-links.yml b/.github/workflows/navigation-links.yml index 2e3b16397..7d18c0508 100644 --- a/.github/workflows/navigation-links.yml +++ b/.github/workflows/navigation-links.yml @@ -26,15 +26,16 @@ jobs: - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 with: python-version: '3.11.16' - - name: Resolve every link from the containing document and check every file-sourced quotation, in both interpreter modes + - name: Resolve every link from the containing document and authenticate every navigation quotation, in both interpreter modes env: PYTHONDONTWRITEBYTECODE: '1' + GITHUB_TOKEN: ${{ github.token }} run: | set -euo pipefail python -B -S tools/check_doc_links.py PROOF_INDEX.md docs/integration/*.md python -B -O -S tools/check_doc_links.py PROOF_INDEX.md docs/integration/*.md - python -B -S tools/check_doc_quotes.py PROOF_INDEX.md docs/integration/2026-09-29-navigation-refresh.md - python -B -O -S tools/check_doc_quotes.py PROOF_INDEX.md docs/integration/2026-09-29-navigation-refresh.md + python -B -S tools/check_doc_quotes.py --github --require-online PROOF_INDEX.md docs/integration/2026-09-29-navigation-refresh.md + python -B -O -S tools/check_doc_quotes.py --github --require-online PROOF_INDEX.md docs/integration/2026-09-29-navigation-refresh.md python -B -S -m unittest -v tests.test_navigation_links tests.test_navigation_quotes python -B -O -S -m unittest -v tests.test_navigation_links tests.test_navigation_quotes git diff --exit-code diff --git a/tests/test_navigation_quotes.py b/tests/test_navigation_quotes.py index 9063797e3..03f6fd8f4 100644 --- a/tests/test_navigation_quotes.py +++ b/tests/test_navigation_quotes.py @@ -89,6 +89,25 @@ def test_github_link_is_unchecked_offline_not_failed(self): self.assertEqual(report['failures'], []) self.assertEqual((report['checked'], report['unchecked_offline']), (0, 1)) + + def test_require_online_rejects_unchecked_github_link(self): + doc = self.root / 'docs' / 'nested' / 'a.md' + doc.write_text(HEADER + '| #1 | [c](https://github.com/o/r/pull/1#issuecomment-2) — “anything at all” |\n', encoding='utf-8') + rc = check_doc_quotes.main([str(doc), '--root', self.tmp, '--require-online']) + self.assertEqual(rc, 1) + + def test_github_transport_failure_is_not_counted_as_offline(self): + doc = self.root / 'docs' / 'nested' / 'a.md' + doc.write_text(HEADER + '| #1 | [c](https://github.com/o/r/pull/1#issuecomment-2) — “anything at all” |\n', encoding='utf-8') + original = check_doc_quotes.Sources._fetch + try: + check_doc_quotes.Sources._fetch = lambda self, match: (None, 'unreachable') + report = check_doc_quotes.check_document(str(doc), self.tmp, github=True, token='x') + finally: + check_doc_quotes.Sources._fetch = original + self.assertEqual(report['unchecked_offline'], 0) + self.assertEqual([f[0] for f in report['failures']], ['source-unreachable']) + def test_nearest_preceding_link_governs_each_passage(self): (self.root / 'reviews' / 's.md').write_text('Disposition: AMEND the ledger.\n', encoding='utf-8') row = ('| #1 | [r](../../reviews/r.md) — “No defect was found.”' diff --git a/tools/check_doc_quotes.py b/tools/check_doc_quotes.py index 1e25a80ba..635505b48 100644 --- a/tools/check_doc_quotes.py +++ b/tools/check_doc_quotes.py @@ -187,14 +187,18 @@ def main(argv=None): parser.add_argument('documents', nargs='+') parser.add_argument('--root', default=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) parser.add_argument('--github', action='store_true', help='also check GitHub review/comment links (GITHUB_TOKEN)') + parser.add_argument('--require-online', action='store_true', help='fail if any linked GitHub/HTTP source is left unchecked offline') args = parser.parse_args(argv) token = os.environ.get('GITHUB_TOKEN') - report = {'root': os.path.realpath(args.root), 'github': args.github, 'documents': {}, 'passed': True} + report = {'root': os.path.realpath(args.root), 'github': args.github, 'require_online': args.require_online, 'documents': {}, 'passed': True} for doc in args.documents: result = check_document(doc, args.root, args.github, token) report['documents'][doc] = result if result['failures']: report['passed'] = False + if args.require_online and result['unchecked_offline']: + result['failures'].append(['unchecked-offline-required', '', str(result['unchecked_offline'])]) + report['passed'] = False print(json.dumps(report, indent=2, sort_keys=True)) return 0 if report['passed'] else 1