aboutsummaryrefslogtreecommitdiff
path: root/etc/scripts/util/formatcheck.py
blob: b56f810f2ad4d819932b55293aa996d09bb4e116 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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 = set(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()