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

mozilla / relman-auto-nag / #5638

08 Oct 2025 01:12PM UTC coverage: 20.812% (+0.02%) from 20.792%
#5638

push

coveralls-python

marco-c
Remove filters on old-style severity

426 of 3022 branches covered (14.1%)

1943 of 9336 relevant lines covered (20.81%)

0.21 hits per line

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

0.0
/bugbot/rules/moved_to_performance.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 base64
×
6
import json
×
7
from datetime import timedelta
×
8
from typing import Dict
×
9

10
from libmozdata import utils as lmdutils
×
11

12
from bugbot.bzcleaner import BzCleaner
×
13

14

15
class MovedToPerformance(BzCleaner):
×
16
    """Add a comment to bugs that recently moved to the performance component"""
17

18
    def __init__(self, recent_date_weeks: int = 26):
×
19
        """Constructor
20

21
        Args:
22
            recent_date_weeks: Number of weeks to consider when looking for
23
                recent data (e.g. profiler links and memory reports)
24
        """
25
        super().__init__()
×
26
        self.ni_extra: Dict[str, dict] = {}
×
27
        self.recent_date_limit = lmdutils.get_date_str(
×
28
            lmdutils.get_date_ymd("today") - timedelta(weeks=recent_date_weeks)
29
        )
30

31
    def description(self):
×
32
        return "Bugs that recently moved to the performance component"
×
33

34
    def get_extra_for_needinfo_template(self):
×
35
        return self.ni_extra
×
36

37
    def handle_bug(self, bug, data):
×
38
        bugid = str(bug["id"])
×
39

40
        has_profiler_link = any(
×
41
            "https://share.firefox.dev/" in comment["text"]
42
            for comment in bug["comments"]
43
            if comment["creator"] == bug["creator"]
44
            and comment["creation_time"] > self.recent_date_limit
45
        )
46

47
        has_memory_report = any(
×
48
            self._is_memory_report_file(attachment)
49
            for attachment in bug["attachments"]
50
            if attachment["creator"] == bug["creator"]
51
            and attachment["creation_time"] > self.recent_date_limit
52
            and not attachment["is_obsolete"]
53
            and not attachment["is_patch"]
54
        )
55

56
        has_troubleshooting_info = any(
×
57
            self._is_troubleshooting_content(attachment)
58
            for attachment in bug["attachments"]
59
            if attachment["creator"] == bug["creator"]
60
            and attachment["creation_time"] > self.recent_date_limit
61
            and not attachment["is_obsolete"]
62
            and not attachment["is_patch"]
63
        )
64

65
        if has_profiler_link and has_memory_report and has_troubleshooting_info:
×
66
            # Nothing missing, no need to add a comment
67
            return None
×
68

69
        self.ni_extra[bugid] = {
×
70
            "has_profiler_link": has_profiler_link,
71
            "has_memory_report": has_memory_report,
72
            "has_troubleshooting_info": has_troubleshooting_info,
73
        }
74

75
        return bug
×
76

77
    @staticmethod
×
78
    def _is_memory_report_file(attachment):
×
79
        return (
×
80
            attachment["content_type"]
81
            in (
82
                "application/gzip",
83
                "application/x-gzip",
84
                "application/json",
85
            )
86
            and "memory-report" in attachment["file_name"]
87
        )
88

89
    @staticmethod
×
90
    def _is_troubleshooting_content(attachment):
×
91
        if (
×
92
            attachment["content_type"]
93
            not in (
94
                "application/json",
95
                "text/plain",
96
            )
97
            or "memory-report" in attachment["file_name"]
98
        ):
99
            return False
×
100

101
        content_bytes = base64.b64decode(attachment["data"])
×
102
        try:
×
103
            content = json.loads(content_bytes)
×
104
        except ValueError:
×
105
            return False
×
106

107
        return all(
×
108
            key in content
109
            for key in (
110
                "application",
111
                "processes",
112
                "addons",
113
                "startupCache",
114
                "modifiedPreferences",
115
            )
116
        )
117

118
    def ignore_meta(self):
×
119
        return True
×
120

121
    def get_mail_to_auto_ni(self, bug):
×
122
        return {"mail": bug["creator"], "nickname": bug["creator_detail"]["nick"]}
×
123

124
    def get_bz_params(self, date):
×
125
        fields = [
×
126
            "creator",
127
            "attachments.is_obsolete",
128
            "attachments.is_patch",
129
            "attachments.content_type",
130
            "attachments.data",
131
            "attachments.file_name",
132
            "attachments.creator",
133
            "attachments.creation_time",
134
            "comments.text",
135
            "comments.creator",
136
            "comments.creation_time",
137
            "url",
138
        ]
139

140
        params = {
×
141
            "include_fields": fields,
142
            "resolution": "---",
143
            "bug_type": "defect",
144
            "f1": "product",
145
            "o1": "equals",
146
            "v1": "Core",
147
            "f2": "component",
148
            "o2": "equals",
149
            "v2": "Performance",
150
            "f3": "component",
151
            "o3": "changedafter",
152
            "v3": "-7d",
153
            "n4": 1,
154
            "f4": "component",
155
            "o4": "changedafter",
156
            "v4": "-1d",
157
            "n5": 1,
158
            "f5": "longdesc",
159
            "o5": "casesubstring",
160
            "v5": "could you make sure the following information is on this bug?",
161
        }
162

163
        return params
×
164

165

166
if __name__ == "__main__":
×
167
    MovedToPerformance().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