Skip to content

Commit fad8b7c

Browse files
authored
fix: strip color codes and remove empty flake comments (#18664)
- delete the flake comment if no flakes are found - strip ansi characters
2 parents 3791739 + 8b38299 commit fad8b7c

File tree

1 file changed

+36
-9
lines changed

1 file changed

+36
-9
lines changed

scripts/process_flake_log.py

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,24 @@
99

1010
FLAKE_MARKER = "<!-- CI3_FLAKE_DETECTION_COMMENT -->"
1111
TEST_PATTERNS_FILE = ".test_patterns.yml"
12+
# Match ANSI escape sequences:
13+
# - Standard: ESC followed by various control sequences
14+
# - Orphan CSI: [ followed by parameters and command (when ESC is stripped/lost)
15+
# - OSC hyperlink sequences (preserving URL via capture group)
16+
ANSI_ESCAPE_RE = re.compile(
17+
r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~]|\][^\x07\x1B]*(?:\x07|\x1B\\)?)' # Standard ANSI/OSC
18+
r'|\[[0-9;]*m' # Orphan CSI color codes
19+
)
20+
# OSC 8 hyperlink pattern: 8;;URL followed by text and closing 8;;
21+
# Captures the URL to preserve it, removes the control sequences
22+
OSC_HYPERLINK_RE = re.compile(r'8;;(https?://[^\s\uFFFD]*)\uFFFD([^\uFFFD]*)\uFFFD?8;;\uFFFD?')
23+
24+
def strip_ansi_colors(text):
25+
"""Strip ANSI color codes and OSC sequences from text, preserving hyperlink URLs"""
26+
text = ANSI_ESCAPE_RE.sub('', text)
27+
# Convert OSC 8 hyperlinks to just the URL
28+
text = OSC_HYPERLINK_RE.sub(r'\1', text)
29+
return text
1230

1331
def run(cmd, input_data=None):
1432
"""Execute command and return (success, stdout, stderr)"""
@@ -32,10 +50,10 @@ def get_pr_number():
3250
return None
3351

3452
def read_flakes(file_path):
35-
"""Read flake data from file"""
53+
"""Read flake data from file, stripping ANSI color codes"""
3654
try:
3755
with open(file_path, 'r') as f:
38-
lines = [line.strip() for line in f if line.strip()]
56+
lines = [strip_ansi_colors(line.strip()) for line in f if line.strip()]
3957
return lines
4058
except FileNotFoundError:
4159
return []
@@ -48,6 +66,16 @@ def get_comment_id(pr_number):
4866
])
4967
return out.split("\n")[0] if ok and out else None
5068

69+
def delete_comment(pr_number):
70+
"""Delete existing flake comment on PR if it exists"""
71+
if comment_id := get_comment_id(pr_number):
72+
print(f"Deleting comment {comment_id} on PR #{pr_number}")
73+
ok, _, err = run(["gh", "api", f"repos/{{owner}}/{{repo}}/issues/comments/{comment_id}", "-X", "DELETE"])
74+
if not ok:
75+
print(f"Delete failed: {err}")
76+
return ok
77+
return True # No comment to delete is success
78+
5179
def post_comment(pr_number, body):
5280
"""Create or update flake comment on PR"""
5381
if comment_id := get_comment_id(pr_number):
@@ -122,16 +150,10 @@ def check_flake_thresholds(flake_groups_config, flakes_by_group):
122150

123151
return exceeded
124152

125-
def strip_ansi_colors(text):
126-
"""Strip ANSI color codes from text"""
127-
ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
128-
return ansi_escape.sub('', text)
129-
130153
def build_comment(flakes, threshold_exceeded=None):
131154
"""Build markdown comment body from flake list"""
132155
count = len(flakes)
133-
# Strip color codes from flakes for clean markdown display
134-
tests = "\n".join(strip_ansi_colors(flake) for flake in flakes)
156+
tests = "\n".join(flakes)
135157

136158
threshold_warning = ""
137159
if threshold_exceeded:
@@ -156,6 +178,11 @@ def main():
156178
flakes = read_flakes(args.flakes_file)
157179
if not flakes:
158180
print(f"No flaked tests found in {args.flakes_file}")
181+
# Delete existing comment if no flakes found
182+
if args.post_comment:
183+
if pr_number := get_pr_number():
184+
if delete_comment(pr_number):
185+
print(f"Deleted existing flake comment on PR #{pr_number} (no flakes found)")
159186
return 0
160187
print(f"Found {len(flakes)} flaked test(s)")
161188

0 commit comments

Comments
 (0)