• 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

0.0
/bugbot/rules/code_freeze_week.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 datetime
×
6
import re
×
7

8
import whatthepatch
×
9
from dateutil.relativedelta import relativedelta
×
10
from libmozdata import hgmozilla
×
11
from libmozdata import utils as lmdutils
×
12
from libmozdata.bugzilla import Bugzilla
×
13
from libmozdata.connection import Query
×
14
from libmozdata.fx_trains import FirefoxTrains
×
15

16
from bugbot import utils
×
17
from bugbot.bzcleaner import BzCleaner
×
18
from bugbot.people import People
×
19

20
NIGHTLY_PAT = Bugzilla.get_landing_patterns(channels=["nightly"])
×
21
BUG_PAT = re.compile("[\t ]*bug[s]?[\t ]*([0-9]+)", re.I)
×
22
BACKOUT_PAT = re.compile("^back(ed)?[ \t]*out", re.I)
×
23

24

25
class CodeFreezeWeek(BzCleaner):
×
26
    def __init__(self):
×
27
        super(CodeFreezeWeek, self).__init__()
×
28
        if not self.init_versions():
×
29
            return
×
30

31
        self.people = People.get_instance()
×
32
        self.nightly = self.versions["central"]
×
33
        self.beta = self.versions["beta"]
×
34
        self.release = self.versions["release"]
×
35
        self.status_nightly = utils.get_flag(self.nightly, "status", "central")
×
36
        self.status_beta = utils.get_flag(self.beta, "status", "beta")
×
37
        self.status_release = utils.get_flag(self.release, "status", "release")
×
38
        self.tracking_nightly = utils.get_flag(self.nightly, "tracking", "central")
×
39
        self.tracking_beta = utils.get_flag(self.beta, "tracking", "beta")
×
40
        self.tracking_release = utils.get_flag(self.release, "tracking", "release")
×
41

42
    def description(self):
×
43
        return "Bugs with patches which landed during the soft freeze week"
×
44

45
    def get_extra_for_template(self):
×
46
        return {
×
47
            "nightly": self.nightly,
48
            "beta": self.beta,
49
            "release": self.release,
50
            "date": lmdutils.get_date_str(self.date),
51
        }
52

53
    def filter_no_nag_keyword(self):
×
54
        return False
×
55

56
    def must_run(self, date):
×
57
        schedule = FirefoxTrains().get_release_schedule("nightly")
×
58
        freeze = lmdutils.get_date_ymd(schedule["soft_code_freeze"])
×
59
        merge = lmdutils.get_date_ymd(schedule["merge_day"])
×
60

61
        # run from the soft freeze date until merge day
62
        return freeze <= date < merge
×
63

64
    def has_product_component(self):
×
65
        return True
×
66

67
    def columns(self):
×
68
        return [
×
69
            "id",
70
            "summary",
71
            "product",
72
            "component",
73
            "assignee",
74
            "landed_patches",
75
            "addlines",
76
            "rmlines",
77
            "size",
78
            "test_size",
79
            "priority",
80
            "severity",
81
            "tracking",
82
            "status",
83
            "status_flags",
84
            "keywords",
85
            "type",
86
        ]
87

88
    def sort_columns(self):
×
89
        return lambda p: (p[2], p[3], -p[5], -p[8], -p[9], -int(p[0]))
×
90

91
    def handle_bug(self, bug, data):
×
92
        bugid = str(bug["id"])
×
93

94
        assignee = bug.get("assigned_to", "")
×
95
        if assignee:
×
96
            info = self.people.get_info(assignee)
×
97
            if info:
×
98
                assignee = info["cn"]
×
99
            else:
100
                name = bug.get("assigned_to_detail", {}).get("real_name", "")
×
101
                if name:
×
102
                    assignee = utils.get_better_name(name)
×
103
        else:
104
            assignee = "Nobody"
×
105

106
        data[bugid] = {
×
107
            "land": {},
108
            "assignee": assignee,
109
            "priority": bug["priority"],
110
            "severity": bug["severity"],
111
            "tracking": bug[self.tracking_nightly],
112
            "status": bug["status"].lower(),
113
            "status_flags": {
114
                self.nightly: bug[self.status_nightly],
115
                self.beta: bug[self.status_beta],
116
                self.release: bug[self.status_release],
117
            },
118
            "keywords": ",".join(bug["keywords"]),
119
            "type": bug["type"],
120
        }
121

122
        return bug
×
123

124
    def filter_bugs(self, bugs):
×
125
        invalids = set()
×
126

127
        def comment_handler(bug, bugid, data):
×
128
            r = Bugzilla.get_landing_comments(bug["comments"], [], NIGHTLY_PAT)
×
129
            if not r:
×
130
                invalids.add(bugid)
×
131
                return
×
132

133
            data[bugid]["land"] = {
×
134
                i["revision"]: {"date": None, "backedout": False, "bugid": bugid}
135
                for i in r
136
            }
137

138
        bugids = list(bugs.keys())
×
139
        Bugzilla(
×
140
            bugids=bugids,
141
            commenthandler=comment_handler,
142
            commentdata=bugs,
143
            comment_include_fields=["text"],
144
        ).get_data().wait()
145

146
        for bugid in invalids:
×
147
            del bugs[bugid]
×
148

149
    def patch_analysis(self, patch):
×
150
        info = {"size": 0, "test_size": 0, "addlines": 0, "rmlines": 0}
×
151

152
        for diff in whatthepatch.parse_patch(patch):
×
153
            if diff.header and diff.changes:
×
154
                h = diff.header
×
155
                new_path = h.new_path[2:] if h.new_path.startswith("b/") else h.new_path
×
156

157
                # Calc changes additions & deletions
158
                counts = [
×
159
                    (old is None and new is not None, new is None and old is not None)
160
                    for old, new, _, _ in diff.changes
161
                ]
162
                counts = list(zip(*counts))  # inverse zip
×
163
                info["addlines"] += sum(counts[0])
×
164
                info["rmlines"] += sum(counts[1])
×
165

166
                if utils.is_test_file(new_path):
×
167
                    info["test_size"] += len(diff.changes)
×
168
                else:
169
                    info["size"] += len(diff.changes)
×
170

171
        return info
×
172

173
    def get_hg_patches(self, bugs):
×
174
        url = hgmozilla.RawRevision.get_url("nightly")
×
175
        queries = []
×
176

177
        def handler(patch, data):
×
178
            info = self.patch_analysis(patch)
×
179
            if "addlines" not in data:
×
180
                data.update(info)
×
181
            else:
182
                for k, v in info.items():
×
183
                    data[k] += v
×
184

185
        for info in bugs.values():
×
186
            for rev, i in info["land"].items():
×
187
                if not i["backedout"]:
×
188
                    queries.append(Query(url, {"node": rev}, handler, info))
×
189

190
        if queries:
×
191
            hgmozilla.Revision(queries=queries).wait()
×
192

193
        torm = []
×
194
        for bug, info in bugs.items():
×
195
            landed_patches = [v["backedout"] for v in info["land"].values()].count(
×
196
                False
197
            )
198
            # bug with only backouts
199
            if landed_patches == 0:
×
200
                torm.append(bug)
×
201
            else:
202
                info["landed_patches"] = landed_patches
×
203

204
        # Remove bugs that we don't want to show
205
        for bug in torm:
×
206
            del bugs[bug]
×
207

208
    def get_hg(self, bugs):
×
209
        url = hgmozilla.Revision.get_url("nightly")
×
210
        queries = []
×
211

212
        def handler_rev(json, data):
×
213
            push = json["pushdate"][0]
×
214
            push = datetime.datetime.utcfromtimestamp(push)
×
215
            push = lmdutils.as_utc(push)
×
216
            data["date"] = lmdutils.get_date_str(push)
×
217
            data["backedout"] = utils.is_backout(json)
×
218
            m = BUG_PAT.search(json["desc"])
×
219
            if not m or m.group(1) != data["bugid"]:
×
220
                data["bugid"] = ""
×
221

222
        for info in bugs.values():
×
223
            for rev, i in info["land"].items():
×
224
                queries.append(Query(url, {"node": rev}, handler_rev, i))
×
225

226
        if queries:
×
227
            hgmozilla.Revision(queries=queries).wait()
×
228

229
        # clean
230
        bug_torm = []
×
231
        for bug, info in bugs.items():
×
232
            torm = []
×
233
            for rev, i in info["land"].items():
×
234
                if not i["bugid"] or not (
×
235
                    self.date <= lmdutils.get_date_ymd(i["date"]) < self.tomorrow
236
                ):
237
                    torm.append(rev)
×
238
            for x in torm:
×
239
                del info["land"][x]
×
240
            if not info["land"]:
×
241
                bug_torm.append(bug)
×
242
        for x in bug_torm:
×
243
            del bugs[x]
×
244

245
        self.get_hg_patches(bugs)
×
246

247
    def get_bz_params(self, date):
×
248
        self.date = lmdutils.get_date_ymd(date)
×
249
        self.tomorrow = self.date + relativedelta(days=1)
×
250
        bugs = utils.get_bugs_from_pushlog(self.date, self.tomorrow)
×
251
        assignee_skiplist = self.get_config("assignee_skiplist", default=[])
×
252
        assignee_skiplist = ",".join(assignee_skiplist)
×
253
        fields = [
×
254
            "assigned_to",
255
            "assigned_to_detail",
256
            "status",
257
            "resolution",
258
            "priority",
259
            "severity",
260
            "keywords",
261
            "type",
262
        ]
263
        fields += [self.status_nightly, self.status_beta, self.status_release]
×
264
        fields += [self.tracking_nightly]
×
265
        params = {
×
266
            "include_fields": fields,
267
            "bug_id": ",".join(bugs),
268
            "f1": "assigned_to",
269
            "o1": "nowords",
270
            "v1": assignee_skiplist,
271
        }
272

273
        return params
×
274

275
    def get_bugs(self, date="today", bug_ids=[]):
×
276
        bugs = super(CodeFreezeWeek, self).get_bugs(date=date, bug_ids=bug_ids)
×
277
        self.filter_bugs(bugs)
×
278
        self.get_hg(bugs)
×
279

280
        return bugs
×
281

282

283
if __name__ == "__main__":
×
284
    CodeFreezeWeek().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