diff --git a/tools/github_ci_tool.py b/tools/github_ci_tool.py index 8e022d9..7173453 100644 --- a/tools/github_ci_tool.py +++ b/tools/github_ci_tool.py @@ -288,13 +288,7 @@ class GitHubCIHelper(BaseTool): # Inherits from BaseTool # then a line of hyphens, "Traceback (most recent call last):", and the traceback details. # It stops before the next failure block or common summary lines. failure_pattern = re.compile( - r"^(FAIL|ERROR): (.*?)\s*\\((.*?)\\)\s*\ --{5,}\\s*\ -Traceback \\(most recent call last\\):\\s*\ -(.*?)(?=\ -(?:FAIL:|ERROR:)|\ --{5,}\\s*\ -Ran \\d+ tests? in|\\Z)", + r"^(FAIL|ERROR): (.*?)\s*\\((.*?)\\)\s*\n-{5,}\\s*\nTraceback \\(most recent call last\\):\\s*\n(.*?)(?=\n(?:FAIL:|ERROR:)|\n-{5,}\\s*\nRan \\d+ tests? in|\\Z)", re.DOTALL | re.MULTILINE ) @@ -307,12 +301,9 @@ Ran \\d+ tests? in|\\Z)", # Reconstruct a readable failure block failure_block = ( - f"{failure_type}: {test_name} ({test_module_class})\ -" - f"---------------------\ -" - f"Traceback (most recent call last):\ -" + f"{failure_type}: {test_name} ({test_module_class})\n" + f"---------------------\n" + f"Traceback (most recent call last):\n" f"{traceback_details}" ) failures.append(failure_block) @@ -324,20 +315,14 @@ Ran \\d+ tests? in|\\Z)", # Fallback: A more general pattern if the above doesn't match (e.g., due to slight variations in formatting) # This looks for "FAIL:" or "ERROR:", a line for the test name, then captures content until common separators. general_failure_pattern = re.compile( - r"^(FAIL|ERROR): ([^\ -]+)\ -(.*?)(?=\ -(?:FAIL:|ERROR:)|\ --{20,}\ -|Ran \\d+ tests? in|\\Z)", + r"^(FAIL|ERROR): ([^\n]+)\n(.*?)(?=\n(?:FAIL:|ERROR:)|\n-{20,}\n|Ran \\d+ tests? in|\\Z)", re.DOTALL | re.MULTILINE ) for match in general_failure_pattern.finditer(log_content): failure_type = match.group(1) test_header = match.group(2).strip() details = match.group(3).strip() - full_block = f"{failure_type}: {test_header}\ -{details}" + full_block = f"{failure_type}: {test_header}\n{details}" # Avoid adding essentially duplicate or overly broad captures if specific ones exist if not any(f.startswith(f"{failure_type}: {test_header}") for f in failures): failures.append(full_block) @@ -353,14 +338,12 @@ Ran \\d+ tests? in|\\Z)", start_index = log_content.find(summary_marker) if start_index != -1: # Try to find a reasonable end for this summary block - end_pattern = re.compile(r"Ran \\d+ tests? in [\\d\\.]+s|\ --{70,}") + end_pattern = re.compile(r"Ran \\d+ tests? in [\\d\\.]+s|\n-{70,}") end_match = end_pattern.search(log_content, start_index) end_index = end_match.start() if end_match else len(log_content) failure_summary_block = log_content[start_index:end_index].strip() if failure_summary_block: - failures.append(f"FAILURE SUMMARY BLOCK:\ -{failure_summary_block}") + failures.append(f"FAILURE SUMMARY BLOCK:\n{failure_summary_block}") self.logger.info("Captured a general failure summary block.") return failures @@ -400,19 +383,15 @@ if __name__ == "__main__": if isinstance(log_content, str) and not log_content.startswith("Error") and not log_content.startswith("Job") and not log_content.startswith("Failed"): example_logger.info(f"Successfully downloaded logs (length: {len(log_content)} characters).") - example_logger.info("\ ---- Parsing unittest failures ---") + example_logger.info("\n--- Parsing unittest failures ---") failures = helper.parse_unittest_failures_from_log(log_content) if failures: for i, failure_details in enumerate(failures): - print(f"\ -Failure {i+1}:\ -{failure_details}") + print(f"\nFailure {i+1}:\n{failure_details}") else: print("No specific unittest failures parsed by the tool.") # Consider logging the beginning of the log if parsing fails, for debugging the regexes - # print(f"Log start:\ -{log_content[:2000]}") + # print(f"Log start:\n{log_content[:2000]}") elif log_content is None: example_logger.error("Could not retrieve log content (returned None).") else: # If it\'s an error message string from the function itself