Skip to content

Commit

Permalink
Add new rule for monitoring performance alert resolution changes (#2535)
Browse files Browse the repository at this point in the history
Co-authored-by: Suhaib Mujahid <[email protected]>
  • Loading branch information
gmierz and suhaibmujahid authored Nov 18, 2024
1 parent 100a72b commit 8ede0c2
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 0 deletions.
195 changes: 195 additions & 0 deletions bugbot/rules/perfalert_resolved_regression.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.

from datetime import timedelta

from libmozdata import utils as lmdutils
from libmozdata.bugzilla import BugzillaUser

from bugbot.bzcleaner import BzCleaner
from bugbot.constants import BOT_MAIN_ACCOUNT


class PerfAlertResolvedRegression(BzCleaner):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.extra_ni = {}

def description(self):
return "PerfAlert regressions whose resolution has changed recently"

def columns(self):
return [
"id",
"summary",
"status",
"status_author",
"resolution",
"resolution_comment",
"resolution_previous",
]

def get_extra_for_needinfo_template(self):
return self.extra_ni

def get_bz_params(self, date):
end_date = lmdutils.get_date_ymd("today")
start_date = end_date - timedelta(1)

fields = [
"id",
"history",
"comments.text",
"comments.creation_time",
"comments.author",
]

# Find all bugs that have perf-alert, and regression in their keywords. Search
# for bugs that have been changed in the last day. Only look for bugs after
# October 1st, 2024 to prevent triggering comments on older performance regressions
params = {
"include_fields": fields,
"f3": "creation_ts",
"o3": "greaterthan",
"v3": "2024-10-01T00:00:00Z",
"f1": "regressed_by",
"o1": "isnotempty",
"f2": "keywords",
"o2": "allwords",
"v2": ["regression", "perf-alert"],
"f4": "resolution",
"o4": "changedafter",
"v4": start_date,
"f5": "resolution",
"o5": "changedbefore",
"v5": end_date,
}

return params

def should_needinfo(self, bug_comments, status_time):
# Check if the bugbot has already needinfo'ed on the bug since
# the last status change before making one
for comment in bug_comments[::-1]:
if comment["creation_time"] <= status_time:
break

if comment["author"] == BOT_MAIN_ACCOUNT:
if (
"could you provide a comment explaining the resolution?"
in comment["text"]
):
# Bugbot has already commented on this bug since the last
# status change. No need to comment again since this was
# just a resolution change
return False

return True

def get_resolution_history(self, bug):
bug_info = {}

# Get the last resolution change that was made in this bug
for change in bug["history"][::-1]:
# Get the most recent resolution change first, this is because
# it could have changed since the status was changed and by who
if not bug_info.get("resolution"):
for specific_change in change["changes"]:
if specific_change["field_name"] == "resolution":
bug_info["resolution"] = specific_change["added"]
bug_info["resolution_previous"] = (
specific_change["removed"].strip() or "---"
)
bug_info["resolution_time"] = change["when"]
break

if bug_info.get("resolution"):
# Find the status that the bug was resolved to, and by who
for specific_change in change["changes"]:
if specific_change["field_name"] == "status" and specific_change[
"added"
] in ("RESOLVED", "REOPENED"):
bug_info["status"] = specific_change["added"]
bug_info["status_author"] = change["who"]
bug_info["status_time"] = change["when"]
break

if bug_info.get("status"):
break

return bug_info

def set_autofix(self, bugs):
for bug_id, bug_info in bugs.items():
if bug_info["needinfo"]:
self.extra_ni[bug_id] = {
"resolution": bug_info["resolution"],
"status": bug_info["status"],
}
self.add_auto_ni(
bug_id,
{
"mail": bug_info["status_author"],
"nickname": bug_info["nickname"],
},
)

def get_needinfo_nicks(self, bugs):
def _user_handler(user, data):
data[user["name"]] = user["nick"]

authors_to_ni = set()
for bug_id, bug_info in bugs.items():
if bug_info["needinfo"]:
authors_to_ni.add(bug_info["status_author"])

if not authors_to_ni:
return

user_emails_to_names = {}
BugzillaUser(
user_names=list(authors_to_ni),
include_fields=["nick", "name"],
user_handler=_user_handler,
user_data=user_emails_to_names,
).wait()

for bug_id, bug_info in bugs.items():
if bug_info["needinfo"]:
bug_info["nickname"] = user_emails_to_names[bug_info["status_author"]]

def handle_bug(self, bug, data):
# Match all the resolutions with resolution comments if they exist
bug_id = str(bug["id"])
bug_comments = bug["comments"]
bug_history = self.get_resolution_history(bug)

# Sometimes a resolution comment is not provided so use a default
bug_history["needinfo"] = False
bug_history["resolution_comment"] = "N/A"
for comment in bug_comments[::-1]:
if (
comment["creation_time"] == bug_history["status_time"]
and comment["author"] == bug_history["status_author"]
):
bug_history["resolution_comment"] = comment["text"]
break
else:
bug_history["needinfo"] = self.should_needinfo(
bug_comments, bug_history["status_time"]
)

data[bug_id] = bug_history

return bug

def get_bugs(self, *args, **kwargs):
bugs = super().get_bugs(*args, **kwargs)
self.get_needinfo_nicks(bugs)
self.set_autofix(bugs)
return bugs


if __name__ == "__main__":
PerfAlertResolvedRegression().run()
3 changes: 3 additions & 0 deletions configs/rules.json
Original file line number Diff line number Diff line change
Expand Up @@ -472,5 +472,8 @@
},
"perfalert_inactive_regression": {
"additional_receivers": ["[email protected]", "[email protected]"]
},
"perfalert_resolved_regression": {
"additional_receivers": ["[email protected]", "[email protected]"]
}
}
3 changes: 3 additions & 0 deletions scripts/cron_run_daily.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ python -m bugbot.rules.performancebug --production
# Try to detect potential performance alerts that have been inactive for too long
python -m bugbot.rules.perfalert_inactive_regression --production

# Send an email about all performance alerts who were recently resolved
python -m bugbot.rules.perfalert_resolved_regression --production

# Send a mail if the logs are not empty
# MUST ALWAYS BE THE LAST COMMAND
python -m bugbot.log --send
Expand Down
41 changes: 41 additions & 0 deletions templates/perfalert_resolved_regression.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<p>The following bug list contains performance alerts whose resolution has changed in the last week:</p>
<table {{ table_attrs }}>
<thead>
<tr>
<th>Bug</th>
<th>Summary</th>
<th>Status</th>
<th>Resolution</th>
</tr>
</thead>
<tbody>
{% for i, (bugid, summary, status, status_author, resolution, resolution_comment, resolution_previous) in enumerate(data) -%}
<tr {% if i % 2 == 0 %}bgcolor="#E0E0E0"
{% endif -%}
>
<td>
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id={{ bugid }}">{{ bugid }}</a>
</td>
<td>
<table>
<tr>
<td>{{ summary | e }}</td>
</tr>
<tr>
<td>
<b>Resolution Comment:</b> {{ resolution_comment }}
</td>
</tr>
<tr>
<td>
<i>Resolved by {{ status_author }}</i>
</td>
</tr>
</table>
</td>
<td>{{ status }}</td>
<td>{{ resolution_previous }} -> {{ resolution }}</td>
</tr>
{% endfor -%}
</tbody>
</table>
7 changes: 7 additions & 0 deletions templates/perfalert_resolved_regression_needinfo.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
A comment containing a reason for why the performance regression was {{ "resolved as " + extra[bugid]["resolution"] if extra[bugid]["status"].lower() == "resolved" else "reopened" }} could not be found. It should provided when the status of the bug is changed.

:{{ nickname }}, since you resolved this bug, could you provide a comment explaining the resolution? If one has already been provided, this needinfo can be ignored/removed.

If you need additional information/help, reach out in [#perftest](https://matrix.to/#/#perftest:mozilla.org), or [#perfsheriffs](https://matrix.to/#/#perfsheriffs:mozilla.org) on Element.

{{ documentation }}

0 comments on commit 8ede0c2

Please sign in to comment.