1212from .nix import Attr
1313from .utils import System , info , link , skipped , system_order_key , to_link , warn
1414
15+ # https://github.com/orgs/community/discussions/27190
16+ MAX_GITHUB_COMMENT_LENGTH = 65536
17+
1518
1619def get_log_filename (a : Attr , system : str ) -> str :
1720 return f"{ a .name } -{ system } .log"
1821
1922
23+ def get_log_dir (root : Path ) -> Path :
24+ return root / "logs"
25+
26+
2027def print_number (
2128 logs_dir : Path ,
2229 system : str ,
@@ -59,6 +66,28 @@ def html_pkgs_section(
5966 return res
6067
6168
69+ def get_file_tail (file : Path , lines : int = 20 ) -> str :
70+ try :
71+ with file .open ("rb" ) as f :
72+ f .seek (0 , os .SEEK_END )
73+ end = f .tell ()
74+ f .seek (max (end - lines * 1024 , 0 ), os .SEEK_SET )
75+ return "\n " .join (
76+ f .read ().decode ("utf-8" , errors = "replace" ).splitlines ()[- lines :]
77+ )
78+ except OSError :
79+ return ""
80+
81+
82+ def html_logs_section (logs_dir : Path , packages : list [Attr ], system : str ) -> str :
83+ res = ""
84+ for pkg in packages :
85+ tail = get_file_tail (logs_dir / get_log_filename (pkg , system ))
86+ if tail :
87+ res += f"<details>\n <summary>{ pkg .name } </summary>\n <pre>{ tail } </pre>\n </details>\n "
88+ return res
89+
90+
6291class LazyDirectory :
6392 def __init__ (self , path : Path ) -> None :
6493 self .path = path
@@ -112,7 +141,7 @@ def write_error_logs(
112141 * ,
113142 max_workers : int | None = 1 ,
114143) -> None :
115- logs = LazyDirectory (directory . joinpath ( "logs" ))
144+ logs = LazyDirectory (get_log_dir ( directory ))
116145 results = LazyDirectory (directory .joinpath ("results" ))
117146 failed_results = LazyDirectory (directory .joinpath ("failed_results" ))
118147
@@ -242,11 +271,13 @@ def __init__(
242271 skip_packages : set [str ],
243272 skip_packages_regex : list [Pattern [str ]],
244273 show_header : bool = True ,
274+ show_logs : bool = False ,
245275 max_workers : int | None = 1 ,
246276 * ,
247277 checkout : Literal ["merge" , "commit" ] = "merge" ,
248278 ) -> None :
249279 self .show_header = show_header
280+ self .show_logs = show_logs
250281 self .max_workers = max_workers
251282 self .attrs = attrs_per_system
252283 self .checkout = checkout
@@ -272,10 +303,10 @@ def built_packages(self) -> dict[System, list[str]]:
272303 }
273304
274305 def write (self , directory : Path , pr : int | None ) -> None :
275- directory .joinpath ("report.md" ).write_text (self .markdown (pr ))
276- directory .joinpath ("report.json" ).write_text (self .json (pr ))
277-
306+ # write logs first because snippets from them may be needed for the report
278307 write_error_logs (self .attrs , directory , max_workers = self .max_workers )
308+ directory .joinpath ("report.md" ).write_text (self .markdown (directory , pr ))
309+ directory .joinpath ("report.json" ).write_text (self .json (pr ))
279310
280311 def succeeded (self ) -> bool :
281312 """Whether the report is considered a success or a failure"""
@@ -301,7 +332,7 @@ def json(self, pr: int | None) -> str:
301332 indent = 4 ,
302333 )
303334
304- def markdown (self , pr : int | None ) -> str :
335+ def markdown (self , root : Path , pr : int | None ) -> str :
305336 msg = ""
306337 if self .show_header :
307338 msg += "## `nixpkgs-review` result\n \n "
@@ -346,6 +377,19 @@ def markdown(self, pr: int | None) -> str:
346377 )
347378 msg += html_pkgs_section (":white_check_mark:" , report .built , "built" )
348379
380+ if self .show_logs :
381+ for system , report in self .system_reports .items ():
382+ if not report .failed :
383+ continue
384+ full_msg = msg
385+ full_msg += "\n ---\n "
386+ full_msg += f"### Error logs: `{ system } `\n "
387+ full_msg += html_logs_section (get_log_dir (root ), report .failed , system )
388+ # if the final message won't fit a single github comment, stop
389+ if len (full_msg ) > MAX_GITHUB_COMMENT_LENGTH :
390+ break
391+ msg = full_msg
392+
349393 return msg
350394
351395 def print_console (self , root : Path , pr : int | None ) -> None :
@@ -354,7 +398,7 @@ def print_console(self, root: Path, pr: int | None) -> None:
354398 info ("\n Link to currently reviewing PR:" )
355399 link (to_link (pr_url , pr_url ))
356400
357- logs_dir = root / "logs"
401+ logs_dir = get_log_dir ( root )
358402 for system , report in self .system_reports .items ():
359403 info (f"--------- Report for '{ system } ' ---------" )
360404 p = functools .partial (print_number , logs_dir , system )
0 commit comments