bugbot/rules/moved_to_performance.py (130 lines of code) (raw):
# 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/.
import base64
import json
from datetime import timedelta
from typing import Dict
from libmozdata import utils as lmdutils
from bugbot.bzcleaner import BzCleaner
class MovedToPerformance(BzCleaner):
"""Add a comment to bugs that recently moved to the performance component"""
def __init__(self, recent_date_weeks: int = 26):
"""Constructor
Args:
recent_date_weeks: Number of weeks to consider when looking for
recent data (e.g. profiler links and memory reports)
"""
super().__init__()
self.ni_extra: Dict[str, dict] = {}
self.recent_date_limit = lmdutils.get_date_str(
lmdutils.get_date_ymd("today") - timedelta(weeks=recent_date_weeks)
)
def description(self):
return "Bugs that recently moved to the performance component"
def get_extra_for_needinfo_template(self):
return self.ni_extra
def handle_bug(self, bug, data):
bugid = str(bug["id"])
has_profiler_link = any(
"https://share.firefox.dev/" in comment["text"]
for comment in bug["comments"]
if comment["creator"] == bug["creator"]
and comment["creation_time"] > self.recent_date_limit
)
has_memory_report = any(
self._is_memory_report_file(attachment)
for attachment in bug["attachments"]
if attachment["creator"] == bug["creator"]
and attachment["creation_time"] > self.recent_date_limit
and not attachment["is_obsolete"]
and not attachment["is_patch"]
)
has_troubleshooting_info = any(
self._is_troubleshooting_content(attachment)
for attachment in bug["attachments"]
if attachment["creator"] == bug["creator"]
and attachment["creation_time"] > self.recent_date_limit
and not attachment["is_obsolete"]
and not attachment["is_patch"]
)
if has_profiler_link and has_memory_report and has_troubleshooting_info:
# Nothing missing, no need to add a comment
return None
self.ni_extra[bugid] = {
"has_profiler_link": has_profiler_link,
"has_memory_report": has_memory_report,
"has_troubleshooting_info": has_troubleshooting_info,
}
return bug
@staticmethod
def _is_memory_report_file(attachment):
return (
attachment["content_type"]
in (
"application/gzip",
"application/x-gzip",
"application/json",
)
and "memory-report" in attachment["file_name"]
)
@staticmethod
def _is_troubleshooting_content(attachment):
if (
attachment["content_type"]
not in (
"application/json",
"text/plain",
)
or "memory-report" in attachment["file_name"]
):
return False
content_bytes = base64.b64decode(attachment["data"])
try:
content = json.loads(content_bytes)
except ValueError:
return False
return all(
key in content
for key in (
"application",
"processes",
"addons",
"startupCache",
"modifiedPreferences",
)
)
def ignore_meta(self):
return True
def get_mail_to_auto_ni(self, bug):
return {"mail": bug["creator"], "nickname": bug["creator_detail"]["nick"]}
def get_bz_params(self, date):
fields = [
"creator",
"attachments.is_obsolete",
"attachments.is_patch",
"attachments.content_type",
"attachments.data",
"attachments.file_name",
"attachments.creator",
"attachments.creation_time",
"comments.text",
"comments.creator",
"comments.creation_time",
"url",
]
params = {
"include_fields": fields,
"resolution": "---",
"bug_type": "defect",
"f1": "product",
"o1": "equals",
"v1": "Core",
"f2": "component",
"o2": "equals",
"v2": "Performance",
"f3": "component",
"o3": "changedafter",
"v3": "-7d",
"n4": 1,
"f4": "component",
"o4": "changedafter",
"v4": "-1d",
"n5": 1,
"f5": "longdesc",
"o5": "casesubstring",
"v5": "could you make sure the following information is on this bug?",
}
return params
if __name__ == "__main__":
MovedToPerformance().run()