1616 Optional ,
1717 Tuple ,
1818)
19+ import argparse
1920
2021import nox
22+ import requests # type: ignore
2123from nox import Session
22- from requests import (
23- get ,
24- head ,
25- )
26- from requests .exceptions import Timeout
2724
2825from exasol .toolbox .nox ._shared import DOCS_OUTPUT_DIR
2926from noxconfig import (
3431
3532def _build_docs (session : nox .Session , config : Config ) -> None :
3633 session .run (
37- "poetry" ,
38- "run" ,
3934 "sphinx-build" ,
4035 "-W" ,
4136 "-b" ,
@@ -47,15 +42,34 @@ def _build_docs(session: nox.Session, config: Config) -> None:
4742
4843def _build_multiversion_docs (session : nox .Session , config : Config ) -> None :
4944 session .run (
50- "poetry" ,
51- "run" ,
5245 "sphinx-multiversion" ,
5346 f"{ config .doc } " ,
5447 DOCS_OUTPUT_DIR ,
5548 )
5649 session .run ("touch" , f"{ DOCS_OUTPUT_DIR } /.nojekyll" )
5750
5851
52+ def _check_failed_links (results : list [str ]):
53+ errors = []
54+ for line , result in enumerate (results ):
55+ if result .startswith ("{" ) and "}" in result :
56+ data = json .loads (result )
57+ if not (data ["status" ] == "working" ) or (data ["status" ] == "ignored" ):
58+ match = re .search (r"https?://[^\s\"\'<>]+" , data ["uri" ])
59+ if match :
60+ try :
61+ request = requests .head (match .group (), timeout = 15 )
62+ if request .status_code == 200 :
63+ data ["status" ] = "working"
64+ data ["code" ] = request .status_code
65+ results [line ] = json .dumps (data )
66+ except requests .exceptions .Timeout :
67+ pass
68+ if (data ["status" ] == "broken" ) or data ["status" ] == "timeout" :
69+ errors .append (result )
70+ return results , errors
71+
72+
5973def _git_diff_changes_main () -> int :
6074 """
6175 Check if doc/changes is changed and return the exit code of command git diff.
@@ -108,25 +122,18 @@ def clean_docs(_session: Session) -> None:
108122@nox .session (name = "docs:links" , python = False )
109123def docs_list_links (session : Session ) -> None :
110124 """List all the links within the documentation."""
111- ignore = [r".*" ]
112- env = os .environ .copy ()
113- env ["SPHINX_EXTRA_LINKCHECK_IGNORES" ] = "," .join (ignore )
114125 with tempfile .TemporaryDirectory () as path :
115126 tmpdir = Path (path )
116127 sp = subprocess .run (
117128 [
118- "poetry" ,
119- "run" ,
120- "--" ,
121129 "sphinx-build" ,
122130 "-b" ,
123131 "linkcheck" ,
132+ "-D" ,
133+ "linkcheck_ignore=.*" ,
124134 PROJECT_CONFIG .root / "doc" ,
125135 tmpdir ,
126136 ],
127- capture_output = True ,
128- text = True ,
129- env = env ,
130137 )
131138 print (sp .returncode )
132139 if sp .returncode >= 2 :
@@ -151,65 +158,43 @@ def docs_list_links(session: Session) -> None:
151158@nox .session (name = "docs:links:check" , python = False )
152159def docs_links_check (session : Session ) -> None :
153160 """Checks whether all links in the documentation are accessible."""
154- ignore = [r"https?://" ]
155- env = os .environ .copy ()
156- env ["SPHINX_EXTRA_LINKCHECK_IGNORES" ] = "," .join (ignore )
161+ parser = argparse .ArgumentParser (
162+ prog = "nox -s release:prepare" ,
163+ usage = "nox -s release:prepare -- [-h] [-o |--output]" ,
164+ formatter_class = argparse .ArgumentDefaultsHelpFormatter ,
165+ )
166+ parser .add_argument (
167+ "-o" ,
168+ "--output" ,
169+ type = Path ,
170+ help = "path to output file" ,
171+ default = "" ,
172+ )
173+ args = parser .parse_args (session .posargs )
157174 with tempfile .TemporaryDirectory () as path :
158175 tmpdir = Path (path )
159176 sp = subprocess .run (
160177 [
161- "poetry" ,
162- "run" ,
163- "--" ,
164178 "sphinx-build" ,
165179 "-b" ,
166180 "linkcheck" ,
167181 PROJECT_CONFIG .root / "doc" ,
168182 tmpdir ,
169183 ],
170- capture_output = True ,
171- text = True ,
172- env = env ,
173184 )
174- print (sp .returncode )
175185 if sp .returncode >= 2 :
176186 print (sp .stderr )
177187 session .error (2 )
178188 output = tmpdir / "output.json"
179- results = output .read_text ().split ("\n " )
180- reslen = len (results )
181- resstr = results [- 1 ]
182- if (reslen == 0 ) or ((reslen == 1 ) and (resstr == "" )):
183- return
184- elif resstr == "" :
185- results .pop ()
186- for line_nr , result in enumerate (results ):
187- resdict = json .loads (result )
188- if resdict ["status" ] == "ignored" and resdict ["uri" ].startswith ("http" ):
189- try :
190- match = re .search (r"https?://[^\s\"\'<>]+" , resdict ["uri" ])
191- if match :
192- resdict ["uri" ] = match .group ()
193- print (f"{ line_nr } /{ reslen } " )
194- request = head (resdict ["uri" ], timeout = 5 )
195- if request .status_code != 200 :
196- request = get (resdict ["uri" ], timeout = 5 , stream = True )
197- request .close ()
198- if request .status_code >= 400 :
199- resdict ["status" ] = "broken"
200- resdict ["code" ] = request .status_code
201- if request .status_code < 400 :
202- resdict ["status" ] = "working"
203- resdict ["code" ] = request .status_code
204- except Timeout :
205- resdict ["status" ] = "timeout"
206- results [line_nr ] = json .dumps (resdict )
207- output .write_text ("\n " .join (f"{ r } " for r in results ))
208- errors = []
209- for result in results :
210- data = json .loads (result )
211- if (data ["status" ] == "broken" ) or data ["status" ] == "timeout" :
212- errors .append (result )
189+ out = output .read_text ().split ("\n " )
190+ results , errors = _check_failed_links (out )
191+ if hasattr (args , "output" ):
192+ outputfile = Path (args .output ) / "link-check-output.json"
193+ if not outputfile .exists ():
194+ outputfile .parent .mkdir (parents = True , exist_ok = True )
195+ outputfile .touch ()
196+ outputfile .write_text ("\n " .join (result for result in results ))
197+ print (f"file generated at path: { outputfile .resolve ()} " )
213198 if errors :
214199 print ("Error" + "s" if len (errors ) > 1 else "" )
215200 print ("\n " .join (error for error in errors ))
0 commit comments