1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
"""Given a test name, path to log file and exit code, generate/append an Evergreen report.json."""
import json
import pathlib
import os
from typing import List, Dict, Optional
from typing_extensions import TypedDict
import click
class Result(TypedDict, total=False):
"""Evergreen test result."""
status: str
exit_code: int
test_file: str
start: float
end: float
elapsed: float
log_raw: str
class Report(TypedDict):
"""Evergreen report."""
failures: int
results: List[Result]
def _open_and_truncate_log_lines(log_file: pathlib.Path) -> List[str]:
with open(log_file) as fh:
lines = fh.read().splitlines()
for i, line in enumerate(lines):
if line == "scons: done reading SConscript files.":
offset = i
# if possible, also shave off the current and next line
# as they contain:
# scons: done reading SConscript files.
# scons: Building targets ...
# which is superfluous.
if len(lines) > i + 2:
offset = i + 2
return lines[offset:]
return lines
def _clean_log_file(log_file: pathlib.Path, dedup_lines: bool) -> str:
lines = _open_and_truncate_log_lines(log_file)
if dedup_lines:
lines = _dedup_lines(lines)
return os.linesep.join(lines)
def make_report(test_name: str, log_file_contents: str, exit_code: int) -> Report:
status = "pass" if exit_code == 0 else "fail"
return Report({
'failures':
0 if exit_code == 0 else 1, "results": [
Result({
"status": status, "exit_code": exit_code, "test_file": test_name,
"log_raw": log_file_contents
})
]
})
def try_combine_reports(out: Report):
try:
with open("report.json") as fh:
report = json.load(fh)
out["results"] += report["results"]
out["failures"] += report["failures"]
except NameError:
pass
except IOError:
pass
def _dedup_lines(lines: List[str]) -> List[str]:
return list(set(lines))
def put_report(out: Report):
with open("report.json", "w") as fh:
json.dump(out, fh)
@click.command()
@click.option("--test-name", required=True, type=str)
@click.option("--log-file", required=True, type=pathlib.Path)
@click.option("--exit-code", required=True, type=int)
@click.option("--dedup-lines", is_flag=True)
def main(test_name: str, log_file: pathlib.Path, exit_code: int, dedup_lines: bool):
"""Given a test name, path to log file and exit code, generate/append an Evergreen report.json."""
log_file_contents = _clean_log_file(log_file, dedup_lines)
report = make_report(test_name, log_file_contents, exit_code)
try_combine_reports(report)
put_report(report)
if __name__ == "__main__":
main() # pylint: disable=no-value-for-parameter
|