Skip to content

Commit 52c83dd

Browse files
committed
HBASE-29888 GitHub Actions job summary should show which tests failed (#7735)
Signed-off-by: Dávid Paksy <paksyd@apache.org>
1 parent 21cda89 commit 52c83dd

File tree

1 file changed

+66
-33
lines changed

1 file changed

+66
-33
lines changed

dev-support/yetus_console_to_md.py

Lines changed: 66 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -170,72 +170,104 @@ def process_first_table(lines: List[str], start_idx: int) -> Tuple[List[str], in
170170
return content, i
171171

172172

173+
SECTION_HEADERS = {
174+
'[ERROR] Failures:': 'failures',
175+
'[ERROR] Errors:': 'errors',
176+
'[WARNING] Flakes:': 'flakes',
177+
}
178+
179+
173180
# TODO: Yetus should support this natively, but docker integration with job summaries doesn't seem
174181
# to work out of the box.
175-
def extract_failed_tests_from_unit_files(output_dir: Path) -> List[Tuple[str, List[str]]]:
182+
def extract_test_results_from_unit_files(
183+
output_dir: Path,
184+
) -> Tuple[List[Tuple[str, List[str]]], List[Tuple[str, List[str]]]]:
176185
"""
177-
Extract failed test names from patch-unit-*.txt files.
186+
Extract failed and flaky test names from patch-unit-*.txt files.
178187
179-
Parses Maven surefire output to find lines like:
180-
[ERROR] org.apache.hadoop.hbase.types.TestPBCell.testRoundTrip
188+
Parses Maven surefire summary sections:
189+
[ERROR] Failures: - assertion failures
190+
[ERROR] Errors: - exceptions thrown during test execution
191+
[WARNING] Flakes: - tests that failed on some runs but passed on retry
181192
182193
Returns:
183-
List of (module_name, [failed_test_names]) tuples
194+
Tuple of (failed_tests, flaky_tests) where each is
195+
List of (module_name, [test_names]) tuples
184196
"""
185-
results = []
197+
all_failed = []
198+
all_flaky = []
186199

187200
for unit_file in output_dir.glob('patch-unit-*.txt'):
188201
module_name = unit_file.stem.replace('patch-unit-', '')
189202
failed_tests = set()
203+
flaky_tests = set()
190204

191205
with open(unit_file, 'r') as f:
192-
in_failures_section = False
206+
current_section = None
193207
for line in f:
194208
stripped = line.strip()
195209

196-
if stripped == '[ERROR] Failures:':
197-
in_failures_section = True
210+
if stripped in SECTION_HEADERS:
211+
current_section = SECTION_HEADERS[stripped]
198212
continue
199213

200-
if in_failures_section:
201-
if stripped.startswith('[ERROR]') and not stripped.startswith('[ERROR] Run'):
202-
test_name = stripped.replace('[ERROR] ', '').strip()
214+
if stripped.startswith('[ERROR] Tests run:'):
215+
current_section = None
216+
continue
217+
218+
if current_section is None:
219+
continue
220+
221+
if re.match(r'\[(ERROR|INFO)]\s+Run \d+:', stripped):
222+
continue
223+
if stripped.startswith('[INFO]') or not stripped:
224+
continue
225+
226+
if current_section in ('failures', 'errors'):
227+
if stripped.startswith('[ERROR]'):
228+
test_name = stripped[len('[ERROR]'):].strip()
203229
if test_name and '.' in test_name:
204230
failed_tests.add(test_name)
205-
elif stripped.startswith('[INFO]') or not stripped:
206-
in_failures_section = False
231+
elif current_section == 'flakes':
232+
if stripped.startswith('[WARNING]'):
233+
test_name = stripped[len('[WARNING]'):].strip()
234+
if test_name and '.' in test_name:
235+
flaky_tests.add(test_name)
207236

208237
if failed_tests:
209-
results.append((module_name, sorted(failed_tests)))
238+
all_failed.append((module_name, sorted(failed_tests)))
239+
if flaky_tests:
240+
all_flaky.append((module_name, sorted(flaky_tests)))
210241

211-
return results
242+
return all_failed, all_flaky
212243

213244

214-
def format_failed_tests_section(failed_tests: List[Tuple[str, List[str]]]) -> List[str]:
215-
"""
216-
Format failed tests into markdown.
217-
218-
Args:
219-
failed_tests: List of (module_name, [test_names]) tuples
220-
221-
Returns:
222-
List of markdown lines
223-
"""
224-
if not failed_tests:
245+
def _format_test_table(
246+
heading: str, tests: List[Tuple[str, List[str]]], column_name: str
247+
) -> List[str]:
248+
if not tests:
225249
return []
226250

227251
content = []
228-
content.append('\n## ❌ Failed Tests\n\n')
229-
content.append('| Module | Failed Tests |\n')
252+
content.append(f'\n## {heading}\n\n')
253+
content.append(f'| Module | {column_name} |\n')
230254
content.append('|--------|-------------|\n')
231255

232-
for module_name, tests in failed_tests:
233-
tests_str = ', '.join(tests)
234-
content.append(f'| {module_name} | {tests_str} |\n')
256+
for module_name, names in tests:
257+
for name in names:
258+
content.append(f'| {module_name} | {name} |\n')
235259

236260
return content
237261

238262

263+
def format_failed_tests_section(failed_tests: List[Tuple[str, List[str]]]) -> List[str]:
264+
return _format_test_table('❌ Failed Tests', failed_tests, 'Failed Tests')
265+
266+
267+
def format_flaky_tests_section(flaky_tests: List[Tuple[str, List[str]]]) -> List[str]:
268+
return _format_test_table('⚠️ Flaky Tests (passed on retry)', flaky_tests, 'Flaky Tests')
269+
270+
239271
def process_second_table(lines: List[str], start_idx: int) -> Tuple[List[str], int]:
240272
"""
241273
Process the second table (Subsystem, Report/Notes).
@@ -306,8 +338,9 @@ def convert_console_to_markdown(input_file: str, output_file: Optional[str] = No
306338

307339
# Extract and add failed tests from patch-unit-*.txt files
308340
if not added_failed_tests:
309-
failed_tests = extract_failed_tests_from_unit_files(output_dir)
341+
failed_tests, flaky_tests = extract_test_results_from_unit_files(output_dir)
310342
content.extend(format_failed_tests_section(failed_tests))
343+
content.extend(format_flaky_tests_section(flaky_tests))
311344
added_failed_tests = True
312345
continue
313346

0 commit comments

Comments
 (0)