Skip to content

Commit 513c67e

Browse files
authored
Add logic to check deeper for perfalert resolution comments (#2587)
1 parent fda8427 commit 513c67e

File tree

2 files changed

+90
-13
lines changed

2 files changed

+90
-13
lines changed

bugbot/rules/perfalert_resolved_regression.py

+87-12
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,39 @@
99

1010
from bugbot.bzcleaner import BzCleaner
1111
from bugbot.constants import BOT_MAIN_ACCOUNT
12+
from bugbot.utils import is_bot_email
13+
14+
RESOLUTION_KEYWORDS = (
15+
"backedout",
16+
"backed out",
17+
"back out",
18+
"backout",
19+
"wontfix",
20+
"invalid",
21+
"incomplete",
22+
"duplicate",
23+
"fixed",
24+
"resolved",
25+
"resolve",
26+
"resolution",
27+
)
1228

1329

1430
class PerfAlertResolvedRegression(BzCleaner):
15-
def __init__(self, *args, **kwargs):
16-
super().__init__(*args, **kwargs)
31+
def __init__(self, max_seconds_before_status=86400):
32+
"""
33+
Initializes the bugbot rule for ensuring performance alerts
34+
have a valid resolution comment when they are closed.
35+
36+
max_seconds_before_status int: When a resolution comment is not provided
37+
at the time of resolution, the preceding comment can be considered as a
38+
resolution comment as long it hasn't been more than `max_seconds_before_status`
39+
seconds since the comment was made. Only applies when the resolution
40+
author is different from the preceding comment author, otherwise, the
41+
comment is accepted without checking the time that has elapsed.
42+
"""
43+
super().__init__()
44+
self.max_seconds_before_status = max_seconds_before_status
1745
self.extra_ni = {}
1846

1947
def description(self):
@@ -28,6 +56,7 @@ def columns(self):
2856
"resolution",
2957
"resolution_comment",
3058
"resolution_previous",
59+
"needinfo",
3160
]
3261

3362
def get_extra_for_needinfo_template(self):
@@ -87,6 +116,56 @@ def should_needinfo(self, bug_comments, status_time):
87116

88117
return True
89118

119+
def get_resolution_comments(self, comments, status_time):
120+
resolution_comment = None
121+
preceding_comment = None
122+
123+
for comment in comments:
124+
if comment["creation_time"] > status_time:
125+
break
126+
if comment["creation_time"] == status_time:
127+
resolution_comment = comment
128+
if not is_bot_email(comment["author"]):
129+
preceding_comment = comment
130+
131+
return resolution_comment, preceding_comment
132+
133+
def get_resolution_comment(self, comments, bug_history):
134+
status_time = bug_history["status_time"]
135+
resolution_comment, preceding_comment = self.get_resolution_comments(
136+
comments, status_time
137+
)
138+
139+
if (
140+
resolution_comment
141+
and resolution_comment["author"] == bug_history["status_author"]
142+
):
143+
# Accept if status author provided a comment at the same time
144+
return resolution_comment["text"]
145+
if preceding_comment:
146+
if preceding_comment["author"] == bug_history["status_author"]:
147+
# Accept if status author provided a comment before setting
148+
# resolution
149+
return preceding_comment["text"]
150+
151+
preceding_resolution_comment = f"{preceding_comment['text']} (provided by {preceding_comment['author']})"
152+
if any(
153+
keyword in preceding_comment["text"].lower()
154+
for keyword in RESOLUTION_KEYWORDS
155+
):
156+
# Accept if a non-status author provided a comment before a
157+
# resolution was set, and hit some keywords
158+
return preceding_resolution_comment
159+
if (
160+
lmdutils.get_timestamp(status_time)
161+
- lmdutils.get_timestamp(preceding_comment["creation_time"])
162+
) < self.max_seconds_before_status:
163+
# Accept if the previous comment from another author is
164+
# within the time limit
165+
return preceding_resolution_comment
166+
167+
return None
168+
90169
def get_resolution_history(self, bug):
91170
bug_info = {}
92171

@@ -165,17 +244,13 @@ def handle_bug(self, bug, data):
165244
bug_comments = bug["comments"]
166245
bug_history = self.get_resolution_history(bug)
167246

168-
# Sometimes a resolution comment is not provided so use a default
169247
bug_history["needinfo"] = False
170-
bug_history["resolution_comment"] = "N/A"
171-
for comment in bug_comments[::-1]:
172-
if (
173-
comment["creation_time"] == bug_history["status_time"]
174-
and comment["author"] == bug_history["status_author"]
175-
):
176-
bug_history["resolution_comment"] = comment["text"]
177-
break
178-
else:
248+
bug_history["resolution_comment"] = self.get_resolution_comment(
249+
bug_comments, bug_history
250+
)
251+
if bug_history["resolution_comment"] is None:
252+
# Use N/A to signify no resolution comment was provided
253+
bug_history["resolution_comment"] = "N/A"
179254
bug_history["needinfo"] = self.should_needinfo(
180255
bug_comments, bug_history["status_time"]
181256
)

templates/perfalert_resolved_regression.html

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
<th>Summary</th>
77
<th>Status</th>
88
<th>Resolution</th>
9+
<th>Needinfo</th>
910
</tr>
1011
</thead>
1112
<tbody>
12-
{% for i, (bugid, summary, status, status_author, resolution, resolution_comment, resolution_previous) in enumerate(data) -%}
13+
{% for i, (bugid, summary, status, status_author, resolution, resolution_comment, resolution_previous, needinfo) in enumerate(data) -%}
1314
<tr {% if i % 2 == 0 %}bgcolor="#E0E0E0"
1415
{% endif -%}
1516
>
@@ -35,6 +36,7 @@
3536
</td>
3637
<td>{{ status }}</td>
3738
<td>{{ resolution_previous }} -> {{ resolution }}</td>
39+
<td>{{ "Yes" if needinfo else "No"}}</td>
3840
</tr>
3941
{% endfor -%}
4042
</tbody>

0 commit comments

Comments
 (0)