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

mozilla / relman-auto-nag / #4682

pending completion
#4682

push

coveralls-python

web-flow
[uplift_beta] Alert about potential out-of-sync uplift flags (#2178)

716 of 3562 branches covered (20.1%)

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

1924 of 8721 relevant lines covered (22.06%)

0.22 hits per line

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

0.0
/bugbot/rules/uplift_beta.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 libmozdata import utils as lmdutils
×
6
from libmozdata.bugzilla import Bugzilla
×
7

8
from bugbot import utils
×
9
from bugbot.bzcleaner import BzCleaner
×
10

11

12
class UpliftBeta(BzCleaner):
×
13
    def __init__(self):
×
14
        super(UpliftBeta, self).__init__()
×
15
        if not self.init_versions():
×
16
            return
×
17

18
        self.beta = self.versions["beta"]
×
19
        self.status_central = utils.get_flag(
×
20
            self.versions["central"], "status", "central"
21
        )
22
        self.status_beta = utils.get_flag(self.beta, "status", "beta")
×
23

24
        # Bugs will be added to `extra_ni` later after being fetched
25
        self.extra_ni = {"status_beta": f"status-firefox{self.beta}"}
×
26

27
    def description(self):
×
28
        return "Bugs fixed in nightly but still affecting beta"
×
29

30
    def has_assignee(self):
×
31
        return True
×
32

33
    def get_extra_for_needinfo_template(self):
×
34
        return self.extra_ni
×
35

36
    def columns(self):
×
37
        return ["id", "summary", "assignee"]
×
38

39
    def handle_bug(self, bug, data):
×
40
        # XXX: This is a temporary workaround, should be dropped after
41
        # fixing https://github.com/mozilla/bugbot/issues/1953
42
        if self._has_patch_after_closed(bug):
×
43
            from bugbot import logger
×
44

45
            logger.error(
×
46
                "Bug %s has a patch after being closed without an uplift approval flag. This could be a sign that Bug 1825961 is still not fixed.",
47
                bug["id"],
48
            )
49
            return
×
50

51
        bugid = str(bug["id"])
×
52

53
        assignee = bug.get("assigned_to", "")
×
54
        if utils.is_no_assignee(assignee):
×
55
            assignee = ""
×
56
            nickname = ""
×
57
        else:
58
            nickname = bug["assigned_to_detail"]["nick"]
×
59

60
        data[bugid] = {
×
61
            "id": bugid,
62
            "mail": assignee,
63
            "nickname": nickname,
64
            "summary": self.get_summary(bug),
65
            "regressions": bug["regressions"],
66
        }
67
        return bug
×
68

69
    def filter_by_regr(self, bugs):
×
70
        # Filter the bugs which don't have any regression or where the regressions are all closed
71
        def bug_handler(bug, data):
×
72
            if bug["status"] in {"RESOLVED", "VERIFIED", "CLOSED"}:
×
73
                data.add(bug["id"])
×
74

75
        bugids = {r for info in bugs.values() for r in info["regressions"]}
×
76
        if not bugids:
×
77
            return bugs
×
78

79
        fixed_bugs = set()
×
80
        Bugzilla(
×
81
            bugids=list(bugids),
82
            include_fields=["id", "status"],
83
            bughandler=bug_handler,
84
            bugdata=fixed_bugs,
85
        ).get_data().wait()
86

87
        bugs_without_regr = {}
×
88
        for bugid, info in bugs.items():
×
89
            regs = set(info["regressions"])
×
90
            regs = regs - fixed_bugs
×
91
            if not regs:
×
92
                bugs_without_regr[bugid] = info
×
93

94
        return bugs_without_regr
×
95

96
    def get_bz_params(self, date):
×
97
        self.date = lmdutils.get_date_ymd(date)
×
98
        fields = [
×
99
            self.status_beta,
100
            "regressions",
101
            "attachments.creation_time",
102
            "attachments.is_obsolete",
103
            "attachments.content_type",
104
            "cf_last_resolved",
105
        ]
106
        params = {
×
107
            "include_fields": fields,
108
            "bug_type": "defect",
109
            "resolution": ["---", "FIXED"],
110
            "f1": self.status_central,
111
            "o1": "anyexact",
112
            "v1": ",".join(["fixed", "verified"]),
113
            "f2": self.status_beta,
114
            "o2": "anyexact",
115
            "v2": ["affected", "fix-optional"],
116
            "f3": "flagtypes.name",
117
            "o3": "notsubstring",
118
            "v3": "approval-mozilla-beta",
119
            "f4": "flagtypes.name",
120
            "o4": "notsubstring",
121
            "v4": "needinfo",
122
            # Don't nag several times
123
            "n5": 1,
124
            "f5": "longdesc",
125
            "o5": "casesubstring",
126
            # this a part of the comment we've in templates/uplift_beta_needinfo.txt
127
            "v5": ", is this bug important enough to require an uplift?",
128
            # Check if have at least one attachment which is a Phabricator request
129
            "f6": "attachments.mimetype",
130
            "o6": "anyexact",
131
            "v6": ["text/x-phabricator-request", "text/x-github-pull-request"],
132
            # skip if whiteboard contains checkin-needed-beta (e.g. test-only uplift)
133
            "f7": "status_whiteboard",
134
            "o7": "notsubstring",
135
            "v7": "[checkin-needed-beta]",
136
        }
137

138
        return params
×
139

140
    def _has_patch_after_closed(self, bug):
×
141
        patches = [
×
142
            attachment["creation_time"]
143
            for attachment in bug["attachments"]
144
            if attachment["content_type"] == "text/x-phabricator-request"
145
            and not attachment["is_obsolete"]
146
        ]
147
        if len(patches) == 0:
×
148
            return False
×
149

150
        latest_patch_at = max(patches)
×
151
        resolved_at = bug["cf_last_resolved"]
×
152

153
        return latest_patch_at > resolved_at
×
154

155
    def get_bugs(self, date="today", bug_ids=[]):
×
156
        bugs = super(UpliftBeta, self).get_bugs(date=date, bug_ids=bug_ids)
×
157
        bugs = self.filter_by_regr(bugs)
×
158

159
        for bugid, data in bugs.items():
×
160
            if data["mail"] and data["nickname"]:
×
161
                self.extra_ni[bugid] = {"regression": len(data["regressions"])}
×
162
                self.add_auto_ni(
×
163
                    bugid, {"mail": data["mail"], "nickname": data["nickname"]}
164
                )
165

166
        return bugs
×
167

168

169
if __name__ == "__main__":
×
170
    UpliftBeta().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