зеркало из https://github.com/mozilla/bugbot.git
[crash/analyzer] Refactor to use the bug analyzer
This commit is contained in:
Родитель
a507e36b98
Коммит
88fea6fbe5
|
@ -10,6 +10,7 @@ from libmozdata import versions as lmdversions
|
|||
from libmozdata.bugzilla import Bugzilla
|
||||
|
||||
from bugbot import utils
|
||||
from bugbot.components import ComponentName
|
||||
|
||||
|
||||
class VersionStatus(NamedTuple):
|
||||
|
@ -37,6 +38,21 @@ class BugAnalyzer:
|
|||
self._bug = bug
|
||||
self._store = store
|
||||
|
||||
@property
|
||||
def id(self) -> int:
|
||||
"""The bug id."""
|
||||
return self._bug["id"]
|
||||
|
||||
@property
|
||||
def component(self) -> ComponentName:
|
||||
"""The component that the bug is in."""
|
||||
return ComponentName(self._bug["product"], self._bug["component"])
|
||||
|
||||
@property
|
||||
def is_security(self) -> bool:
|
||||
"""Whether the bug is a security bug."""
|
||||
return any("core-security" in group for group in self._bug["groups"])
|
||||
|
||||
@property
|
||||
def regressed_by_bugs(self) -> list["BugAnalyzer"]:
|
||||
"""The bugs that regressed the bug."""
|
||||
|
@ -155,7 +171,7 @@ class BugNotInStoreError(LookupError):
|
|||
class BugsStore:
|
||||
"""A class to retrieve bugs."""
|
||||
|
||||
def __init__(self, bugs: Iterable[dict], versions_map: dict[str, int] = None):
|
||||
def __init__(self, bugs: Iterable[dict] = (), versions_map: dict[str, int] = None):
|
||||
self.bugs = {bug["id"]: BugAnalyzer(bug, self) for bug in bugs}
|
||||
self.versions_map = versions_map
|
||||
|
||||
|
@ -182,16 +198,12 @@ class BugsStore:
|
|||
Args:
|
||||
include_fields: The fields to include when fetching the bugs.
|
||||
"""
|
||||
bug_ids = {
|
||||
bug_ids = (
|
||||
bug_id
|
||||
for bug in self.bugs.values()
|
||||
if bug.get_field("regressed_by")
|
||||
for bug_id in bug.get_field("regressed_by")
|
||||
if bug_id not in self.bugs
|
||||
}
|
||||
|
||||
if not bug_ids:
|
||||
return
|
||||
)
|
||||
|
||||
self.fetch_bugs(bug_ids, include_fields)
|
||||
|
||||
|
@ -202,6 +214,17 @@ class BugsStore:
|
|||
bug_ids: The ids of the bugs to fetch.
|
||||
include_fields: The fields to include when fetching the bugs.
|
||||
"""
|
||||
bug_ids = {
|
||||
bug_id
|
||||
for bug_id in bug_ids
|
||||
# TODO: We only fetch bugs that aren't already in the store.
|
||||
# However, the new fetch request might be specifying fields that
|
||||
# aren't in the existing bug. We need at some point to handle such
|
||||
# cases (currently, we do not have this requirement).
|
||||
if bug_id not in self.bugs
|
||||
}
|
||||
if not bug_ids:
|
||||
return
|
||||
|
||||
def bug_handler(bugs):
|
||||
for bug in bugs:
|
||||
|
|
|
@ -15,6 +15,7 @@ from libmozdata.bugzilla import Bugzilla
|
|||
from libmozdata.connection import Connection
|
||||
|
||||
from bugbot import logger, utils
|
||||
from bugbot.bug.analyzer import BugAnalyzer, BugsStore
|
||||
from bugbot.components import ComponentName
|
||||
from bugbot.crash import socorro_util
|
||||
|
||||
|
@ -119,8 +120,9 @@ class ClouseauDataAnalyzer:
|
|||
MINIMUM_CLOUSEAU_SCORE_THRESHOLD: int = 8
|
||||
DEFAULT_CRASH_COMPONENT = ComponentName("Core", "General")
|
||||
|
||||
def __init__(self, reports: Iterable[dict]):
|
||||
def __init__(self, reports: Iterable[dict], bugs_store: BugsStore):
|
||||
self._clouseau_reports = reports
|
||||
self.bugs_store = bugs_store
|
||||
|
||||
@cached_property
|
||||
def max_clouseau_score(self):
|
||||
|
@ -177,27 +179,22 @@ class ClouseauDataAnalyzer:
|
|||
return None
|
||||
|
||||
@cached_property
|
||||
def regressed_by_potential_bugs(self) -> list[dict]:
|
||||
def regressed_by_potential_bugs(self) -> list[BugAnalyzer]:
|
||||
"""The bugs whose patches could have caused the crash."""
|
||||
|
||||
def handler(bug: dict, data: list):
|
||||
data.append(bug)
|
||||
|
||||
bugs: list[dict] = []
|
||||
Bugzilla(
|
||||
bugids=self.regressed_by_potential_bug_ids,
|
||||
include_fields=[
|
||||
self.bugs_store.fetch_bugs(
|
||||
self.regressed_by_potential_bug_ids,
|
||||
[
|
||||
"id",
|
||||
"groups",
|
||||
"assigned_to",
|
||||
"product",
|
||||
"component",
|
||||
],
|
||||
bughandler=handler,
|
||||
bugdata=bugs,
|
||||
).wait()
|
||||
|
||||
return bugs
|
||||
)
|
||||
return [
|
||||
self.bugs_store.get_bug_by_id(bug_id)
|
||||
for bug_id in self.regressed_by_potential_bug_ids
|
||||
]
|
||||
|
||||
@cached_property
|
||||
def regressed_by_author(self) -> dict | None:
|
||||
|
@ -213,8 +210,8 @@ class ClouseauDataAnalyzer:
|
|||
return None
|
||||
|
||||
bug = self.regressed_by_potential_bugs[0]
|
||||
assert bug["id"] == self.regressed_by
|
||||
return bug["assigned_to_detail"]
|
||||
assert bug.id == self.regressed_by
|
||||
return bug.get_field("assigned_to_detail")
|
||||
|
||||
@cached_property
|
||||
def crash_component(self) -> ComponentName:
|
||||
|
@ -223,8 +220,7 @@ class ClouseauDataAnalyzer:
|
|||
If there are multiple components, the value will be the default one.
|
||||
"""
|
||||
potential_components = {
|
||||
ComponentName(bug["product"], bug["component"])
|
||||
for bug in self.regressed_by_potential_bugs
|
||||
bug.component for bug in self.regressed_by_potential_bugs
|
||||
}
|
||||
if len(potential_components) == 1:
|
||||
return next(iter(potential_components))
|
||||
|
@ -476,9 +472,10 @@ class SignatureAnalyzer(SocorroDataAnalyzer, ClouseauDataAnalyzer):
|
|||
socorro_signature: dict,
|
||||
num_total_crashes: int,
|
||||
clouseau_reports: list[dict],
|
||||
bugs_store: BugsStore,
|
||||
):
|
||||
SocorroDataAnalyzer.__init__(self, socorro_signature, num_total_crashes)
|
||||
ClouseauDataAnalyzer.__init__(self, clouseau_reports)
|
||||
ClouseauDataAnalyzer.__init__(self, clouseau_reports, bugs_store)
|
||||
|
||||
def _fetch_crash_reports(
|
||||
self,
|
||||
|
@ -550,8 +547,7 @@ class SignatureAnalyzer(SocorroDataAnalyzer, ClouseauDataAnalyzer):
|
|||
- one of the potential regressors is a security bug
|
||||
"""
|
||||
return self.is_near_allocator_related_crash or any(
|
||||
any("core-security" in group for group in bug["groups"])
|
||||
for bug in self.regressed_by_potential_bugs
|
||||
bug.is_security for bug in self.regressed_by_potential_bugs
|
||||
)
|
||||
|
||||
|
||||
|
@ -899,12 +895,14 @@ class SignaturesDataFetcher:
|
|||
self._signatures.intersection_update(clouseau_reports.keys())
|
||||
|
||||
signatures, num_total_crashes = self.fetch_socorro_info()
|
||||
bugs_store = BugsStore()
|
||||
|
||||
return [
|
||||
SignatureAnalyzer(
|
||||
signature,
|
||||
num_total_crashes,
|
||||
clouseau_reports[signature["term"]],
|
||||
bugs_store,
|
||||
)
|
||||
for signature in signatures
|
||||
]
|
||||
|
|
Загрузка…
Ссылка в новой задаче