Skip to content

Instantly share code, notes, and snippets.

@qinyu
Last active May 17, 2024 09:27
Show Gist options
  • Save qinyu/c4d35ce884eb19697f9bedcd9fdf7655 to your computer and use it in GitHub Desktop.
Save qinyu/c4d35ce884eb19697f9bedcd9fdf7655 to your computer and use it in GitHub Desktop.
Count lint issues in multiple apps and present a bar chart
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