• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mozilla / relman-auto-nag / #4458

pending completion
#4458

push

coveralls-python

web-flow
[needinfo_regression_author] Don't needinfo when the needinfo is blocked (#2044)

639 of 3205 branches covered (19.94%)

2 of 2 new or added lines in 1 file covered. (100.0%)

1816 of 8004 relevant lines covered (22.69%)

0.23 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/bugbot/rules/needinfo_regression_author.py
1
# This Source Code Form is subject to the terms of the Mozilla Public
2
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
3
# You can obtain one at http://mozilla.org/MPL/2.0/.
4

5
import collections
×
6

7
from libmozdata.bugzilla import Bugzilla
×
8

9
from bugbot import logger, utils
×
10
from bugbot.bzcleaner import BzCleaner
×
11
from bugbot.user_activity import UserActivity, UserStatus
×
12

13

14
class NeedinfoRegressionAuthor(BzCleaner):
×
15
    def __init__(self):
×
16
        super().__init__()
×
17
        self.extra_ni = {}
×
18

19
    def description(self):
×
20
        return "Unassigned regressions with non-empty Regressed By field"
×
21

22
    def handle_bug(self, bug, data):
×
23
        if len(bug["regressed_by"]) != 1:
×
24
            # either we don't have access to the regressor, or there's more than one, either way leave things alone
25
            return
×
26

27
        data[str(bug["id"])] = {
×
28
            "creator": bug["creator"],
29
            "regressor_id": bug["regressed_by"][0],
30
            "severity": bug["severity"],
31
        }
32

33
        return bug
×
34

35
    def get_extra_for_needinfo_template(self):
×
36
        return self.extra_ni
×
37

38
    def get_autofix_change(self):
×
39
        return {
×
40
            "keywords": {"add": ["regression"]},
41
        }
42

43
    def set_autofix(self, bugs):
×
44
        for bugid, info in bugs.items():
×
45
            self.extra_ni[bugid] = {
×
46
                "regressor_id": str(info["regressor_id"]),
47
                "suggest_set_severity": info["suggest_set_severity"],
48
            }
49
            self.add_auto_ni(
×
50
                bugid,
51
                {
52
                    "mail": info["regressor_author_email"],
53
                    "nickname": info["regressor_author_nickname"],
54
                },
55
            )
56

57
    def get_bz_params(self, date):
×
58
        start_date, _ = self.get_dates(date)
×
59

60
        fields = [
×
61
            "id",
62
            "creator",
63
            "regressed_by",
64
            "assigned_to",
65
            "severity",
66
        ]
67

68
        # Find all bugs with regressed_by information which were open after start_date or
69
        # whose regressed_by field was set after start_date.
70
        params = {
×
71
            "include_fields": fields,
72
            "f1": "OP",
73
            "j1": "OR",
74
            "f2": "creation_ts",
75
            "o2": "greaterthan",
76
            "v2": start_date,
77
            "f3": "regressed_by",
78
            "o3": "changedafter",
79
            "v3": start_date,
80
            "f4": "CP",
81
            "f5": "regressed_by",
82
            "o5": "isnotempty",
83
            "n6": 1,
84
            "f6": "longdesc",
85
            "o6": "casesubstring",
86
            "v6": "since you are the author of the regressor",
87
            "f7": "flagtypes.name",
88
            "o7": "notsubstring",
89
            "v7": "needinfo?",
90
            "status": ["UNCONFIRMED", "NEW", "REOPENED"],
91
            "resolution": ["---"],
92
        }
93

94
        utils.get_empty_assignees(params)
×
95

96
        return params
×
97

98
    def retrieve_regressors(self, bugs):
×
99
        regressor_to_bugs = collections.defaultdict(list)
×
100
        for bug in bugs.values():
×
101
            regressor_to_bugs[bug["regressor_id"]].append(bug)
×
102

103
        def bug_handler(regressor_bug):
×
104
            for bug in regressor_to_bugs[regressor_bug["id"]]:
×
105
                bug["regressor_author_email"] = regressor_bug["assigned_to"]
×
106
                bug["regressor_author_nickname"] = regressor_bug["assigned_to_detail"][
×
107
                    "nick"
108
                ]
109

110
        Bugzilla(
×
111
            bugids={bug["regressor_id"] for bug in bugs.values()},
112
            bughandler=bug_handler,
113
            include_fields=["id", "assigned_to"],
114
        ).get_data().wait()
115

116
    def filter_bugs(self, bugs):
×
117
        # Exclude bugs whose regressor author is nobody.
118
        for bug in list(bugs.values()):
×
119
            if utils.is_no_assignee(bug["regressor_author_email"]):
×
120
                logger.warning(
×
121
                    "Bug {}, regressor of bug {}, doesn't have an author".format(
122
                        bug["regressor_id"], bug["id"]
123
                    )
124
                )
125
                del bugs[bug["id"]]
×
126

127
        # Exclude bugs whose creator is the regressor author.
128
        bugs = {
×
129
            bug["id"]: bug
130
            for bug in bugs.values()
131
            if bug["creator"] != bug["regressor_author_email"]
132
        }
133

134
        # Exclude bugs where a commentor is the regressor author.
135
        def comment_handler(bug, bug_id):
×
136
            if any(
×
137
                comment["creator"] == bugs[bug_id]["regressor_author_email"]
138
                for comment in bug["comments"]
139
            ):
140
                del bugs[str(bug_id)]
×
141

142
        # Exclude bugs where the regressor author is inactive or blocked needinfo.
143
        # TODO: We can drop this when https://github.com/mozilla/bugbot/issues/1465 is implemented.
144
        users_info = UserActivity(include_fields=["groups", "requests"]).check_users(
×
145
            set(bug["regressor_author_email"] for bug in bugs.values()),
146
            keep_active=True,
147
        )
148

149
        for bug_id, bug in list(bugs.items()):
×
150
            user_info = users_info[bug["regressor_author_email"]]
×
151
            if (
×
152
                user_info["status"] != UserStatus.ACTIVE
153
                or user_info["requests"]["needinfo"]["blocked"]
154
            ):
155
                del bugs[bug_id]
×
156
            else:
157
                bug["suggest_set_severity"] = bug["severity"] in (
×
158
                    "--",
159
                    "n/a",
160
                ) and user_info.get("is_employee")
161

162
        Bugzilla(
×
163
            bugids=self.get_list_bugs(bugs),
164
            commenthandler=comment_handler,
165
            comment_include_fields=["creator"],
166
        ).get_data().wait()
167

168
        return bugs
×
169

170
    def get_bugs(self, *args, **kwargs):
×
171
        bugs = super().get_bugs(*args, **kwargs)
×
172
        self.retrieve_regressors(bugs)
×
173
        bugs = self.filter_bugs(bugs)
×
174
        self.set_autofix(bugs)
×
175
        return bugs
×
176

177

178
if __name__ == "__main__":
×
179
    NeedinfoRegressionAuthor().run()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc