From 738c1c6be13e853c5992022e34dc2ed83c2b390d Mon Sep 17 00:00:00 2001 From: Suhaib Mujahid Date: Thu, 6 Oct 2022 22:45:51 -0400 Subject: [PATCH 1/3] Suggest filing a new bug when an external user commenting on a closed bug --- auto_nag/scripts/closed_comment.py | 73 ++++++++++++++++++++++++++++++ templates/closed_comment.html | 21 +++++++++ 2 files changed, 94 insertions(+) create mode 100644 auto_nag/scripts/closed_comment.py create mode 100644 templates/closed_comment.html diff --git a/auto_nag/scripts/closed_comment.py b/auto_nag/scripts/closed_comment.py new file mode 100644 index 000000000..614421d40 --- /dev/null +++ b/auto_nag/scripts/closed_comment.py @@ -0,0 +1,73 @@ +# 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 auto_nag import utils +from auto_nag.bzcleaner import BzCleaner +from auto_nag.people import People + + +class ClosedComment(BzCleaner): + def __init__(self): + super().__init__() + self.people = People.get_instance() + + def description(self): + return "Closed bugs with a new external comment" + + def handle_bug(self, bug, data): + last_comment = bug["comments"][-1] + if ( + last_comment["creation_time"] <= bug["cf_last_resolved"] + or last_comment["creator"] in (bug["creator"], bug["assigned_to"]) + or self._internal_user(last_comment["creator"]) + or any( + last_comment["creator"] == comment["creator"] + and comment["creation_time"] < bug["cf_last_resolved"] + for comment in bug["comments"] + ) + ): + return None + + return bug + + def _internal_user(self, email): + return ( + email.endswith("@mozilla.com") + or email.endswith("@softvision.com") + or utils.is_bot_email(email) + or self.people.is_mozilla(email) + ) + + def get_bz_params(self, date): + fields = [ + "assigned_to", + "creator", + "cf_last_resolved", + "comments.creator", + "comments.creation_time", + ] + + params = { + "include_fields": fields, + "bug_type": "defect", + "bug_status": "__closed__", + "f1": "cf_last_resolved", + "o1": "greaterthan", + "v1": "-5d", + "n2": 1, + "f2": "longdesc", + "o2": "casesubstring", + "v2": "Please file a new bug", + } + + return params + + def get_autofix_change(self): + return { + "comment": {"body": "This bug is closed. Please file a new bug."}, + } + + +if __name__ == "__main__": + ClosedComment().run() diff --git a/templates/closed_comment.html b/templates/closed_comment.html new file mode 100644 index 000000000..35b8bd303 --- /dev/null +++ b/templates/closed_comment.html @@ -0,0 +1,21 @@ +

The following {{ plural('bug has', data, pword='bugs have') }} an external comment after being closed: + + + + + + + + {% for i, (bugid, summary) in enumerate(data) -%} + + + + + {% endfor -%} + +
BugSummary
+ {{ bugid }} + + {{ summary | e }} +
+

From 8111eb9cc1837e4b815d467706695f4e687ffca6 Mon Sep 17 00:00:00 2001 From: Suhaib Mujahid Date: Fri, 14 Oct 2022 23:36:52 -0400 Subject: [PATCH 2/3] Improve the filtering and customize the comments for duplicate bugs --- auto_nag/scripts/closed_comment.py | 75 ++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 8 deletions(-) diff --git a/auto_nag/scripts/closed_comment.py b/auto_nag/scripts/closed_comment.py index 614421d40..5611f3989 100644 --- a/auto_nag/scripts/closed_comment.py +++ b/auto_nag/scripts/closed_comment.py @@ -2,6 +2,8 @@ # 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 libmozdata.bugzilla import Bugzilla + from auto_nag import utils from auto_nag.bzcleaner import BzCleaner from auto_nag.people import People @@ -17,18 +19,33 @@ def description(self): def handle_bug(self, bug, data): last_comment = bug["comments"][-1] + # Ignore a comment if: + # - has any tag (e.g., spam) + # - was posted before closing the bug + # - was posted by: + # - the bug creator + # - the bug assignee + # - an internal user (e.g., a bot or employee) + # - a participant who previously commented on the bug if ( - last_comment["creation_time"] <= bug["cf_last_resolved"] + last_comment["tags"] + or last_comment["creation_time"] <= bug["cf_last_resolved"] or last_comment["creator"] in (bug["creator"], bug["assigned_to"]) or self._internal_user(last_comment["creator"]) or any( last_comment["creator"] == comment["creator"] - and comment["creation_time"] < bug["cf_last_resolved"] + and comment["creation_time"] <= bug["cf_last_resolved"] for comment in bug["comments"] ) ): return None + bugid = str(bug["id"]) + data[bugid] = { + "dupe_of": bug["dupe_of"], + "is_incomplete": bug["resolution"] == "INCOMPLETE", + } + return bug def _internal_user(self, email): @@ -39,35 +56,77 @@ def _internal_user(self, email): or self.people.is_mozilla(email) ) + def get_bugs(self, date="today", bug_ids=..., chunk_size=None): + bugs = super().get_bugs(date, bug_ids, chunk_size) + + dup_bug_ids = {bug["dupe_of"] for bug in bugs.values() if bug["dupe_of"]} + dup_bug_is_open = {} + if dup_bug_ids: + Bugzilla( + dup_bug_ids, + include_fields=["id", "is_open"], + bughandler=self._handle_dup_bug, + bugdata=dup_bug_is_open, + ).wait() + + for bug_id, bug in list(bugs.items()): + if dup_bug_is_open.get(bug["dupe_of"]): + dupe_of_id = bug["dupe_of"] + self.autofix_changes[bug_id] = { + "comment": { + "body": f"This bug is a duplicate of bug {dupe_of_id}. If you have an input, please comment in bug {dupe_of_id} instead." + }, + } + elif not bug["is_incomplete"]: + self.autofix_changes[bug_id] = { + "comment": { + "body": {"body": "This bug is closed. Please file a new bug."} + }, + } + + return bugs + + def _handle_dup_bug(self, bug, data): + data[bug["id"]] = bug["is_open"] + + def ignore_meta(self): + return True + + def has_access_to_sec_bugs(self): + return False + def get_bz_params(self, date): fields = [ + "resolution", + "dupe_of", "assigned_to", "creator", "cf_last_resolved", "comments.creator", "comments.creation_time", + "comments.tags", ] params = { "include_fields": fields, "bug_type": "defect", "bug_status": "__closed__", + "resolution_type": "notequals", + "resolution": "WONTFIX", "f1": "cf_last_resolved", - "o1": "greaterthan", + "o1": "lessthan", "v1": "-5d", "n2": 1, "f2": "longdesc", "o2": "casesubstring", "v2": "Please file a new bug", + "f3": "longdesc", + "o3": "changedafter", + "v3": "-4d", } return params - def get_autofix_change(self): - return { - "comment": {"body": "This bug is closed. Please file a new bug."}, - } - if __name__ == "__main__": ClosedComment().run() From 906a10d84bcf3f883d98acf17512ff7fad598295 Mon Sep 17 00:00:00 2001 From: Suhaib Mujahid Date: Sat, 15 Oct 2022 14:41:52 -0400 Subject: [PATCH 3/3] Run the tool hourly --- auto_nag/scripts/closed_comment.py | 2 +- runauto_nag_hourly.sh | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/auto_nag/scripts/closed_comment.py b/auto_nag/scripts/closed_comment.py index 5611f3989..d9d9df688 100644 --- a/auto_nag/scripts/closed_comment.py +++ b/auto_nag/scripts/closed_comment.py @@ -122,7 +122,7 @@ def get_bz_params(self, date): "v2": "Please file a new bug", "f3": "longdesc", "o3": "changedafter", - "v3": "-4d", + "v3": "-1d", } return params diff --git a/runauto_nag_hourly.sh b/runauto_nag_hourly.sh index 4ffdf64ee..ec78f22a7 100755 --- a/runauto_nag_hourly.sh +++ b/runauto_nag_hourly.sh @@ -67,6 +67,9 @@ python -m auto_nag.scripts.closed_dupeme --production # Detect spam bugs using bugbug python -m auto_nag.scripts.spambug --production +# Suggest opening a new bug when commenting on a closed bug +python -m auto_nag.scripts.closed_comment --production + # Suggest components for untriaged bugs (hourly, list only bugs on which we acted) python -m auto_nag.scripts.component --frequency hourly --production