blob: c4b9f1247061ecce28640cff48cc991a1a16f3f2 [file] [log] [blame]
#!/usr/bin/env python3
# Future improvements:
# - link bugs and code references
# - handle multiple bug references per line (currently only fetches one)
# - fetch more than the first ~900 entries from Buganizer
# - check if CLI tool is available + authenticated
import pathlib, re, subprocess
outfile = "closed_bugs.csv"
print("Searching code for bug references")
androidx_root = pathlib.Path(__file__).parent.parent.resolve()
grep_cmd = subprocess.run(
["egrep",
# -I excludes binary files
# -i case insensitive search
# -n include line numbers
# -r recursive
"-Iinr",
# regex for buganizer format ("b/123456789")
"b\/[[:digit:]]{8,9}",
# Files and directories to include and exclude
"--exclude-dir=.idea",
"--include=*.gradle",
"--include=*.java",
"--include=*.kt",
"--include=*.xml",
# Search all of the AndroidX repo checkout
f"{androidx_root}"
],
capture_output=True,
text=True
)
raw_output_lines = grep_cmd.stdout.split("\n")
print("Cleaning up search results")
bug_dict = {} # mapping of bug id to list of filename + line number
for line in raw_output_lines:
regex_result = re.search('b\/[0-9]{8,9}', line)
if regex_result is not None:
bug_id = regex_result.group(0).removeprefix("b/")
file = line.split(":")[0].removeprefix(str(androidx_root))
linenum = line.split(":")[1]
if bug_id in bug_dict:
matching_files = bug_dict[bug_id]
else:
matching_files = set()
matching_files.add(f"{file}:{linenum}")
bug_dict[bug_id] = matching_files
print(f"Found {len(bug_dict)} bugs")
# Create bug id query string.
# The CLI tool fails if there are too many bugs (>900?); only use the first 900.
bug_ids = list(bug_dict.keys())
bug_ids.sort()
joined_ids = "|".join(bug_ids[0:899])
# Query buganizer to determine which of the given bugs are closed.
# Store the issue, reporter, and assignee of the matching [closed] bugs.
print("Querying Buganizer to find how many of these bugs are resolved")
bugged_cmd = subprocess.run(
["bugged", "search", f"id:({joined_ids})", "status:closed", "--columns=issue,reporter,assignee"],
capture_output=True,
text=True # capture output as String instead of byte sequence
)
closed_bug_list = bugged_cmd.stdout.split("\n")
# Remove header and trailing rows of Buganizer query result
closed_bug_list.pop(0)
closed_bug_list.pop()
print(f"{len(closed_bug_list)} have been resolved")
# Combine buganizer results with file search results and write to CSV
csv_str = "bug_id,reporter,assignee,files\n"
for line in closed_bug_list:
elements = re.split(" +", line)
bug_id = elements[0]
reporter = elements[1]
assignee = elements[2]
matching_files = bug_dict[bug_id]
line_str = f"b/{bug_id},{reporter},{assignee},"
# The list of matching file(s) are enclosed in double quotes to preserve \n in the csv
line_str += ("\"" + "\n".join(matching_files) + "\"")
csv_str += line_str + "\n"
print(csv_str, file=open(outfile, 'w'))
print(f"Wrote results to {outfile}")