Last active
May 17, 2024 09:27
-
-
Save qinyu/c4d35ce884eb19697f9bedcd9fdf7655 to your computer and use it in GitHub Desktop.
Count lint issues in multiple apps and present a bar chart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
import re | |
import os | |
import xml.etree.ElementTree as ET | |
import matplotlib.pyplot as plt | |
def fetch_lint_rules() -> tuple[dict[str, tuple[str, int]], list[tuple[str, int]]]: | |
""" | |
Fetch the lint rules and severities from the android lint sample website: | |
https://googlesamples.github.io/android-custom-lint-rules/checks/severity.md | |
:return: rules grouped by severities and severities | |
""" | |
_rules = {} | |
_severities = [] | |
_response = requests.get("https://googlesamples.github.io/android-custom-lint-rules/checks/severity.md") | |
_lines = _response.text.split("\n") | |
_severity_name = None | |
_severity_level = 0 | |
for _line in _lines: | |
# If the line starts with "*", it's a severity | |
if _line.startswith("*"): | |
_severity_level += 1 | |
_severity_name = _line.split()[1] | |
_severities.append((_severity_name, _severity_level)) | |
# If the line starts with "-", it's an rule | |
elif _line.startswith(" -"): | |
# Extract the rule name using regex | |
_lint_id = re.search(r'\[(.*?):', _line) | |
if not _lint_id: | |
_lint_id = re.search(r'\[(.*?)\]', _line) | |
if _lint_id: | |
_lint_id = _lint_id.group(1) | |
_rules[_lint_id] = _severity_name, _severity_level | |
return _rules, _severities | |
def count_app_lint_issues(result_folder, file_name): | |
_result = [] | |
for _app_folder in os.listdir(result_folder): | |
_app_lint_result = os.path.join(result_folder, _app_folder, file_name) | |
if os.path.exists(_app_lint_result): | |
_issue_count = {} | |
for _issue in ET.parse(_app_lint_result).findall("issue"): | |
_id = _issue.get("id") | |
if _id in _issue_count: | |
_issue_count[_id] += 1 | |
else: | |
_issue_count[_id] = 1 | |
_issue_count = [(k, lint_rules[k], v) for k, v in _issue_count.items()] | |
_result.append((_app_folder, _issue_count)) | |
return _result | |
def count_issue_by_severity(issues, severities): | |
""" | |
Count the number of issues by severity | |
:param issues: | |
:return: count of issues by severity | |
""" | |
_severity_count = { _severity : 0 for _severity in severities} | |
for _, _severity, _count in issues: | |
_severity_count[_severity] += _count | |
return _severity_count | |
def draw_app_lint_issues_counts(severities, app_issues): | |
""" | |
Draw the count of issues by severity for each app | |
:param severities: | |
:param app_issues: | |
:return: | |
""" | |
_app_width = 36 # 一组柱状体的宽度 | |
_app_len = len(app_issues) # 多少个应用 | |
_count_len = len(severities) # 多少个级别 | |
_count_width = _app_width / _count_len # 单个柱体的宽度 | |
_app_issue_counts = [(_app, count_issue_by_severity(_issues, severities)) for _app, _issues in app_issues] | |
_count_idx = 0 | |
for _severity in severities: | |
plt.bar([_app_width * _app_idx + _count_width * _count_idx for _app_idx in range(_app_len)], | |
height=[_issue_counts[_severity] for _, _issue_counts in _app_issue_counts], | |
label=_severity[0], | |
width=_count_width) | |
_count_idx += 1 | |
plt.xlabel("App") | |
plt.xticks([_app_width * x + _app_width / 2 for x in range(_app_len)], | |
[_app[0][:5] for _app in app_issues]) | |
plt.ylabel("Count") | |
plt.yscale("log") | |
plt.title("App Issues Count") | |
plt.legend() | |
plt.show() | |
if __name__ == "__main__": | |
lint_rules, lint_severities = fetch_lint_rules() | |
# print(lint_rules) | |
# print(lint_severities) | |
app_lint_issues = count_app_lint_issues("./lint_baseline", "lint-baseline.xml") | |
# print(app_lint_issues) | |
draw_app_lint_issues_counts(lint_severities, app_lint_issues) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment