Skip to content

Commit 894fc7f

Browse files
committed
Add tails of logs of failed packages to github comments
Snippets will be hidden under dropdown sections so as not to clutter UI. Snippets are limited to 20 lines, and if too many logs are generated, the report is truncated so that it fits into a single github comment. Signed-off-by: Ihar Hrachyshka <[email protected]>
1 parent 65bbe2d commit 894fc7f

File tree

1 file changed

+47
-6
lines changed

1 file changed

+47
-6
lines changed

nixpkgs_review/report.py

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,18 @@
1212
from .nix import Attr
1313
from .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

1619
def 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+
2027
def 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_failed_section(logs_dir: Path, packages: list[Attr], system: str) -> str:
83+
res = "<details>\n"
84+
for pkg in packages:
85+
tail = get_file_tail(logs_dir / get_log_filename(pkg, system))
86+
res += f" <summary>{pkg.name}</summary>\n<pre>{tail}</pre>\n"
87+
res += "</details>\n"
88+
return res
89+
90+
6291
class 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

@@ -272,10 +301,10 @@ def built_packages(self) -> dict[System, list[str]]:
272301
}
273302

274303
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-
304+
# write logs first because snippets from them may be needed for the report
278305
write_error_logs(self.attrs, directory, max_workers=self.max_workers)
306+
directory.joinpath("report.md").write_text(self.markdown(directory, pr))
307+
directory.joinpath("report.json").write_text(self.json(pr))
279308

280309
def succeeded(self) -> bool:
281310
"""Whether the report is considered a success or a failure"""
@@ -301,7 +330,7 @@ def json(self, pr: int | None) -> str:
301330
indent=4,
302331
)
303332

304-
def markdown(self, pr: int | None) -> str:
333+
def markdown(self, root: Path, pr: int | None) -> str:
305334
msg = ""
306335
if self.show_header:
307336
msg += "## `nixpkgs-review` result\n\n"
@@ -346,6 +375,18 @@ def markdown(self, pr: int | None) -> str:
346375
)
347376
msg += html_pkgs_section(":white_check_mark:", report.built, "built")
348377

378+
for system, report in self.system_reports.items():
379+
if not report.failed:
380+
continue
381+
full_msg = msg
382+
full_msg += "\n---\n"
383+
full_msg += f"### Error logs: `{system}`\n"
384+
full_msg += html_failed_section(get_log_dir(root), report.failed, system)
385+
# if the final message won't fit a single github comment, stop
386+
if len(full_msg) > MAX_GITHUB_COMMENT_LENGTH:
387+
break
388+
msg = full_msg
389+
349390
return msg
350391

351392
def print_console(self, root: Path, pr: int | None) -> None:
@@ -354,7 +395,7 @@ def print_console(self, root: Path, pr: int | None) -> None:
354395
info("\nLink to currently reviewing PR:")
355396
link(to_link(pr_url, pr_url))
356397

357-
logs_dir = root / "logs"
398+
logs_dir = get_log_dir(root)
358399
for system, report in self.system_reports.items():
359400
info(f"--------- Report for '{system}' ---------")
360401
p = functools.partial(print_number, logs_dir, system)

0 commit comments

Comments
 (0)