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

mozilla / relman-auto-nag / #4767

13 Oct 2023 01:27AM CUT coverage: 22.091%. Remained the same
#4767

push

coveralls-python

suhaibmujahid
Format the .pre-commit-config.yaml file

716 of 3558 branches covered (0.0%)

1925 of 8714 relevant lines covered (22.09%)

0.22 hits per line

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

7.74
/bugbot/history.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
from pprint import pprint
1✔
6

7
from libmozdata.bugzilla import Bugzilla
1✔
8

9
from bugbot import logger
1✔
10

11

12
class History(object):
1✔
13
    BOT = "release-mgmt-account-bot@mozilla.tld"
1✔
14

15
    def __init__(self):
1✔
16
        super(History, self).__init__()
×
17

18
    def get_bugs(self):
1✔
19
        logger.info("History: get bugs: start...")
×
20

21
        def bug_handler(bug, data):
×
22
            data.add(bug["id"])
×
23

24
        fields_map = {
×
25
            "changedby": [
26
                "keywords",
27
                "product",
28
                "component",
29
                "assigned_to",
30
                "cf_crash_signature",
31
                "everconfirmed",
32
                "cf_has_regression_range",
33
                "cf_has_str",
34
                "priority",
35
                "bug_severity",
36
                "resolution",
37
                "bug_status",
38
                "bug_type",
39
                "cf_status_firefox68",
40
                "cf_status_firefox67",
41
                "cf_status_firefox66",
42
                "cf_status_firefox65",
43
                "cf_status_firefox64",
44
                "cf_status_firefox63",
45
                "cf_status_firefox62",
46
            ],
47
            "equals": ["commenter", "setters.login_name"],
48
        }
49

50
        queries = []
×
51
        bugids = set()
×
52
        for operator, fields in fields_map.items():
×
53
            for field in fields:
×
54
                params = {
×
55
                    "include_fields": "id",
56
                    "f1": field,
57
                    "o1": operator,
58
                    "v1": History.BOT,
59
                }
60
                queries.append(
×
61
                    Bugzilla(params, bughandler=bug_handler, bugdata=bugids, timeout=20)
62
                )
63

64
        for q in queries:
×
65
            q.get_data().wait()
×
66

67
        logger.info("History: get bugs: end.")
×
68

69
        return bugids
×
70

71
    def get_bug_info(self, bugids):
1✔
72
        logger.info("History: get bugs info: start...")
×
73

74
        def history_handler(bug, data):
×
75
            bugid = str(bug["id"])
×
76
            for h in bug["history"]:
×
77
                if h["who"] == History.BOT:
×
78
                    del h["who"]
×
79
                    data[bugid].append(h)
×
80

81
        def comment_handler(bug, bugid, data):
×
82
            bugid = str(bugid)
×
83
            for comment in bug["comments"]:
×
84
                if comment["author"] == History.BOT:
×
85
                    text = comment["text"]
×
86
                    data[bugid].append(
×
87
                        {"comment": text, "date": comment["creation_time"]}
88
                    )
89

90
        data = {str(bugid): [] for bugid in bugids}
×
91

92
        Bugzilla(
×
93
            list(data.keys()),
94
            historyhandler=history_handler,
95
            historydata=data,
96
            commenthandler=comment_handler,
97
            commentdata=data,
98
            timeout=960,
99
        ).get_data().wait()
100

101
        logger.info("History: get bugs info: end.")
×
102

103
        return data
×
104

105
    def cleanup(self, data):
1✔
106
        # res is a dictionary: change_date_time => change or comment
107
        res = {}
×
108

109
        for bugid, info in data.items():
×
110
            res[bugid] = x = {}
×
111
            for c in info:
×
112
                if "changes" in c:
×
113
                    when = c["when"]
×
114
                    del c["when"]
×
115
                    if when not in x:
×
116
                        x[when] = {"changes": c["changes"]}
×
117
                    else:
118
                        x[when]["changes"] += c["changes"]
×
119
                if "comment" in c:
×
120
                    when = c["date"]
×
121
                    del c["date"]
×
122
                    if when not in x:
×
123
                        x[when] = {"comment": c["comment"]}
×
124
                    else:
125
                        x[when]["comment"] = c["comment"]
×
126
        return res
×
127

128
    def get_pc(self, changes):
1✔
129
        p = ""
×
130
        c = ""
×
131
        for change in changes:
×
132
            if change.get("field_name") == "component" and "added" in change:
×
133
                c = change["added"]
×
134
            if change.get("field_name") == "product" and "added" in change:
×
135
                p = change["added"]
×
136
        return "{}::{}".format(p, c)
×
137

138
    def get_ni(self, changes):
1✔
139
        for change in changes:
×
140
            if change.get("field_name") == "flagtypes.name" and "added" in change:
×
141
                c = change["added"]
×
142
                ni = "needinfo?("
×
143
                if c.startswith(ni):
×
144
                    return c[len(ni) : -1]
×
145
        return ""
×
146

147
    def guess_tool(self, data):
1✔
148
        res = []
×
149
        no_tool = []
×
150

151
        for bugid, info in data.items():
×
152
            for date, i in info.items():
×
153
                if "comment" in i:
×
154
                    c = i["comment"]
×
155
                    if c.startswith("Crash volume for signature"):
×
156
                        continue
×
157

158
                    tool = None
×
159
                    if c.startswith(
×
160
                        "The leave-open keyword is there and there is no activity for"
161
                    ):
162
                        tool = "leave_open_no_activity"
×
163
                    elif c.startswith("Closing because no crashes reported for"):
×
164
                        tool = "no_crashes"
×
165
                    elif c.startswith("Moving to p3 because no activity for at least"):
×
166
                        tool = "old_p2_bug"
×
167
                    elif c.startswith("Moving to p2 because no activity for at least"):
×
168
                        tool = "old_p1_bug"
×
169
                    elif c.startswith(
×
170
                        "There's a r+ patch which didn't land and no activity in this bug"
171
                    ) or c.startswith(
172
                        "There are some r+ patches which didn't land and no activity in this bug for"
173
                    ):
174
                        tool = "not_landed"
×
175
                    elif c.startswith(
×
176
                        "The meta keyword is there, the bug doesn't depend on other bugs and there is no activity for"
177
                    ):
178
                        tool = "meta_no_deps_no_activity"
×
179
                    elif (
×
180
                        "[mozregression](https://wiki.mozilla.org/Auto-tools/Projects/Mozregression)"
181
                        in c
182
                    ):
183
                        tool = "has_str_no_range"
×
184
                    elif (
×
185
                        "as the bug is tracked by a release manager for the current"
186
                        in c
187
                    ):
188
                        tool = "mismatch_priority_tracking"
×
189
                    elif c.startswith("The severity flag is not set for this bug.\n:"):
×
190
                        tool = "no_severity"
×
191
                    elif c.startswith(
×
192
                        "The priority flag is not set for this bug and there is no activity for"
193
                    ):
194
                        tool = "ni_triage_owner"
×
195

196
                    if tool is None:
×
197
                        no_tool.append((bugid, info))
×
198
                    else:
199
                        extra = self.get_ni(i.get("changes", []))
×
200
                        res.append(
×
201
                            {"tool": tool, "date": date, "bugid": bugid, "extra": extra}
202
                        )
203
                else:
204
                    changes = i["changes"]
×
205
                    N = len(res)
×
206
                    for change in changes:
×
207
                        if change.get("added") == "meta":
×
208
                            res.append(
×
209
                                {
210
                                    "tool": "summary_meta_missing",
211
                                    "date": date,
212
                                    "bugid": bugid,
213
                                    "extra": "",
214
                                }
215
                            )
216
                            break
×
217
                        elif change.get("field_name") in {"component", "product"}:
×
218
                            res.append(
×
219
                                {
220
                                    "tool": "component",
221
                                    "date": date,
222
                                    "bugid": bugid,
223
                                    "extra": self.get_pc(changes),
224
                                }
225
                            )
226
                            break
×
227
                        elif change.get("field_name") == "cf_has_str":
×
228
                            res.append(
×
229
                                {
230
                                    "tool": "has_str_no_hasstr",
231
                                    "date": date,
232
                                    "bugid": bugid,
233
                                    "extra": "",
234
                                }
235
                            )
236
                            break
×
237
                        elif change.get("removed") == "leave-open":
×
238
                            res.append(
×
239
                                {
240
                                    "tool": "leave_open",
241
                                    "date": date,
242
                                    "bugid": bugid,
243
                                    "extra": "",
244
                                }
245
                            )
246
                            break
×
247
                        elif change.get("field_name") == "assigned_to":
×
248
                            res.append(
×
249
                                {
250
                                    "tool": "no_assignee",
251
                                    "date": date,
252
                                    "bugid": bugid,
253
                                    "extra": change["added"],
254
                                }
255
                            )
256
                            break
×
257
                        elif (
×
258
                            change.get("field_name", "").startswith("cf_status_firefox")
259
                            and change.get("added") == "affected"
260
                        ):
261
                            res.append(
×
262
                                {
263
                                    "tool": "nighty_reopened",
264
                                    "date": date,
265
                                    "bugid": bugid,
266
                                    "extra": "",
267
                                }
268
                            )
269
                            break
×
270
                        elif (
×
271
                            change.get("field_name") == "status"
272
                            and change.get("added") == "ASSIGNED"
273
                        ):
274
                            res.append(
×
275
                                {
276
                                    "tool": "assignee_but_unconfirmed",
277
                                    "date": date,
278
                                    "bugid": bugid,
279
                                    "extra": "",
280
                                }
281
                            )
282
                            break
×
283
                        elif (
×
284
                            change.get("field_name") == "keywords"
285
                            and change.get("added") == "regression"
286
                        ):
287
                            res.append(
×
288
                                {
289
                                    "tool": "regression",
290
                                    "date": date,
291
                                    "bugid": bugid,
292
                                    "extra": "",
293
                                }
294
                            )
295
                            break
×
296
                        elif change.get("field_name") == "cf_crash_signature":
×
297
                            res.append(
×
298
                                {
299
                                    "tool": "copy_duplicate_info",
300
                                    "date": date,
301
                                    "bugid": bugid,
302
                                    "extra": "",
303
                                }
304
                            )
305
                            break
×
306
                        elif (
×
307
                            change.get("field_name") == "keywords"
308
                            and change.get("removed") == "stalled"
309
                        ):
310
                            res.append(
×
311
                                {
312
                                    "tool": "regression",
313
                                    "date": date,
314
                                    "bugid": bugid,
315
                                    "extra": "",
316
                                }
317
                            )
318
                            break
×
319
                        elif (
×
320
                            change.get("field_name") == "type"
321
                            and change.get("added") == "defect"
322
                        ):
323
                            res.append(
×
324
                                {
325
                                    "tool": "regression_but_type_enhancement_task",
326
                                    "date": date,
327
                                    "bugid": bugid,
328
                                    "extra": "",
329
                                }
330
                            )
331
                            break
×
332
                        elif (
×
333
                            change.get("field_name") == "keywords"
334
                            and change.get("removed") == "dupeme"
335
                        ):
336
                            res.append(
×
337
                                {
338
                                    "tool": "closed_dupeme",
339
                                    "date": date,
340
                                    "bugid": bugid,
341
                                    "extra": "",
342
                                }
343
                            )
344
                            break
×
345
                        elif (
×
346
                            change.get("field_name") == "keywords"
347
                            and change.get("added") == "dupeme"
348
                        ):
349
                            res.append(
×
350
                                {
351
                                    "tool": "dupeme_whiteboard_keyword",
352
                                    "date": date,
353
                                    "bugid": bugid,
354
                                    "extra": "",
355
                                }
356
                            )
357
                            break
×
358
                        elif change.get("field_name") == "summary" and change.get(
×
359
                            "added"
360
                        ).startswith("[meta]"):
361
                            res.append(
×
362
                                {
363
                                    "tool": "meta_summary_missing",
364
                                    "date": date,
365
                                    "bugid": bugid,
366
                                    "extra": "",
367
                                }
368
                            )
369
                            break
×
370
                        elif change.get("field_name", "").startswith(
×
371
                            "cf_status_firefox"
372
                        ) and change.get("added") in {
373
                            "?",
374
                            "fixed",
375
                            "verified",
376
                            "unaffected",
377
                        }:
378
                            res.append(
×
379
                                {
380
                                    "tool": "missing_beta_status",
381
                                    "date": date,
382
                                    "bugid": bugid,
383
                                    "extra": "",
384
                                }
385
                            )
386
                            break
×
387

388
                    if len(res) == N:
×
389
                        no_tool.append((bugid, info))
×
390

391
        if no_tool:
×
392
            pprint(no_tool)
×
393

394
        return res
×
395

396
    def get(self):
1✔
397
        bugids = self.get_bugs()
×
398
        bugs = self.get_bug_info(bugids)
×
399
        bugs = self.cleanup(bugs)
×
400
        history = self.guess_tool(bugs)
×
401

402
        return history
×
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