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

mozilla / relman-auto-nag / #4612

pending completion
#4612

push

coveralls-python

suhaibmujahid
Improve a method name

646 of 3416 branches covered (18.91%)

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

1828 of 8490 relevant lines covered (21.53%)

0.22 hits per line

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

0.0
/bugbot/rules/file_crash_bug.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 pprint
×
6

7
import jinja2
×
8
import requests
×
9

10
from bugbot import logger
×
11
from bugbot.bzcleaner import BzCleaner
×
12
from bugbot.crash import socorro_util
×
13
from bugbot.crash.analyzer import DevBugzilla, SignaturesDataFetcher
×
14

15

16
class FileCrashBug(BzCleaner):
×
17
    """File bugs for new actionable crashes."""
18

19
    # NOTE: If you make changes that affect the output of the rule, you should
20
    # increment this number. This is needed in the experimental phase only.
21
    VERSION = 1
×
22
    MAX_BUG_TITLE_LENGTH = 255
×
23

24
    def __init__(self):
×
25
        super().__init__()
×
26

27
        self.bug_description_template = jinja2.Environment(
×
28
            loader=jinja2.FileSystemLoader("templates")
29
        ).get_template("file_crash_bug_description.md.jinja")
30

31
    def description(self):
×
32
        return "New actionable crashes"
×
33

34
    def columns(self):
×
35
        return ["component", "id", "summary"]
×
36

37
    def get_bz_params(self, date):
×
38
        return {
×
39
            "resolution": ["---", "FIXED"],
40
            "keywords": ["feature", "regression"],
41
            "keywords_type": "allwords",
42
        }
43

44
    def get_bugs(self, date):
×
45
        self.query_url = None
×
46
        bugs = {}
×
47

48
        signatures = SignaturesDataFetcher.find_new_actionable_crashes(
×
49
            "Firefox", "nightly"
50
        )
51

52
        for signature in signatures.analyze():
×
53
            logger.debug("Generating bug for signature: %s", signature.signature_term)
×
54

55
            title = (
×
56
                f"Startup crash in [@ {signature.signature_term}]"
57
                if signature.is_startup_related_crash
58
                else f"Crash in [@ {signature.signature_term}]"
59
            )
60
            if len(title) > self.MAX_BUG_TITLE_LENGTH:
×
61
                title = title[: self.MAX_BUG_TITLE_LENGTH - 3] + "..."
×
62

63
            # TODO: Handle cases where the regressor is a security bug. In such
64
            # cases, we may want to file the bug as security bug.
65

66
            flags = None
×
67
            if signature.regressed_by:
×
68
                # TODO: check user activity and if the ni? is open
69
                flags = [
×
70
                    {
71
                        "name": "needinfo",
72
                        "requestee": signature.regressed_by_author["name"],
73
                        "status": "?",
74
                        "new": "true",
75
                    }
76
                ]
77

78
            report = signature.fetch_representative_processed_crash()
×
79
            description = self.bug_description_template.render(
×
80
                {
81
                    **socorro_util.generate_bug_description_data(report),
82
                    "signature": signature,
83
                    "needinfo_regression_author": bool(flags),
84
                }
85
            )
86

87
            # TODO: Provide the following information:
88
            # [X] Crash signature
89
            # [X] Top 10 frames of crashing thread
90
            # [X] Component
91
            # [X] The kind of crash
92
            # [ ] Regression window
93
            # [X] Inducing patch
94
            # [X] Reason
95
            # [X] Regressed by
96
            # [X] Platform
97
            # [ ] Firefox status flags
98
            # [ ] Severity
99
            # [ ] Time correlation
100
            # [X] User comments
101
            # [ ] Crash address commonalities
102
            # [ ] Estimated future crash volume
103

104
            bug_data = {
×
105
                "blocks": "bugbot-auto-crash",
106
                "type": "defect",
107
                "keywords": ["crash"],
108
                "status_whiteboard": f"[bugbot-crash-v{self.VERSION}]",
109
                "summary": title,
110
                "product": signature.crash_component.product,
111
                "component": signature.crash_component.name,
112
                "op_sys": signature.bugzilla_op_sys,
113
                "rep_platform": signature.bugzilla_cpu_arch,
114
                "cf_crash_signature": f"[@ {signature.signature_term}]",
115
                "description": description,
116
                # TODO: Uncomment the following lines when we move to file on
117
                # the production instance of Bugzilla. Filling `regressed_by` or
118
                # `flags` on bugzilla-dev will cause "bug does not exist" errors.
119
                # "regressed_by": signature.regressed_by,
120
                # "flags": flags,
121
            }
122

123
            if self.dryrun:
×
124
                logger.info("Dry-run bug:")
×
125
                pprint.pprint(bug_data)
×
126
                bug_id = str(len(bugs) + 1)
×
127
            else:
128
                # NOTE: When moving to production:
129
                #   - Use Bugzilla instead of DevBugzilla
130
                #   - Drop the DevBugzilla class
131
                #   - Update the bug URL `file_crash_bug.html`
132
                #   - Drop the bug link `file_crash_bug_description.md.jinja`
133
                #   - Fill the `regressed_by` and `flags` fields
134
                #   - Create the bug using `utils.create_bug``
135
                resp = requests.post(
×
136
                    url=DevBugzilla.API_URL,
137
                    json=bug_data,
138
                    headers=DevBugzilla([]).get_header(),
139
                    verify=True,
140
                    timeout=DevBugzilla.TIMEOUT,
141
                )
142
                resp.raise_for_status()
×
143
                bug = resp.json()
×
144
                bug_id = str(bug["id"])
×
145
                # TODO: log the created bugs info somewhere (e.g., DB,
146
                # spreadsheet, or LabelStudio)
147

148
            bugs[bug_id] = {
×
149
                "id": bug_id,
150
                "summary": title,
151
                "component": signature.crash_component,
152
            }
153

154
        logger.debug("Total of %d bugs have been filed", len(bugs))
×
155

156
        return bugs
×
157

158

159
if __name__ == "__main__":
×
160
    FileCrashBug().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