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

mozilla / relman-auto-nag / #4077

pending completion
#4077

push

coveralls-python

suhaibmujahid
Merge remote-tracking branch 'upstream/master' into wiki-missed

549 of 3109 branches covered (17.66%)

615 of 615 new or added lines in 27 files covered. (100.0%)

1773 of 8016 relevant lines covered (22.12%)

0.22 hits per line

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

15.22
/auto_nag/scripts/no_crashes.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 dateutil.relativedelta import relativedelta
1✔
6
from libmozdata import utils as lmdutils
1✔
7
from libmozdata.socorro import SuperSearch
1✔
8

9
from auto_nag import utils
1✔
10
from auto_nag.bzcleaner import BzCleaner
1✔
11

12

13
class SocorroError(Exception):
1✔
14
    pass
1✔
15

16

17
class NoCrashes(BzCleaner):
1✔
18
    def __init__(self):
1✔
19
        super(NoCrashes, self).__init__()
×
20
        self.nweeks = utils.get_config(self.name(), "number_of_weeks", 12)
×
21
        self.summaries = {}
×
22

23
    def description(self):
1✔
24
        return "Bugs with no more crashes in the last {} weeks".format(self.nweeks)
×
25

26
    def get_extra_for_template(self):
1✔
27
        return {"nweeks": self.nweeks}
×
28

29
    def get_data(self):
1✔
30
        return {"signatures": set(), "ids": {}}
×
31

32
    def get_bz_params(self, date):
1✔
33
        date = lmdutils.get_date_ymd(date) - relativedelta(weeks=self.nweeks)
×
34
        reporters = self.get_config("reporter_exception", default=[])
×
35
        reporters = ",".join(reporters)
×
36
        keywords = self.get_config("keyword_exception", default=[])
×
37
        keywords = ",".join(keywords)
×
38
        fields = ["cf_crash_signature"]
×
39
        params = {
×
40
            "include_fields": fields,
41
            "resolution": "---",
42
            "status": ["UNCONFIRMED", "NEW", "ASSIGNED"],
43
            "f1": "cf_crash_signature",
44
            "o1": "isnotempty",
45
            "f2": "creation_ts",
46
            "o2": "lessthan",
47
            "v2": date,
48
            "f3": "days_elapsed",
49
            "o3": "greaterthan",
50
            "v3": self.nweeks * 7,
51
        }
52

53
        if reporters:
×
54
            params.update({"f4": "reporter", "o4": "nowordssubstr", "v4": reporters})
×
55

56
        if keywords:
×
57
            params.update({"f5": "keywords", "o5": "nowords", "v5": keywords})
×
58

59
        return params
×
60

61
    @staticmethod
1✔
62
    def chunkify(signatures):
63
        """Make some chunks with signatures,
64
        the total length of each chunk must be <= 1536"""
65
        total = sum(len(s) for s in signatures)
×
66
        M = 1536
×
67
        n = total // M + 1
×
68
        res = [[M, []] for _ in range(n)]
×
69
        for s in signatures:
×
70
            L = len(s)
×
71
            if L > M:
×
72
                continue
×
73
            added = False
×
74
            for i in res:
×
75
                if L < i[0]:
×
76
                    added = True
×
77
                    i[1].append(s)
×
78
                    i[0] -= L
×
79
                    break
×
80
            if not added:
×
81
                res.append([M - L, [s]])
×
82
        res = [x for _, x in res if len(x)]
×
83
        return res, max(len(x) for x in res)
×
84

85
    def bughandler(self, bug, data):
1✔
86
        """bug handler for the Bugzilla query"""
87
        if "cf_crash_signature" not in bug:
×
88
            return
×
89
        sgns = utils.get_signatures(bug["cf_crash_signature"])
×
90
        id = bug["id"]
×
91
        self.summaries[str(id)] = self.get_summary(bug)
×
92
        data["ids"][id] = sgns
×
93
        signatures = data["signatures"]
×
94
        for s in sgns:
×
95
            signatures.add(s)
×
96

97
    def get_stats(self, signatures, date):
1✔
98
        def handler(json, data):
×
99
            if json["errors"]:
×
100
                raise SocorroError()
×
101
            del json["hits"]
×
102
            for facet in json["facets"].get("signature", {}):
×
103
                data.remove(facet["term"])
×
104

105
        date = lmdutils.get_date_ymd(date) - relativedelta(weeks=self.nweeks)
×
106
        search_date = SuperSearch.get_search_date(date)
×
107
        chunks, size = self.chunkify(signatures)
×
108
        base = {
×
109
            "date": search_date,
110
            "signature": "",
111
            "_result_number": 0,
112
            "_facets": "signature",
113
            "_facets_size": size,
114
        }
115

116
        searches = []
×
117
        for chunk in chunks:
×
118
            params = base.copy()
×
119
            params["signature"] = ["=" + x for x in chunk]
×
120
            searches.append(
×
121
                SuperSearch(
122
                    params=params,
123
                    handler=handler,
124
                    handlerdata=signatures,
125
                    raise_error=True,
126
                )
127
            )
128

129
        for s in searches:
×
130
            s.wait()
×
131

132
    def get_bugs_without_crashes(self, data):
1✔
133
        # data['ids'] contains bugid => set(...signatures...)
134
        # data['signatures'] is a set of signatures with no crashes
135
        res = {}
×
136
        signatures = data["signatures"]
×
137
        for bugid, bug_sgns in data["ids"].items():
×
138
            if bug_sgns < signatures:
×
139
                # all the signatures in the bug have no crashes
140
                bugid = str(bugid)
×
141
                res[bugid] = {"id": bugid, "summary": self.summaries[bugid]}
×
142
        return res
×
143

144
    def get_autofix_change(self):
1✔
145
        return {
×
146
            "comment": {
147
                "body": "Closing because no crashes reported for {} weeks.".format(
148
                    self.nweeks
149
                )
150
            },
151
            "status": "RESOLVED",
152
            "resolution": "WORKSFORME",
153
        }
154

155
    def get_bugs(self, date="today", bug_ids=[]):
1✔
156
        data = super(NoCrashes, self).get_bugs(date=date, bug_ids=bug_ids)
×
157
        self.get_stats(data["signatures"], date)
×
158
        bugs = self.get_bugs_without_crashes(data)
×
159
        return bugs
×
160

161

162
if __name__ == "__main__":
1!
163
    NoCrashes().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