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:
+
+
+
+ | Bug | Summary |
+
+
+
+ {% for i, (bugid, summary) in enumerate(data) -%}
+
+ |
+ {{ bugid }}
+ |
+
+ {{ summary | e }}
+ |
+
+ {% endfor -%}
+
+
+
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