2 Check repository settings.
8 from subprocess import Popen, PIPE
10 from argparse import ArgumentParser
12 from util import Reporter, require
14 # Import this way to produce a more useful error message.
18 print('Unable to import requests module: please install requests', file=sys.stderr)
22 # Pattern to match Git command-line output for remotes => (user name, project name).
23 P_GIT_REMOTE = re.compile(r'upstream\s+[^:]+:([^/]+)/([^.]+)\.git\s+\(fetch\)')
25 # Repository URL format string.
26 F_REPO_URL = 'https://github.com/{0}/{1}/'
28 # Pattern to match repository URLs => (user name, project name)
29 P_REPO_URL = re.compile(r'https?://github\.com/([^.]+)/([^/]+)/?')
31 # API URL format string.
32 F_API_URL = 'https://api.github.com/repos/{0}/{1}/labels'
34 # Expected labels and colors.
36 'help wanted': 'dcecc7',
37 'status:in progress': '9bcc65',
38 'status:changes requested': '679f38',
39 'status:wait': 'fff2df',
40 'status:refer to cac': 'ffdfb2',
41 'status:need more info': 'ee6c00',
42 'status:blocked': 'e55100',
43 'status:out of scope': 'eeeeee',
44 'status:duplicate': 'bdbdbd',
45 'type:typo text': 'f8bad0',
47 'type:formatting': 'ac1357',
48 'type:template and tools': '7985cb',
49 'type:instructor guide': '00887a',
50 'type:discussion': 'b2e5fc',
51 'type:enhancement': '7fdeea',
52 'type:clarification': '00acc0',
53 'type:teaching example': 'ced8dc',
54 'good first issue': 'ffeb3a',
55 'high priority': 'd22e2e'
66 repo_url = get_repo_url(args.repo_url)
67 check_labels(reporter, repo_url)
73 Parse command-line arguments.
76 parser = ArgumentParser(description="""Check repository settings.""")
77 parser.add_argument('-r', '--repo',
80 help='repository URL')
81 parser.add_argument('-s', '--source',
84 help='source directory')
86 args, extras = parser.parse_known_args()
88 'Unexpected trailing command-line arguments "{0}"'.format(extras))
93 def get_repo_url(repo_url):
95 Figure out which repository to query.
98 # Explicitly specified.
99 if repo_url is not None:
103 cmd = 'git remote -v'
104 p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE,
105 close_fds=True, universal_newlines=True)
106 stdout_data, stderr_data = p.communicate()
107 stdout_data = stdout_data.split('\n')
108 matches = [P_GIT_REMOTE.match(line) for line in stdout_data]
109 matches = [m for m in matches if m is not None]
110 require(len(matches) == 1,
111 'Unexpected output from git remote command: "{0}"'.format(matches))
113 username = matches[0].group(1)
115 username, 'empty username in git remote output {0}'.format(matches[0]))
117 project_name = matches[0].group(2)
119 username, 'empty project name in git remote output {0}'.format(matches[0]))
121 url = F_REPO_URL.format(username, project_name)
125 def check_labels(reporter, repo_url):
127 Check labels in repository.
130 actual = get_labels(repo_url)
131 extra = set(actual.keys()) - set(EXPECTED.keys())
133 reporter.check(not extra,
135 'Extra label(s) in repository {0}: {1}',
136 repo_url, ', '.join(sorted(extra)))
138 missing = set(EXPECTED.keys()) - set(actual.keys())
139 reporter.check(not missing,
141 'Missing label(s) in repository {0}: {1}',
142 repo_url, ', '.join(sorted(missing)))
144 overlap = set(EXPECTED.keys()).intersection(set(actual.keys()))
145 for name in sorted(overlap):
146 reporter.check(EXPECTED[name].lower() == actual[name].lower(),
148 'Color mis-match for label {0} in {1}: expected {2}, found {3}',
149 name, repo_url, EXPECTED[name], actual[name])
152 def get_labels(repo_url):
154 Get actual labels from repository.
157 m = P_REPO_URL.match(repo_url)
159 m, 'repository URL {0} does not match expected pattern'.format(repo_url))
161 username = m.group(1)
162 require(username, 'empty username in repository URL {0}'.format(repo_url))
164 project_name = m.group(2)
166 username, 'empty project name in repository URL {0}'.format(repo_url))
168 url = F_API_URL.format(username, project_name)
169 r = requests.get(url)
170 require(r.status_code == 200,
171 'Request for {0} failed with {1}'.format(url, r.status_code))
174 for entry in r.json():
175 result[entry['name']] = entry['color']
179 if __name__ == '__main__':