|
7 | 7 | import subprocess |
8 | 8 | import sys |
9 | 9 | import time |
| 10 | +from collections import defaultdict |
10 | 11 | from gettext import gettext |
11 | 12 | from typing import IO, Any, Final, NoReturn, Sequence, TextIO |
12 | 13 |
|
@@ -158,11 +159,14 @@ def run_build( |
158 | 159 | formatter = util.FancyFormatter(stdout, stderr, options.hide_error_codes) |
159 | 160 |
|
160 | 161 | messages = [] |
| 162 | + messages_by_file = defaultdict(list) |
161 | 163 |
|
162 | | - def flush_errors(new_messages: list[str], serious: bool) -> None: |
| 164 | + def flush_errors(filename: str | None, new_messages: list[str], serious: bool) -> None: |
163 | 165 | if options.pretty: |
164 | 166 | new_messages = formatter.fit_in_terminal(new_messages) |
165 | 167 | messages.extend(new_messages) |
| 168 | + if new_messages: |
| 169 | + messages_by_file[filename].extend(new_messages) |
166 | 170 | if options.non_interactive: |
167 | 171 | # Collect messages and possibly show them later. |
168 | 172 | return |
@@ -200,7 +204,7 @@ def flush_errors(new_messages: list[str], serious: bool) -> None: |
200 | 204 | ), |
201 | 205 | file=stderr, |
202 | 206 | ) |
203 | | - maybe_write_junit_xml(time.time() - t0, serious, messages, options) |
| 207 | + maybe_write_junit_xml(time.time() - t0, serious, messages, messages_by_file, options) |
204 | 208 | return res, messages, blockers |
205 | 209 |
|
206 | 210 |
|
@@ -1054,6 +1058,12 @@ def add_invertible_flag( |
1054 | 1058 | other_group = parser.add_argument_group(title="Miscellaneous") |
1055 | 1059 | other_group.add_argument("--quickstart-file", help=argparse.SUPPRESS) |
1056 | 1060 | other_group.add_argument("--junit-xml", help="Write junit.xml to the given file") |
| 1061 | + imports_group.add_argument( |
| 1062 | + "--junit-format", |
| 1063 | + choices=["global", "per_file"], |
| 1064 | + default="global", |
| 1065 | + help="If --junit-xml is set, specifies format. global: single test with all errors; per_file: one test entry per file with failures", |
| 1066 | + ) |
1057 | 1067 | other_group.add_argument( |
1058 | 1068 | "--find-occurrences", |
1059 | 1069 | metavar="CLASS.MEMBER", |
@@ -1483,18 +1493,32 @@ def process_cache_map( |
1483 | 1493 | options.cache_map[source] = (meta_file, data_file) |
1484 | 1494 |
|
1485 | 1495 |
|
1486 | | -def maybe_write_junit_xml(td: float, serious: bool, messages: list[str], options: Options) -> None: |
| 1496 | +def maybe_write_junit_xml( |
| 1497 | + td: float, |
| 1498 | + serious: bool, |
| 1499 | + all_messages: list[str], |
| 1500 | + messages_by_file: dict[str | None, list[str]], |
| 1501 | + options: Options, |
| 1502 | +) -> None: |
1487 | 1503 | if options.junit_xml: |
1488 | 1504 | py_version = f"{options.python_version[0]}_{options.python_version[1]}" |
1489 | | - util.write_junit_xml( |
1490 | | - td, serious, messages, options.junit_xml, py_version, options.platform |
1491 | | - ) |
| 1505 | + if options.junit_format == "global": |
| 1506 | + util.write_junit_xml( |
| 1507 | + td, serious, {None: all_messages}, options.junit_xml, py_version, options.platform |
| 1508 | + ) |
| 1509 | + else: |
| 1510 | + # per_file |
| 1511 | + util.write_junit_xml( |
| 1512 | + td, serious, messages_by_file, options.junit_xml, py_version, options.platform |
| 1513 | + ) |
1492 | 1514 |
|
1493 | 1515 |
|
1494 | 1516 | def fail(msg: str, stderr: TextIO, options: Options) -> NoReturn: |
1495 | 1517 | """Fail with a serious error.""" |
1496 | 1518 | stderr.write(f"{msg}\n") |
1497 | | - maybe_write_junit_xml(0.0, serious=True, messages=[msg], options=options) |
| 1519 | + maybe_write_junit_xml( |
| 1520 | + 0.0, serious=True, all_messages=[msg], messages_by_file={None: [msg]}, options=options |
| 1521 | + ) |
1498 | 1522 | sys.exit(2) |
1499 | 1523 |
|
1500 | 1524 |
|
|
0 commit comments