|  | import sys | 
|  | import urllib.request | 
|  | import urllib.parse | 
|  | import json | 
|  | import subprocess | 
|  | import os.path | 
|  |  | 
|  |  | 
|  | from typing import Set | 
|  |  | 
|  | OWNER_REPO = "" | 
|  | ACCESS_TOKEN = "" | 
|  | USER_AGENT = "" | 
|  |  | 
|  |  | 
|  | def get(entity: str, query: dict = None) -> dict: | 
|  | if query is None: | 
|  | query = {} | 
|  | path = entity | 
|  | if query: | 
|  | querystring = urllib.parse.urlencode(query) | 
|  | path += f"?{querystring}" | 
|  | print(f"Getting {path}") | 
|  | req = urllib.request.Request( | 
|  | f"https://api.github.com/{path}", | 
|  | None, | 
|  | { | 
|  | "User-Agent": USER_AGENT, | 
|  | "Authorization": f"token {ACCESS_TOKEN}", | 
|  | "Accept": "application/vnd.github.v3+json", | 
|  | }, | 
|  | ) | 
|  | result = urllib.request.urlopen(req) | 
|  | # It's ok not to check for error codes here. We'll throw either way | 
|  | return json.loads(result.read()) | 
|  |  | 
|  |  | 
|  | def paginated_get(entity: str, query: dict = None) -> [dict]: | 
|  | if query is None: | 
|  | query = {} | 
|  | result = [] | 
|  | results_per_page = 50 | 
|  | query["page"] = 1 | 
|  | query["per_page"] = results_per_page | 
|  | while True: | 
|  | current_page_results = get(entity, query) | 
|  | result.extend(current_page_results) | 
|  | if len(current_page_results) == results_per_page: | 
|  | query["page"] += 1 | 
|  | else: | 
|  | break | 
|  | return result | 
|  |  | 
|  |  | 
|  | def list_open_prs(stale_label: str = None) -> [dict]: | 
|  | prs = paginated_get(f"repos/{OWNER_REPO}/pulls", {"state": "open"}) | 
|  | if stale_label is not None: | 
|  | return [pr for pr in prs if not any(label["name"] == stale_label for label in pr["labels"])] | 
|  | return prs | 
|  |  | 
|  |  | 
|  | def list_pr_files(pr: dict) -> [dict]: | 
|  | return paginated_get(f'repos/{OWNER_REPO}/pulls/{pr["number"]}/files') | 
|  |  | 
|  |  | 
|  | def list_modified_paths_in_pr(pr: dict) -> Set[str]: | 
|  | pr_paths = list_pr_files(pr) | 
|  | filtered = {x["filename"] for x in pr_paths if x["status"] == "modified"} | 
|  | return filtered | 
|  |  | 
|  |  | 
|  | def list_files_under_vc() -> Set[str]: | 
|  | output = subprocess.check_output( | 
|  | ["git", "ls-tree", "-r", "main", "--name-only"] | 
|  | ).decode("utf-8") | 
|  | paths = {x for x in output.splitlines()} | 
|  | return paths | 
|  |  | 
|  |  | 
|  | def make_file_formateable(path: str): | 
|  | try: | 
|  | with open(path, "r+") as f: | 
|  | content = ["/**\n", " * @prettier\n", " */\n"] | 
|  | file_contents = f.readlines() | 
|  | if file_contents[0:3] != content: | 
|  | content.extend(file_contents) | 
|  | f.seek(0) | 
|  | f.writelines(content) | 
|  | f.truncate() | 
|  | except: | 
|  | print(f"Error making {path} formatable") | 
|  |  | 
|  |  | 
|  | def main(): | 
|  | # In case you want to save the result to avoid extra API calls | 
|  | use_file = False | 
|  | if not use_file or not os.path.isfile("./paths.json"): | 
|  | current_prs = list_open_prs(stale_label="likely-stale") | 
|  | modified_paths = set() | 
|  | for PR in current_prs: | 
|  | modified_paths.update(list_modified_paths_in_pr(PR)) | 
|  | current_git_files = list_files_under_vc() | 
|  | untouched_paths = list(current_git_files - modified_paths) | 
|  | if use_file: | 
|  | with open("./paths.json", "w") as f: | 
|  | json.dump(untouched_paths, f) | 
|  | else: | 
|  | with open("./paths.json", "r") as f: | 
|  | untouched_paths = json.load(f) | 
|  | js_files = {x for x in untouched_paths if x.endswith(".js")} | 
|  | for path in js_files: | 
|  | make_file_formateable(path) | 
|  |  | 
|  |  | 
|  | if __name__ == "__main__": | 
|  | if len(sys.argv) != 4: | 
|  | print(f"Usage: {os.path.basename(__file__)} OWNER/REPO ACCESS_TOKEN USER_AGENT") | 
|  | else: | 
|  | OWNER_REPO = sys.argv[1] | 
|  | ACCESS_TOKEN = sys.argv[2] | 
|  | USER_AGENT = sys.argv[3] | 
|  | main() |