def bug_analysis()

in libmozdata/patchanalysis.py [0:0]


def bug_analysis(bug, uplift_channel=None, author_cache={}, reviewer_cache={}):
    if isinstance(bug, numbers.Number):
        bug_id = bug
        bug = {}

        def bughandler(found_bug):
            bug.update(found_bug)

        def commenthandler(found_bug, bugid):
            bug["comments"] = found_bug["comments"]

        def attachmenthandler(attachments, bugid):
            bug["attachments"] = attachments

        def historyhandler(found_bug):
            bug["history"] = found_bug["history"]

        INCLUDE_FIELDS = [
            "id",
            "flags",
            "depends_on",
            "keywords",
            "blocks",
            "whiteboard",
            "resolution",
            "status",
            "url",
            "version",
            "summary",
            "priority",
            "product",
            "component",
            "severity",
            "platform",
            "op_sys",
            "cc",
            "assigned_to",
            "creator",
        ]

        ATTACHMENT_INCLUDE_FIELDS = ["flags", "is_patch", "creator", "content_type"]

        COMMENT_INCLUDE_FIELDS = ["id", "text", "author", "time"]

        Bugzilla(
            bug_id,
            INCLUDE_FIELDS,
            bughandler=bughandler,
            commenthandler=commenthandler,
            comment_include_fields=COMMENT_INCLUDE_FIELDS,
            attachmenthandler=attachmenthandler,
            historyhandler=historyhandler,
            attachment_include_fields=ATTACHMENT_INCLUDE_FIELDS,
        ).get_data().wait()

    info = {
        "backout_num": 0,
        "blocks": len(bug["blocks"]),
        "depends_on": len(bug["depends_on"]),
        "comments": len(bug["comments"]),
        "r-ed_patches": sum(
            (a["is_patch"] == 1 or a["content_type"] == "text/x-review-board-request")
            and sum(
                flag["name"] == "review" and flag["status"] == "-"
                for flag in a["flags"]
            )
            > 0
            for a in bug["attachments"]
        ),
        "patches": {},
    }

    # Store in-testsuite flag.
    in_testsuite = [
        flag["status"] for flag in bug["flags"] if flag["name"] == "in-testsuite"
    ]
    info["in-testsuite"] = in_testsuite[0] if len(in_testsuite) > 0 else ""

    # Store bug creator & assignee
    assignee = bug.get("assigned_to_detail")
    creator = bug.get("creator_detail")

    # Get all reviewers and authors, we will match them with the changeset description (r=XXX).
    bugzilla_authors, bugzilla_reviewers = get_bugzilla_authors_reviewers(bug)

    revs, backout_comments = get_commits_for_bug(bug)

    if len(revs) > 0:
        for rev, obj in revs.items():
            # Multiple names because sometimes authors use different emails on Bugzilla and Mercurial and sometimes
            # they change it.
            author_names = author_match(
                obj["author_mercurial"],
                obj["author_real_name"],
                bugzilla_authors,
                bug["cc_detail"],
                author_cache,
            )

            reviewers = set()

            short_reviewers = obj["reviewers"]

            for short_reviewer in short_reviewers:
                # This changeset was not reviewed (probably a simple fix).
                if short_reviewer not in ["me", "oops", "none", "bustage", "backout"]:
                    reviewers.add(
                        reviewer_match(
                            short_reviewer,
                            bugzilla_reviewers | bugzilla_authors,
                            bug["cc_detail"],
                            reviewer_cache,
                        )
                    )

            # Human readable patch URL
            info["patches"][rev] = {
                "source": "mercurial",
                "url": hgmozilla.Mercurial.get_repo_url(obj["channel"])
                + "/rev/{}".format(rev),
            }

            info["patches"][rev].update(
                patch_analysis(
                    hgmozilla.RawRevision.get_revision(obj["channel"], rev),
                    author_names,
                    reviewers,
                    utils.as_utc(datetime.utcfromtimestamp(obj["creation_date"])),
                )
            )
    else:

        def attachmenthandler(attachments, bugid):
            for i in range(0, len(bug["attachments"])):
                bug["attachments"][i].update(attachments[i])

        Bugzilla(
            bug["id"],
            attachmenthandler=attachmenthandler,
            attachment_include_fields=["id", "data", "is_obsolete", "creation_time"],
        ).get_data().wait()

        for attachment in bug["attachments"]:
            if (
                sum(
                    flag["name"] == "review" and flag["status"] == "+"
                    for flag in attachment["flags"]
                )
                == 0
            ):
                continue

            data = None

            if attachment["is_patch"] == 1 and attachment["is_obsolete"] == 0:
                info["patches"][attachment["id"]] = {
                    "source": "attachment",
                    "url": "{}/attachment.cgi?id={}".format(
                        Bugzilla.URL, attachment["id"]
                    ),
                }
                data = base64.b64decode(attachment["data"]).decode("ascii", "ignore")
            elif (
                attachment["content_type"] == "text/x-review-board-request"
                and attachment["is_obsolete"] == 0
            ):
                mozreview_url = base64.b64decode(attachment["data"]).decode("utf-8")
                info["patches"][attachment["id"]] = {
                    "source": "mozreview",
                    "url": mozreview_url,
                }
                review_num = re.search(MOZREVIEW_URL_PATTERN, mozreview_url).group(1)
                mozreview_raw_diff_url = (
                    "https://reviewboard.mozilla.org/r/" + review_num + "/diff/raw/"
                )

                response = urlopen(mozreview_raw_diff_url)
                data = response.read().decode("ascii", "ignore")

            if data is not None:
                info["patches"][attachment["id"]].update(
                    patch_analysis(
                        data,
                        [attachment["creator"]],
                        bugzilla_reviewers,
                        utils.get_date_ymd(attachment["creation_time"]),
                    )
                )

    # TODO: Add number of crashes with signatures from the bug (also before/after the patch?).

    # TODO: Add perfherder results?

    info["backout_num"] = len(backout_comments)

    # Add users
    info["users"] = {
        "creator": creator,
        "assignee": assignee,
        "authors": bugzilla_authors,
        "reviewers": bugzilla_reviewers,
    }

    if uplift_channel is not None:
        # Add uplift request
        info.update(uplift_info(bug, uplift_channel))

    return info