99
1010from bugbot .bzcleaner import BzCleaner
1111from 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
1430class 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 )
0 commit comments