Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/scripts/ci_summarizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import sys
import re

def parse_ci_log(log_file_path):
"""
Reads a CI text log and extracts errors and failed tests.
"""
errors_found = []

try:
with open(log_file_path, 'r', encoding='utf-8') as file:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

CI logs can sometimes contain invalid UTF-8 byte sequences (e.g., from compiler warnings, binary outputs, or localized tools). Opening the file with strict UTF-8 decoding can cause the script to crash with a UnicodeDecodeError, preventing the summary from being generated.

Using errors='replace' or errors='ignore' ensures the script remains robust and processes the entire log file successfully.

Suggested change
with open(log_file_path, 'r', encoding='utf-8') as file:
with open(log_file_path, 'r', encoding='utf-8', errors='replace') as file:

for line in file:
# Search for lines containing the word 'error'
if re.search(r'\berror\b', line, re.IGNORECASE):
errors_found.append(line.strip())

# Search for lines indicating a failed test
elif 'FAIL:' in line:
errors_found.append(line.strip())

except FileNotFoundError:
print(f"Error: Could not find log file at {log_file_path}")
return
Comment on lines +21 to +23

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the log file is not found, the script prints an error message to standard output (stdout) and exits with a successful status code (0). In CI/CD environments, execution failures should be printed to standard error (stderr) and exit with a non-zero status code (e.g., 1) to properly signal the failure to the calling pipeline.

Suggested change
except FileNotFoundError:
print(f"Error: Could not find log file at {log_file_path}")
return
except FileNotFoundError:
print(f"Error: Could not find log file at {log_file_path}", file=sys.stderr)
sys.exit(1)


# Format the output nicely using Markdown
print("### 🚨 CI Failure Summary")
if not errors_found:
print("No explicit errors found in the log.")
else:
print(f"Found {len(errors_found)} critical issues:")
for err in errors_found[:10]: # Cap at 10 to avoid spamming the PR
print(f"- `{err}`")

# This allows the script to be run directly from the command line
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python3 ci_summarizer.py <path_to_log_file>")
else:
parse_ci_log(sys.argv[1])
Comment on lines +36 to +39

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When the script is invoked with incorrect arguments, it prints the usage message to standard output (stdout) and exits with a successful status code (0). CLI usage errors should be printed to standard error (stderr) and exit with a non-zero status code (e.g., 1) to prevent silent failures in pipelines.

Suggested change
if len(sys.argv) < 2:
print("Usage: python3 ci_summarizer.py <path_to_log_file>")
else:
parse_ci_log(sys.argv[1])
if len(sys.argv) < 2:
print("Usage: python3 ci_summarizer.py <path_to_log_file>", file=sys.stderr)
sys.exit(1)
else:
parse_ci_log(sys.argv[1])