9
9
10
10
from bugbot .bzcleaner import BzCleaner
11
11
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
+ )
12
28
13
29
14
30
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
17
45
self .extra_ni = {}
18
46
19
47
def description (self ):
@@ -28,6 +56,7 @@ def columns(self):
28
56
"resolution" ,
29
57
"resolution_comment" ,
30
58
"resolution_previous" ,
59
+ "needinfo" ,
31
60
]
32
61
33
62
def get_extra_for_needinfo_template (self ):
@@ -87,6 +116,56 @@ def should_needinfo(self, bug_comments, status_time):
87
116
88
117
return True
89
118
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
+
90
169
def get_resolution_history (self , bug ):
91
170
bug_info = {}
92
171
@@ -165,17 +244,13 @@ def handle_bug(self, bug, data):
165
244
bug_comments = bug ["comments" ]
166
245
bug_history = self .get_resolution_history (bug )
167
246
168
- # Sometimes a resolution comment is not provided so use a default
169
247
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"
179
254
bug_history ["needinfo" ] = self .should_needinfo (
180
255
bug_comments , bug_history ["status_time" ]
181
256
)
0 commit comments