def get(bug_ids: Iterable[int]) -> Dict[int, dict]: """Function to retrieve Bug Information including history, comments using Bugzilla REST API and attachment using Bugzilla package. :param bug_ids: find bug information for these `bug_ids` :type bug_ids: list of integers or str or int :return: dict with key as `id`(int) of a bug, and values as bug_information :rtype: dict """ def attachmenthandler(bug, bug_id): bug_id = int(bug_id) if bug_id not in new_bugs: new_bugs[bug_id] = dict() new_bugs[bug_id]["attachments"] = bug bug_ids = sorted(set(bug_ids)) new_bugs = dict() batch_size = Bugzilla.BUGZILLA_CHUNK_SIZE # Getting _default, history and comments information using REST API # Attachment meta data is retrieved using Bugzilla module for i in range(0, len(bug_ids), batch_size): batch = bug_ids[i : i + batch_size] batch_of_ids = ",".join(map(str, batch)) # "include_fields": "_default,history,comments,attachments", # Attachments data size is heavy, so handling them separately params_for_custom_fields = { "id": batch_of_ids, "include_fields": "_default,history,comments", } response = utils.get_session("bugzilla").get( "https://bugzilla.mozilla.org/rest/bug", params=params_for_custom_fields ) response.raise_for_status() batch_of_bugs_info = response.json() batch_of_bugs_info = { int(a_bug["id"]): a_bug for a_bug in batch_of_bugs_info["bugs"] } new_bugs.update(batch_of_bugs_info) Bugzilla( batch, bughandler=None, commenthandler=None, comment_include_fields=None, attachmenthandler=attachmenthandler, attachment_include_fields=ATTACHMENT_INCLUDE_FIELDS, historyhandler=None, ).get_data().wait() return new_bugs
def get_product_component_count(): """Returns a dictionary where keys are full components (in the form of `{product}::{component}`) and the value of the number of bugs for the given full components. Full component with 0 bugs are returned. """ url, params = get_product_component_csv_report() csv_file = utils.get_session("bugzilla").get(url, params=params) csv_file.raise_for_status() content = csv_file.text csv_content = content.splitlines() component_key = "Component / Product" bugs_number = {} csv_reader = csv.DictReader(csv_content) for row in csv_reader: # Extract the component key component = row[component_key] for product, raw_value in row.items(): if product == component_key: continue value = int(raw_value) full_comp = f"{product}::{component}" bugs_number[full_comp] = value return bugs_number
def fetch_events(self, events_url: str) -> list: self.api_limit() logger.info(f"Fetching {events_url}") headers = {"Authorization": "token {}".format(self.get_token())} response = get_session("github").get(events_url, headers=headers) response.raise_for_status() events_raw = response.json() return events_raw
def count_bugs(bug_query_params): bug_query_params["count_only"] = 1 r = utils.get_session("bugzilla").get( "https://bugzilla.mozilla.org/rest/bug", params=bug_query_params) r.raise_for_status() count = r.json()["bug_count"] return count
def get_component_team_mapping() -> dict: r = utils.get_session("bugzilla").get( "https://bugzilla.mozilla.org/rest/config/component_teams", headers={ "X-Bugzilla-API-Key": Bugzilla.TOKEN, "User-Agent": "bugbug" }, ) r.raise_for_status() return r.json()
def function(self, filename, code): url = f"{self.base_url}/function?file_name={filename}" r = utils.get_session("code_analysis").post(url, data=code, headers=HEADERS) if not r.ok: return {} return r.json()
def get_component_team_mapping() -> Dict[str, Dict[str, str]]: r = utils.get_session("bugzilla").get( "https://bugzilla.mozilla.org/rest/product?type=accessible&include_fields=name&include_fields=components.name&include_fields=components.team_name", headers={"X-Bugzilla-API-Key": Bugzilla.TOKEN, "User-Agent": "bugbug"}, ) r.raise_for_status() mapping: Dict[str, Dict[str, str]] = collections.defaultdict(dict) for product in r.json()["products"]: for component in product["components"]: mapping[product["name"]][component["name"]] = component["team_name"] return mapping
def get_github_issues_update_time(owner: str, repo: str, issue_nums: Sequence[int]) -> dict: header = {"Authorization": "token {}".format(GITHUB_TOKEN)} repo_url = f"https://api.github.com/repos/{owner}/{repo}/issues/" issues = {} for issue_num in issue_nums: issue_url = repo_url + str(issue_num) response = utils.get_session("github").get(issue_url, headers=header) response.raise_for_status() raw_issue = response.json() issues[raw_issue["number"]] = raw_issue["updated_at"] return issues
def metrics(self, filename, code, unit=True): """ When unit is True, then only metrics for top-level is returned, when False, then we get detailed metrics for all classes, functions, nested functions, ... """ unit = 1 if unit else 0 url = f"{self.base_url}/metrics?file_name={filename}&unit={unit}" r = utils.get_session("code_analysis").post(url, data=code, headers=HEADERS) if not r.ok: return {} return r.json()
def get_groups_users(group_names: List[str]) -> List[str]: r = utils.get_session("bugzilla").get( "https://bugzilla.mozilla.org/rest/group", params={ "names": group_names, "membership": "1", }, headers={"X-Bugzilla-API-Key": Bugzilla.TOKEN, "User-Agent": "bugbug"}, ) r.raise_for_status() return [ member["email"] for group in r.json()["groups"] for member in group["membership"] ]
def get_product_component_count(months: int = 12) -> Dict[str, int]: """Returns a dictionary where keys are full components (in the form of `{product}::{component}`) and the value of the number of bugs for the given full components. Full component with 0 bugs are returned. """ since = datetime.utcnow() - relativedelta(months=months) # Base params params = { "f1": "creation_ts", "o1": "greaterthan", "v1": since.strftime("%Y-%m-%d"), "x_axis_field": "product", "y_axis_field": "component", "action": "wrap", "ctype": "csv", "format": "table", } csv_file = utils.get_session("bugzilla").get( PRODUCT_COMPONENT_CSV_REPORT_URL, params=params ) csv_file.raise_for_status() content = csv_file.text csv_content = content.splitlines() component_key = "Component / Product" bugs_number = {} csv_reader = csv.DictReader(csv_content) for row in csv_reader: # Extract the component key component = row[component_key] for product, raw_value in row.items(): if product == component_key: continue value = int(raw_value) full_comp = f"{product}::{component}" bugs_number[full_comp] = value return bugs_number
def get_bugs_last_change_time(bug_ids): query = { "id": ",".join(map(str, bug_ids)), "include_fields": ["last_change_time", "id"], } header = {"X-Bugzilla-API-Key": "", "User-Agent": "bugbug"} response = utils.get_session("bugzilla").get( BUGZILLA_API_URL, params=query, headers=header, verify=True, timeout=30 ) response.raise_for_status() raw_bugs = response.json() bugs = {} for bug in raw_bugs["bugs"]: bugs[bug["id"]] = bug["last_change_time"] return bugs
def get_bugs_last_change_time(bug_ids): query = { "include_fields": ["last_change_time", "id"], } header = {"X-Bugzilla-API-Key": BUGZILLA_TOKEN, "User-Agent": "bugbug"} bugs = {} for i in range(0, len(bug_ids), Bugzilla.BUGZILLA_CHUNK_SIZE): query["id"] = bug_ids[i : (i + Bugzilla.BUGZILLA_CHUNK_SIZE)] response = utils.get_session("bugzilla").get( BUGZILLA_API_URL, params=query, headers=header, verify=True, timeout=30 ) response.raise_for_status() raw_bugs = response.json() for bug in raw_bugs["bugs"]: bugs[bug["id"]] = bug["last_change_time"] return bugs
def fetch_issues(self, url: str, retrieve_events: bool, params: dict = None) -> tuple[list[IssueDict], dict]: self.api_limit() headers = {"Authorization": "token {}".format(self.get_token())} response = get_session("github").get(url, params=params, headers=headers) response.raise_for_status() data = response.json() # If only one issue is requested, add it to a list if isinstance(data, dict): data = [data] logger.info(f"Fetching {url}") if retrieve_events: for item in data: events = self.fetch_events(item["events_url"]) item.update({"events": events}) return data, response.links
def calculate_maintenance_effectiveness_indicator( team, from_date, to_date, components=None, ): data: dict[str, dict[str, int]] = { "opened": {}, "closed": {}, } for severity in MAINTENANCE_EFFECTIVENESS_SEVERITY_WEIGHTS.keys(): params = { "count_only": 1, "type": "defect", "team_name": team, "chfieldfrom": from_date.strftime("%Y-%m-%d"), "chfieldto": to_date.strftime("%Y-%m-%d"), } if severity != "--": params["bug_severity"] = severity if components is not None: params["component"] = components for query_type in ("opened", "closed"): if query_type == "opened": params["chfield"] = "[Bug creation]" elif query_type == "closed": params.update( { "chfield": "cf_last_resolved", "f1": "resolution", "o1": "notequals", "v1": "---", } ) r = utils.get_session("bugzilla").get( "https://bugzilla.mozilla.org/rest/bug", params=params, headers={"User-Agent": "bugbug"}, ) r.raise_for_status() data[query_type][severity] = r.json()["bug_count"] print("Before applying weights:") print(data) for query_type in ("opened", "closed"): data[query_type]["--"] = data[query_type]["--"] - sum( data[query_type][s] for s in MAINTENANCE_EFFECTIVENESS_SEVERITY_WEIGHTS.keys() if s != "--" ) # Apply weights. for ( severity, weight, ) in MAINTENANCE_EFFECTIVENESS_SEVERITY_WEIGHTS.items(): data[query_type][severity] *= weight print("After applying weights:") print(data) return (1 + sum(data["closed"].values())) / (1 + sum(data["opened"].values()))