-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrepoupdater.py
137 lines (108 loc) · 3.83 KB
/
repoupdater.py
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import argparse
import glob
import os
import re
import sys
import subprocess
from github import Github
from github.GithubException import GithubException
import yaml
import client
ORG_NAME = "OpenSAFELY"
BASE_PATH = os.path.abspath("research")
def main():
parser = argparse.ArgumentParser(prog="repoupdater")
subparsers = parser.add_subparsers(help="sub-command help", dest="subcommand")
list_parser = subparsers.add_parser("list", help="list all repos")
update_parser = subparsers.add_parser(
"update", help="update all repos via pull or clone"
)
exec_parser = subparsers.add_parser(
"exec", help="execute command against all repos"
)
exec_parser.add_argument("command")
exec_parser.add_argument("args", nargs="*")
pull_request_parser = subparsers.add_parser(
"pull-request", help="submit pull request against each repo"
)
pull_request_parser.add_argument("branch")
pull_request_parser.add_argument("title")
pull_request_parser.add_argument('--merge', action='store_true')
args = parser.parse_args()
if args.subcommand == "list":
list_repos()
elif args.subcommand == "update":
update()
elif args.subcommand == "exec":
exec_in_repos([args.command] + args.args)
elif args.subcommand == "pull-request":
pull_request(args.branch, args.title, args.merge)
else:
assert False, args.subcommand
def list_repos():
client = get_client()
for repo in get_repos(client):
print(repo.html_url)
def update():
client = get_client()
repos = get_repos(client)
if check_for_uncommitted_changes(repos):
sys.exit(1)
for repo in repos:
path = os.path.join(BASE_PATH, repo.name)
print("-" * 80)
print(repo.name)
if os.path.exists(path):
os.chdir(path)
subprocess.run(["git", "checkout", "master"], check=True)
subprocess.run(["git", "pull"], check=True)
else:
subprocess.run(["git", "clone", repo.ssh_url, path], check=True)
def exec_in_repos(argv):
for path in sorted(glob.glob(os.path.join(BASE_PATH, "*"))):
print("-" * 80)
print(os.path.basename(path))
os.chdir(path)
subprocess.run(argv)
def pull_request(branch, title, merge):
client = get_client()
repos = get_repos(client)
for repo in repos:
path = os.path.join(BASE_PATH, repo.name)
print("-" * 80)
print(repo.name)
os.chdir(path)
subprocess.run(["git", "checkout", branch], check=True)
subprocess.run(["git", "push", "-u", "origin", branch], check=True)
try:
pr = repo.create_pull(head=branch, base="master", title=title, body="")
except GithubException as e:
if e.status == 422:
print(e)
continue
raise
if merge:
pr.merge()
def get_client():
return client.github_client()
def get_repos(client, org_name=ORG_NAME):
org = client.get_organization(org_name)
config = yaml.safe_load(open('config.yaml'))
excluded = config.get('non_study_repos', [])
repos = [repo for repo in org.get_repos() if repo.full_name not in excluded]
return sorted(repos, key=lambda repo: repo.name)
def check_for_uncommitted_changes(repos):
found_uncommitted_changes = False
for repo in repos:
path = os.path.join(BASE_PATH, repo.name)
if os.path.exists(path):
os.chdir(path)
p = subprocess.run(["git", "status", "--porcelain"], capture_output=True)
if p.stdout:
print("-" * 80)
print(f"Uncommitted changes to {repo.name}")
subprocess.run(["git", "status"])
found_uncommitted_changes = True
return found_uncommitted_changes
if __name__ == "__main__":
main()