13508eddcSopenharmony_cifrom github import Github, Repository 23508eddcSopenharmony_ciimport os 33508eddcSopenharmony_ciimport json 43508eddcSopenharmony_cifrom datetime import datetime 53508eddcSopenharmony_cifrom collections import Counter 63508eddcSopenharmony_cifrom pybars import Compiler 73508eddcSopenharmony_ciimport matplotlib 83508eddcSopenharmony_ci 93508eddcSopenharmony_citry: 103508eddcSopenharmony_ci import tqdm 113508eddcSopenharmony_ci 123508eddcSopenharmony_ci progress = tqdm.tqdm 133508eddcSopenharmony_ciexcept Exception: 143508eddcSopenharmony_ci progress = lambda x: x 153508eddcSopenharmony_ci 163508eddcSopenharmony_cimatplotlib.use("Agg") 173508eddcSopenharmony_ciimport matplotlib.pyplot as plt 183508eddcSopenharmony_ci 193508eddcSopenharmony_ci 203508eddcSopenharmony_cig = Github(os.environ["GITHUB_TOKEN"]) 213508eddcSopenharmony_cisources = json.load(open("fontrepos.json")) 223508eddcSopenharmony_ci 233508eddcSopenharmony_cithis = datetime.now() 243508eddcSopenharmony_ci 253508eddcSopenharmony_ciclosed_per_month = Counter() 263508eddcSopenharmony_ciopened_per_month = Counter() 273508eddcSopenharmony_ciopen_per_repo = Counter() 283508eddcSopenharmony_ciopen_per_tier = Counter() 293508eddcSopenharmony_cireleases_per_month = {} 303508eddcSopenharmony_citotals_per_month = {} 313508eddcSopenharmony_ciissues_by_age = {} 323508eddcSopenharmony_ci 333508eddcSopenharmony_citotal = 0 343508eddcSopenharmony_cifor repo_name in progress(list(sources.keys())): 353508eddcSopenharmony_ci # if repo_name not in org_names: 363508eddcSopenharmony_ci # continue 373508eddcSopenharmony_ci repo = g.get_repo("notofonts/" + repo_name) 383508eddcSopenharmony_ci issues = repo.get_issues(state="all") 393508eddcSopenharmony_ci tier = sources[repo_name].get("tier", 3) 403508eddcSopenharmony_ci for i in issues: 413508eddcSopenharmony_ci if i.state == "open": 423508eddcSopenharmony_ci total += 1 433508eddcSopenharmony_ci open_per_repo[repo_name] += 1 443508eddcSopenharmony_ci open_per_tier[tier] += 1 453508eddcSopenharmony_ci if i.created_at.year == this.year: 463508eddcSopenharmony_ci opened_per_month[i.created_at.month] += 1 473508eddcSopenharmony_ci elif i.closed_at.year == this.year: 483508eddcSopenharmony_ci closed_per_month[i.closed_at.month] += 1 493508eddcSopenharmony_ci 503508eddcSopenharmony_ci releases = repo.get_releases() 513508eddcSopenharmony_ci for release in sorted( 523508eddcSopenharmony_ci releases, key=lambda r: r.published_at.isoformat() if r.published_at else "" 533508eddcSopenharmony_ci ): 543508eddcSopenharmony_ci if release.draft: 553508eddcSopenharmony_ci continue 563508eddcSopenharmony_ci releases_per_month.setdefault(release.published_at.month, []).append( 573508eddcSopenharmony_ci {"tag": release.tag_name, "url": release.html_url} 583508eddcSopenharmony_ci ) 593508eddcSopenharmony_ci 603508eddcSopenharmony_ci# Back-compute totals per month 613508eddcSopenharmony_citotals_per_month[this.month] = total 623508eddcSopenharmony_cifor m in range(this.month, 0, -1): 633508eddcSopenharmony_ci total += closed_per_month[m] - opened_per_month[m] 643508eddcSopenharmony_ci totals_per_month[m] = total 653508eddcSopenharmony_ci 663508eddcSopenharmony_ci# Save it 673508eddcSopenharmony_cijson.dump( 683508eddcSopenharmony_ci { 693508eddcSopenharmony_ci "opened_per_month": opened_per_month, 703508eddcSopenharmony_ci "closed_per_month": closed_per_month, 713508eddcSopenharmony_ci "totals_per_month": totals_per_month, 723508eddcSopenharmony_ci "open_per_repo": open_per_repo, 733508eddcSopenharmony_ci "open_per_tier": open_per_tier, 743508eddcSopenharmony_ci "releases_per_month": releases_per_month, 753508eddcSopenharmony_ci }, 763508eddcSopenharmony_ci open("docs/issues.json", "w"), 773508eddcSopenharmony_ci indent=True, 783508eddcSopenharmony_ci sort_keys=True, 793508eddcSopenharmony_ci) 803508eddcSopenharmony_ci 813508eddcSopenharmony_ciyear_to_date = range(1, this.month + 1) 823508eddcSopenharmony_ci 833508eddcSopenharmony_cimonths = [ 843508eddcSopenharmony_ci "Jan", 853508eddcSopenharmony_ci "Feb", 863508eddcSopenharmony_ci "Mar", 873508eddcSopenharmony_ci "Apr", 883508eddcSopenharmony_ci "May", 893508eddcSopenharmony_ci "Jun", 903508eddcSopenharmony_ci "Jul", 913508eddcSopenharmony_ci "Aug", 923508eddcSopenharmony_ci "Sep", 933508eddcSopenharmony_ci "Oct", 943508eddcSopenharmony_ci "Nov", 953508eddcSopenharmony_ci "Dec", 963508eddcSopenharmony_ci][: this.month] 973508eddcSopenharmony_citotals = [totals_per_month[i] for i in year_to_date] 983508eddcSopenharmony_ci 993508eddcSopenharmony_cifig, ax1 = plt.subplots() 1003508eddcSopenharmony_ciax2 = ax1.twinx() 1013508eddcSopenharmony_ci 1023508eddcSopenharmony_cibars = ax1.bar( 1033508eddcSopenharmony_ci months, 1043508eddcSopenharmony_ci [totals_per_month[i] for i in year_to_date], 1053508eddcSopenharmony_ci label="Total", 1063508eddcSopenharmony_ci color="#aaaaffaa", 1073508eddcSopenharmony_ci) 1083508eddcSopenharmony_ciax1.bar_label(bars) 1093508eddcSopenharmony_ciax1.axes.get_yaxis().set_visible(False) 1103508eddcSopenharmony_ci 1113508eddcSopenharmony_cilns1 = ax2.plot( 1123508eddcSopenharmony_ci months, 1133508eddcSopenharmony_ci [opened_per_month[i] for i in year_to_date], 1143508eddcSopenharmony_ci marker=".", 1153508eddcSopenharmony_ci label="Opened", 1163508eddcSopenharmony_ci color="red", 1173508eddcSopenharmony_ci linewidth=3, 1183508eddcSopenharmony_ci) 1193508eddcSopenharmony_cilns2 = ax2.plot( 1203508eddcSopenharmony_ci months, 1213508eddcSopenharmony_ci [closed_per_month[i] for i in year_to_date], 1223508eddcSopenharmony_ci marker="+", 1233508eddcSopenharmony_ci label="Closed", 1243508eddcSopenharmony_ci color="green", 1253508eddcSopenharmony_ci linewidth=3, 1263508eddcSopenharmony_ci) 1273508eddcSopenharmony_ci 1283508eddcSopenharmony_cilines, labels = ax1.get_legend_handles_labels() 1293508eddcSopenharmony_cilines2, labels2 = ax2.get_legend_handles_labels() 1303508eddcSopenharmony_ciax2.legend(lines + lines2, labels + labels2, loc="lower left") 1313508eddcSopenharmony_ciplt.title("Issues opened, closed, and open") 1323508eddcSopenharmony_ciplt.savefig("docs/open-closed.png") 1333508eddcSopenharmony_ci 1343508eddcSopenharmony_ci 1353508eddcSopenharmony_ci## Top 10 scripts 1363508eddcSopenharmony_citop_10 = sorted(open_per_repo.most_common(10), key=lambda x: -x[1]) 1373508eddcSopenharmony_cilabels, values = list(zip(*top_10)) 1383508eddcSopenharmony_cifig, ax = plt.subplots() 1393508eddcSopenharmony_cibars = ax.bar(labels, values) 1403508eddcSopenharmony_ciax.bar_label(bars) 1413508eddcSopenharmony_ciplt.title("Repositories with most open issues") 1423508eddcSopenharmony_ciplt.xticks(rotation=60) 1433508eddcSopenharmony_ciplt.tight_layout() 1443508eddcSopenharmony_ciplt.savefig("docs/top-10.png") 1453508eddcSopenharmony_ci 1463508eddcSopenharmony_ci 1473508eddcSopenharmony_ci# Low hanging fruit and tiers 1483508eddcSopenharmony_cilow_hanging = {} 1493508eddcSopenharmony_citiers = {1: [], 2: [], 3: [], 4: [], 5: []} 1503508eddcSopenharmony_cifor k, v in open_per_repo.items(): 1513508eddcSopenharmony_ci if v == 0: 1523508eddcSopenharmony_ci continue 1533508eddcSopenharmony_ci tier = sources[k].get("tier", 3) 1543508eddcSopenharmony_ci tiers[tier].append({"repo": k, "issues": v}) 1553508eddcSopenharmony_ci if v > 10: 1563508eddcSopenharmony_ci continue 1573508eddcSopenharmony_ci low_hanging.setdefault(v, []).append(k) 1583508eddcSopenharmony_cilow_hanging = [ 1593508eddcSopenharmony_ci {"issues": k, "repos": low_hanging[k]} for k in sorted(low_hanging.keys()) 1603508eddcSopenharmony_ci] 1613508eddcSopenharmony_ci 1623508eddcSopenharmony_citiers = {k: sorted(v, key=lambda i: -i["issues"]) for k, v in tiers.items()} 1633508eddcSopenharmony_ci 1643508eddcSopenharmony_cilabels = [1, 2, 3, 4, 5] 1653508eddcSopenharmony_civalues = [open_per_tier.get(l, 0) for l in labels] 1663508eddcSopenharmony_cifig, ax = plt.subplots() 1673508eddcSopenharmony_cibars = ax.bar(labels, values) 1683508eddcSopenharmony_ciax.bar_label(bars) 1693508eddcSopenharmony_ciplt.title("Open issues per tier") 1703508eddcSopenharmony_ciplt.tight_layout() 1713508eddcSopenharmony_ciplt.savefig("docs/per-tier.png") 1723508eddcSopenharmony_ci 1733508eddcSopenharmony_ci## Releases per month 1743508eddcSopenharmony_cirelease_count_per_month = [len(releases_per_month.get(i, [])) for i in year_to_date] 1753508eddcSopenharmony_cifig, ax = plt.subplots() 1763508eddcSopenharmony_cibars = ax.bar(months, release_count_per_month) 1773508eddcSopenharmony_ciax.bar_label(bars) 1783508eddcSopenharmony_ciplt.title("Releases per month") 1793508eddcSopenharmony_ciplt.savefig("docs/releases.png") 1803508eddcSopenharmony_ci 1813508eddcSopenharmony_cimonthly_stats = [ 1823508eddcSopenharmony_ci { 1833508eddcSopenharmony_ci "month": months[i - 1], 1843508eddcSopenharmony_ci "opened": opened_per_month.get(i, 0), 1853508eddcSopenharmony_ci "closed": closed_per_month.get(i, 0), 1863508eddcSopenharmony_ci "releases": releases_per_month.get(i, []), 1873508eddcSopenharmony_ci "releases_count": len(releases_per_month.get(i, [])), 1883508eddcSopenharmony_ci } 1893508eddcSopenharmony_ci for i in year_to_date 1903508eddcSopenharmony_ci] 1913508eddcSopenharmony_ci 1923508eddcSopenharmony_cicompiler = Compiler() 1933508eddcSopenharmony_citemplate = open("scripts/analytics-template.html", "r").read() 1943508eddcSopenharmony_citemplate = compiler.compile(template) 1953508eddcSopenharmony_cioutput = template( 1963508eddcSopenharmony_ci { 1973508eddcSopenharmony_ci "monthly_stats": monthly_stats, 1983508eddcSopenharmony_ci "top_10": [{"repo": k, "count": v} for k, v in top_10], 1993508eddcSopenharmony_ci "low_hanging": low_hanging, 2003508eddcSopenharmony_ci "tiers": tiers, 2013508eddcSopenharmony_ci } 2023508eddcSopenharmony_ci) 2033508eddcSopenharmony_ci 2043508eddcSopenharmony_ciwith open("docs/analytics.html", "w") as fh: 2053508eddcSopenharmony_ci fh.write(output) 206