13508eddcSopenharmony_cifrom github import Github, Repository 23508eddcSopenharmony_cifrom gftools.utils import download_file 33508eddcSopenharmony_cifrom zipfile import ZipFile 43508eddcSopenharmony_cifrom pathlib import Path 53508eddcSopenharmony_ciimport tempfile 63508eddcSopenharmony_ciimport os 73508eddcSopenharmony_ciimport json 83508eddcSopenharmony_cifrom io import BytesIO 93508eddcSopenharmony_cifrom pybars import Compiler, strlist 103508eddcSopenharmony_ciimport re 113508eddcSopenharmony_ciimport subprocess 123508eddcSopenharmony_ci 133508eddcSopenharmony_ci 143508eddcSopenharmony_ciTESTING = False 153508eddcSopenharmony_ciSPECIAL_REPOS = [ 163508eddcSopenharmony_ci "notofonts.github.io", 173508eddcSopenharmony_ci "overview", 183508eddcSopenharmony_ci ".github", 193508eddcSopenharmony_ci ".allstar", 203508eddcSopenharmony_ci "notobuilder", 213508eddcSopenharmony_ci "noto-data-dev", 223508eddcSopenharmony_ci "noto-docs", 233508eddcSopenharmony_ci "noto-project-template", 243508eddcSopenharmony_ci "notoglot-mini", 253508eddcSopenharmony_ci] 263508eddcSopenharmony_ci 273508eddcSopenharmony_ci 283508eddcSopenharmony_cidef fonts_from_zip(zipfile, dst=None): 293508eddcSopenharmony_ci """Unzip fonts. If not dst is given unzip as BytesIO objects""" 303508eddcSopenharmony_ci fonts = [] 313508eddcSopenharmony_ci for filename in zipfile.namelist(): 323508eddcSopenharmony_ci if filename.endswith(".ttf") or filename.endswith(".otf"): 333508eddcSopenharmony_ci if dst: 343508eddcSopenharmony_ci target = os.path.join(dst, filename) 353508eddcSopenharmony_ci zipfile.extract(filename, dst) 363508eddcSopenharmony_ci fonts.append(target) 373508eddcSopenharmony_ci else: 383508eddcSopenharmony_ci fonts.append(BytesIO(zipfile.read(filename))) 393508eddcSopenharmony_ci return fonts 403508eddcSopenharmony_ci 413508eddcSopenharmony_ci 423508eddcSopenharmony_cidef tree_has_new_files(): 433508eddcSopenharmony_ci ls = subprocess.run(["git", "ls-files", "--others"], capture_output=True) 443508eddcSopenharmony_ci return ls.stdout 453508eddcSopenharmony_ci 463508eddcSopenharmony_ci 473508eddcSopenharmony_ciprint("Fetching existing repos") 483508eddcSopenharmony_cig = Github(os.environ["GITHUB_TOKEN"]) 493508eddcSopenharmony_ciorg = g.get_organization("notofonts") 503508eddcSopenharmony_ciorg_repos = org.get_repos() 513508eddcSopenharmony_ciorg_names = [r.name for r in org_repos] 523508eddcSopenharmony_ci 533508eddcSopenharmony_cisubprocess.run(["git", "config", "user.name", "actions-user"]) 543508eddcSopenharmony_cisubprocess.run(["git", "config", "user.email", "actions-user@users.noreply.github.com"]) 553508eddcSopenharmony_ci 563508eddcSopenharmony_cito_push = [] 573508eddcSopenharmony_ci 583508eddcSopenharmony_cifontrepos = json.load(open("fontrepos.json")) 593508eddcSopenharmony_ciif os.path.exists("state.json"): 603508eddcSopenharmony_ci state = json.load(open("state.json")) 613508eddcSopenharmony_cielse: 623508eddcSopenharmony_ci state = {} 633508eddcSopenharmony_ci 643508eddcSopenharmony_ciresults = {} 653508eddcSopenharmony_ci 663508eddcSopenharmony_cifor repo_name in org_names: 673508eddcSopenharmony_ci if repo_name in SPECIAL_REPOS: 683508eddcSopenharmony_ci continue 693508eddcSopenharmony_ci repo = g.get_repo("notofonts/" + repo_name) 703508eddcSopenharmony_ci if repo.archived: 713508eddcSopenharmony_ci continue 723508eddcSopenharmony_ci if repo_name not in fontrepos: 733508eddcSopenharmony_ci print("Unknown repo %s; is it missing from fontrepos?" % repo_name) 743508eddcSopenharmony_ci continue 753508eddcSopenharmony_ci 763508eddcSopenharmony_ci print(f"Gathering data for {repo_name}") 773508eddcSopenharmony_ci 783508eddcSopenharmony_ci repo = g.get_repo("notofonts/" + repo_name) 793508eddcSopenharmony_ci results[repo_name] = { 803508eddcSopenharmony_ci "title": repo.description, 813508eddcSopenharmony_ci "tier": fontrepos[repo_name].get("tier", 3), 823508eddcSopenharmony_ci "gh_url": "https://notofonts.github.io/" + repo_name, 833508eddcSopenharmony_ci "repo_url": "https://www.github.com/notofonts/" + repo_name, 843508eddcSopenharmony_ci } 853508eddcSopenharmony_ci 863508eddcSopenharmony_ci # Get issues 873508eddcSopenharmony_ci results[repo_name]["issues"] = [] 883508eddcSopenharmony_ci for issue in repo.get_issues(): 893508eddcSopenharmony_ci results[repo_name]["issues"].append( 903508eddcSopenharmony_ci {"title": issue.title, "number": issue.number, "url": issue.html_url} 913508eddcSopenharmony_ci ) 923508eddcSopenharmony_ci 933508eddcSopenharmony_ci if repo_name not in state: 943508eddcSopenharmony_ci state[repo_name] = {} 953508eddcSopenharmony_ci 963508eddcSopenharmony_ci # Check for new releases 973508eddcSopenharmony_ci releases = repo.get_releases() 983508eddcSopenharmony_ci for release in sorted( 993508eddcSopenharmony_ci releases, key=lambda r: r.published_at.isoformat() if r.published_at else "" 1003508eddcSopenharmony_ci ): 1013508eddcSopenharmony_ci m = re.match(r"^(.*)-(v[\d.]+)", release.tag_name) 1023508eddcSopenharmony_ci if not m: 1033508eddcSopenharmony_ci print(f"Unparsable release {release.tag_name} in {repo_name}") 1043508eddcSopenharmony_ci continue 1053508eddcSopenharmony_ci if release.draft: 1063508eddcSopenharmony_ci continue 1073508eddcSopenharmony_ci family, version = m[1], m[2] 1083508eddcSopenharmony_ci family = re.sub(r"([a-z])([A-Z])", r"\1 \2", family) 1093508eddcSopenharmony_ci if release.tag_name in state[repo_name].get("known_releases", []): 1103508eddcSopenharmony_ci continue 1113508eddcSopenharmony_ci assets = release.get_assets() 1123508eddcSopenharmony_ci if not assets: 1133508eddcSopenharmony_ci continue 1143508eddcSopenharmony_ci latest_asset = assets[0] 1153508eddcSopenharmony_ci state[repo_name].setdefault("known_releases", []).append(release.tag_name) 1163508eddcSopenharmony_ci family_thing = ( 1173508eddcSopenharmony_ci state[repo_name].setdefault("families", {}).setdefault(family, {}) 1183508eddcSopenharmony_ci ) 1193508eddcSopenharmony_ci 1203508eddcSopenharmony_ci body = release.body 1213508eddcSopenharmony_ci if not body: 1223508eddcSopenharmony_ci tag_sha = repo.get_git_ref("tags/" + release.tag_name).object.sha 1233508eddcSopenharmony_ci try: 1243508eddcSopenharmony_ci body = repo.get_git_tag(tag_sha).message 1253508eddcSopenharmony_ci except Exception as e: 1263508eddcSopenharmony_ci print("Couldn't retrieve release message for %s" % release.tag_name) 1273508eddcSopenharmony_ci 1283508eddcSopenharmony_ci family_thing["latest_release"] = { 1293508eddcSopenharmony_ci "url": release.html_url, 1303508eddcSopenharmony_ci "version": version, 1313508eddcSopenharmony_ci "notes": body, 1323508eddcSopenharmony_ci } 1333508eddcSopenharmony_ci 1343508eddcSopenharmony_ci if release.published_at: 1353508eddcSopenharmony_ci family_thing["latest_release"][ 1363508eddcSopenharmony_ci "published" 1373508eddcSopenharmony_ci ] = release.published_at.isoformat() 1383508eddcSopenharmony_ci 1393508eddcSopenharmony_ci try: 1403508eddcSopenharmony_ci z = ZipFile(download_file(latest_asset.browser_download_url)) 1413508eddcSopenharmony_ci family_thing["files"] = [] 1423508eddcSopenharmony_ci with tempfile.TemporaryDirectory() as tmpdir: 1433508eddcSopenharmony_ci fonts = fonts_from_zip(z, tmpdir) 1443508eddcSopenharmony_ci for font in fonts: 1453508eddcSopenharmony_ci newpath = Path("fonts/") / Path(font).relative_to(tmpdir) 1463508eddcSopenharmony_ci os.makedirs(newpath.parent, exist_ok=True) 1473508eddcSopenharmony_ci family_thing["files"].append(str(newpath)) 1483508eddcSopenharmony_ci os.rename(font, newpath) 1493508eddcSopenharmony_ci if tree_has_new_files() and not TESTING: 1503508eddcSopenharmony_ci # Add it and tag it 1513508eddcSopenharmony_ci subprocess.run(["git", "add", "."]) 1523508eddcSopenharmony_ci subprocess.run(["git", "commit", "-m", "Add " + release.tag_name]) 1533508eddcSopenharmony_ci subprocess.run(["git", "tag", release.tag_name]) 1543508eddcSopenharmony_ci to_push.append(release.tag_name) 1553508eddcSopenharmony_ci except Exception as e: 1563508eddcSopenharmony_ci print("Couldn't fetch download for %s" % latest_asset.browser_download_url) 1573508eddcSopenharmony_ci 1583508eddcSopenharmony_ci # Tweet about the new release or something 1593508eddcSopenharmony_ci results[repo_name]["families"] = state[repo_name].get("families", {}) 1603508eddcSopenharmony_ci 1613508eddcSopenharmony_cisubprocess.run(["git", "push"]) 1623508eddcSopenharmony_cifor tag in to_push: 1633508eddcSopenharmony_ci subprocess.run(["git", "push", "origin", tag]) 1643508eddcSopenharmony_ci 1653508eddcSopenharmony_ci# Save state 1663508eddcSopenharmony_cijson.dump(state, open("state.json", "w"), indent=True, sort_keys=True) 1673508eddcSopenharmony_ci 1683508eddcSopenharmony_cifor result in results.values(): 1693508eddcSopenharmony_ci for family in result.get("families", {}).values(): 1703508eddcSopenharmony_ci newfiles = {"unhinted": [], "hinted": [], "full": []} 1713508eddcSopenharmony_ci for file in sorted(family.get("files", [])): 1723508eddcSopenharmony_ci if "unhinted" in file: 1733508eddcSopenharmony_ci newfiles["unhinted"].append(file) 1743508eddcSopenharmony_ci elif "hinted" in file: 1753508eddcSopenharmony_ci newfiles["hinted"].append(file) 1763508eddcSopenharmony_ci elif "full" in file: 1773508eddcSopenharmony_ci newfiles["full"].append(file) 1783508eddcSopenharmony_ci family["files"] = newfiles 1793508eddcSopenharmony_ci 1803508eddcSopenharmony_cijson.dump(results, open("docs/noto.json", "w"), indent=True, sort_keys=True) 181