Skip to content

Commit eca15f6

Browse files
add doc:links and docs:links:check (#427)
* add doc:links and docs:links:check * add doc:links and docs:links:check * use sphinx linkcheck * changed docs:links * changed docs:links * changed docs:links * changed docs:links * changed docs:links:check * add test * fix * fix * new version * fix * fix * fix * fix * fix * fix * fix * add tests for doc links * doc * resolve conversation * formatting * fix * fix * fix --------- Co-authored-by: Ariel Schulz <43442541+ArBridgeman@users.noreply.github.com>
1 parent 72ddc53 commit eca15f6

File tree

13 files changed

+257
-11
lines changed

13 files changed

+257
-11
lines changed

.github/workflows/checks.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ jobs:
3939
run: |
4040
poetry run -- nox -s docs:build
4141
42+
- name: Link Check
43+
run: |
44+
poetry run -- nox -s docs:links:check
45+
46+
4247
Changelog:
4348
name: Changelog Update Check
4449
runs-on: ubuntu-24.04

doc/changes/unreleased.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,35 @@
11
# Unreleased
22

3+
## Summary
4+
5+
### Links in the Documentation
6+
This version of the PTB adds nox tasks to check links present in our documentation:
7+
8+
docs:link - List all the links within the documentation
9+
docs:links:check - Checks whether all links in the documentation are accessible
10+
11+
`docs:links:check` is run in the CI `checks.yml`. If this step fails in the CI,
12+
please check the output & manually resolve the issues. There might be some cases
13+
where you need to update your doc/conf.py with specific values for the allowed
14+
options for the [Linkcheck Builder](https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-the-linkcheck-builder).
15+
16+
We recommend the following values be added:
17+
18+
linkcheck_rate_limit_timeout = 60
19+
linkcheck_timeout = 15
20+
linkcheck_delay = 30
21+
linkcheck_retries = 2
22+
linkcheck_anchors = False
23+
linkcheck_ignore: list[str] = []
24+
linkcheck_allowed_redirects = {
25+
# All HTTP redirections from the source URI to
26+
# the canonical URI will be treated as "working".
27+
r"https://github\.com/.*": r"https://github\.com/login*"
28+
}
29+
30+
## ✨ Features
31+
* #409: Doc link & checks
32+
333
## Refactoring
434
* Switched deprecated Pydantic class-based `config` to `ConfigDict`
535

doc/conf.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,15 @@
7878
"github_url": "https://github.com/exasol/python-toolbox",
7979
"accent_color": "grass",
8080
}
81+
# -- Configure link checking behavior ----------------------------------------
82+
linkcheck_rate_limit_timeout = 60
83+
linkcheck_timeout = 15
84+
linkcheck_delay = 30
85+
linkcheck_retries = 2
86+
linkcheck_anchors = False
87+
linkcheck_ignore: list[str] = []
88+
linkcheck_allowed_redirects = {
89+
# All HTTP redirections from the source URI to
90+
# the canonical URI will be treated as "working".
91+
r"https://github\.com/.*": r"https://github\.com/login*"
92+
}

doc/developer_guide/modules/sphinx/sphinx.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ sphinx
44
sphinx-multiversion
55
+++++++++++++++++++
66

7-
The `sphinx-multiversion` extension is a modified copy of `Holzhaus/sphinx-multiversion <https://github.com/Holzhaus/sphinx-multiversion>`_. This copy was taken from version :code:`0.24.0`.
7+
The `sphinx-multiversion` extension is a modified copy of `sphinx-contrib/multiversion <https://github.com/sphinx-contrib/multiversion>`_. This copy was taken from version :code:`0.24.0`.
88

99
It has been adjusted with minor code changes and modified defaults to work seamlessly with Exasol integration projects, which often require a specific project structure and layout. Additionally, it is designed to be used with an HTML theme that supports displaying and selecting multiple versions if the `versions` variable is set in the HTML context of sphinx. As of this writing, the theme used in conjunction with this modified version of `sphinx-multiversion` is `SHIBUYA <https://github.com/lepture/shibuya>`_, version :code:`2024.10.15`.
1010

doc/github_actions/security_issues.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,4 @@ Ideas
112112
.. todo::
113113

114114
Consider adapting common CVE report format as input, for additional details
115-
`see here <https://github.com/CVEProject/cve-schema/blob/master/schema/v5.0/CVE_JSON_5.0_schema.json>`_.
115+
`see here <https://github.com/CVEProject/cve-schema/blob/main/schema/CVE_Record_Format.json>`_.

doc/styleguide/guides/idioms/idioms.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,5 @@ where we picked it up from, rather than the "original" source.
3737

3838

3939
.. _Raymond Hettinger: https://github.com/rhettinger
40-
.. _Transform Code into Beautiful, Idiomatic Python: https://www.youtube.com/watch?v=OSGv2VnC0go>
40+
.. _Transform Code into Beautiful, Idiomatic Python: https://www.youtube.com/watch?v=OSGv2VnC0go
4141
.. _Transform Python Slides: https://speakerdeck.com/pyconslides/transforming-code-into-beautiful-idiomatic-python-by-raymond-hettinger-1

doc/styleguide/guides/style.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ _____
5454
.. _Google Styleguide: https://google.github.io/styleguide/pyguide.html
5555
.. _PEP 8: https://peps.python.org/pep-0008/
5656
.. _Python Idioms: https://gist.github.com/0x4D31/f0b633548d8e0cfb66ee3bea6a0deff9
57-
.. _Python Like You Mean It: http://www.pythonlikeyoumeanit.com/module_2.html>
57+
.. _Python Like You Mean It: http://www.pythonlikeyoumeanit.com/module_2.html
5858
.. _Python Programming Idioms: https://en.wikibooks.org/wiki/Python_Programming/Idioms
5959

60-
.. _Transform Code into Beautiful, Idiomatic Python: https://www.youtube.com/watch?v=OSGv2VnC0go>
60+
.. _Transform Code into Beautiful, Idiomatic Python: https://www.youtube.com/watch?v=OSGv2VnC0go
6161
.. _Transform Python Slides: https://speakerdeck.com/pyconslides/transforming-code-into-beautiful-idiomatic-python-by-raymond-hettinger-1
6262
.. _Stop Writing Classes: https://www.youtube.com/watch?v=o9pEzgHorH0
6363
.. _Refactoring Python: https://www.youtube.com/watch?v=D_6ybDcU5gc

doc/user_guide/features.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ Uniform Project Layout
77
PTB expects a default project layout following "convention over configuration" when possible and reasonable.
88
See the cookie-cutter project template for details, which is part of the python-toolbox workspace and can be found in directory `project-template`.
99
You can also generate a project from the template to explore the default structure.
10-
For more details on this, please check out section `"getting started" <getting_started.html>`_ section.
10+
For more details on this, please check out section :ref:`Getting Started` section.
1111

1212
Nox
1313
---
1414

1515
The most central tool when interacting with the toolbox is :code:`nox`, which is the task runner used across all of Exasol's Python-based projects.
16-
The toolbox itself provides various standard tasks and a plugin mechanism to extend these tasks if needed. For more information regarding nox, please visit the `nox homepage <http://nox.thea.codes/en/stable/>`_.
16+
The toolbox itself provides various standard tasks and a plugin mechanism to extend these tasks if needed. For more information regarding nox, please visit the `nox homepage <https://nox.thea.codes/en/stable/>`_.
1717

1818
Central files in regards to nox and the toolbox are:
1919

doc/user_guide/getting_started.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.. _Getting Started:
2+
13
Getting Started
24
===============
35

exasol/toolbox/nox/_documentation.py

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
from __future__ import annotations
22

3+
import argparse
4+
import json
35
import shutil
46
import subprocess
57
import sys
8+
import tempfile
69
import webbrowser
10+
from pathlib import Path
711

812
import nox
913
from nox import Session
@@ -17,8 +21,6 @@
1721

1822
def _build_docs(session: nox.Session, config: Config) -> None:
1923
session.run(
20-
"poetry",
21-
"run",
2224
"sphinx-build",
2325
"-W",
2426
"-b",
@@ -30,8 +32,6 @@ def _build_docs(session: nox.Session, config: Config) -> None:
3032

3133
def _build_multiversion_docs(session: nox.Session, config: Config) -> None:
3234
session.run(
33-
"poetry",
34-
"run",
3535
"sphinx-multiversion",
3636
f"{config.doc}",
3737
DOCS_OUTPUT_DIR,
@@ -88,6 +88,92 @@ def clean_docs(_session: Session) -> None:
8888
shutil.rmtree(docs_folder)
8989

9090

91+
def _docs_list_links(doc_config: Path):
92+
with tempfile.TemporaryDirectory() as path:
93+
tmpdir = Path(path)
94+
sp = subprocess.run( # nosec
95+
[
96+
"sphinx-build",
97+
"-b",
98+
"linkcheck",
99+
"-D",
100+
"linkcheck_ignore=.*",
101+
doc_config,
102+
tmpdir,
103+
],
104+
capture_output=True,
105+
text=True,
106+
)
107+
if sp.returncode >= 2:
108+
return sp.returncode, sp.stderr
109+
output = tmpdir / "output.json"
110+
links = output.read_text().split("\n")
111+
file_links = []
112+
for link in links:
113+
if link != "":
114+
line = json.loads(link)
115+
if not line["uri"].startswith("#"):
116+
file_links.append(line)
117+
file_links.sort(key=lambda file: file["filename"])
118+
return 0, "\n".join(
119+
f"filename: {fl['filename']}:{fl['lineno']} -> uri: {fl['uri']}"
120+
for fl in file_links
121+
)
122+
123+
124+
def _docs_links_check(doc_config: Path, args):
125+
with tempfile.TemporaryDirectory() as path:
126+
tmpdir = Path(path)
127+
sp = subprocess.run( # nosec
128+
[
129+
"sphinx-build",
130+
"-b",
131+
"linkcheck",
132+
doc_config,
133+
tmpdir,
134+
],
135+
)
136+
if args.output and sp.returncode <= 1:
137+
result_json = tmpdir / "output.json"
138+
dst = Path(args.output) / "link-check-output.json"
139+
shutil.copyfile(result_json, dst)
140+
print(f"file generated at path: {result_json.resolve()}")
141+
return sp.returncode, (
142+
None if sp.returncode >= 2 else (tmpdir / "output.txt").read_text()
143+
)
144+
145+
146+
@nox.session(name="docs:links", python=False)
147+
def docs_list_links(session: Session) -> None:
148+
"""List all the links within the documentation."""
149+
r_code, text = _docs_list_links(PROJECT_CONFIG.doc)
150+
print(text)
151+
if r_code != 0:
152+
session.error()
153+
154+
155+
@nox.session(name="docs:links:check", python=False)
156+
def docs_links_check(session: Session) -> None:
157+
"""Checks whether all links in the documentation are accessible."""
158+
parser = argparse.ArgumentParser(
159+
prog="nox -s docs:links:check",
160+
usage="nox -s docs:links:check -- [-h] [-o |--output]",
161+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
162+
)
163+
parser.add_argument(
164+
"-o", "--output", type=Path, help="path to copy the output json", default=None
165+
)
166+
args = parser.parse_args(session.posargs)
167+
r_code, problems = _docs_links_check(PROJECT_CONFIG.doc, args)
168+
if r_code >= 2:
169+
session.error(2)
170+
if r_code == 1 or problems != "":
171+
escape_red = "\033[31m"
172+
print(escape_red + "errors:")
173+
print(problems)
174+
session.error(1)
175+
176+
91177
@nox.session(name="changelog:updated", python=False)
92178
def updated(_session: Session) -> None:
93179
"""Checks if the change log has been updated"""

0 commit comments

Comments
 (0)