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