4 Check repository settings.
7 from __future__ import print_function
10 from subprocess import Popen, PIPE
12 from optparse import OptionParser
14 from util import Reporter, load_yaml, require
16 # Import this way to produce a more useful error message.
20 print('Unable to import requests module: please install requests', file=sys.stderr)
24 # Pattern to match Git command-line output for remotes => (user name, project name).
25 P_GIT_REMOTE = re.compile(r'upstream\s+[^:]+:([^/]+)/([^.]+)\.git\s+\(fetch\)')
27 # Repository URL format string.
28 F_REPO_URL = 'https://github.com/{0}/{1}/'
30 # Pattern to match repository URLs => (user name, project name)
31 P_REPO_URL = re.compile(r'https?://github\.com/([^.]+)/([^/]+)/?')
33 # API URL format string.
34 F_API_URL = 'https://api.github.com/repos/{0}/{1}/labels'
36 # Expected labels and colors.
38 'help wanted' : 'dcecc7',
39 'status:in progress' : '9bcc65',
40 'status:changes requested' : '679f38',
41 'status:wait' : 'fff2df',
42 'status:refer to cac' : 'ffdfb2',
43 'status:need more info' : 'ee6c00',
44 'status:blocked' : 'e55100',
45 'status:out of scope' : 'eeeeee',
46 'status:duplicate' : 'bdbdbd',
47 'type:typo text' : 'f8bad0',
48 'type:bug' : 'eb3f79',
49 'type:formatting' : 'ac1357',
50 'type:template and tools' : '7985cb',
51 'type:instructor guide' : '00887a',
52 'type:discussion' : 'b2e5fc',
53 'type:enhancement' : '7fdeea',
54 'type:clarification' : '00acc0',
55 'type:teaching example' : 'ced8dc',
56 'good first issue' : 'ffeb3a',
57 'high priority' : 'd22e2e'
68 repo_url = get_repo_url(args.source_dir, args.repo_url)
69 check_labels(reporter, repo_url)
75 Parse command-line arguments.
78 parser = OptionParser()
79 parser.add_option('-r', '--repo',
82 help='repository URL')
83 parser.add_option('-s', '--source',
86 help='source directory')
88 args, extras = parser.parse_args()
90 'Unexpected trailing command-line arguments "{0}"'.format(extras))
95 def get_repo_url(source_dir, repo_url):
97 Figure out which repository to query.
100 # Explicitly specified.
101 if repo_url is not None:
105 cmd = 'git remote -v'
106 p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, close_fds=True, universal_newlines=True)
107 stdout_data, stderr_data = p.communicate()
108 stdout_data = stdout_data.split('\n')
109 matches = [P_GIT_REMOTE.match(line) for line in stdout_data]
110 matches = [m for m in matches if m is not None]
111 require(len(matches) == 1,
112 'Unexpected output from git remote command: "{0}"'.format(matches))
114 username = matches[0].group(1)
115 require(username, 'empty username in git remote output {0}'.format(matches[0]))
117 project_name = matches[0].group(2)
118 require(username, 'empty project name in git remote output {0}'.format(matches[0]))
120 url = F_REPO_URL.format(username, project_name)
124 def check_labels(reporter, repo_url):
126 Check labels in repository.
129 actual = get_labels(repo_url)
130 extra = set(actual.keys()) - set(EXPECTED.keys())
132 reporter.check(not extra,
134 'Extra label(s) in repository {0}: {1}',
135 repo_url, ', '.join(sorted(extra)))
137 missing = set(EXPECTED.keys()) - set(actual.keys())
138 reporter.check(not missing,
140 'Missing label(s) in repository {0}: {1}',
141 repo_url, ', '.join(sorted(missing)))
143 overlap = set(EXPECTED.keys()).intersection(set(actual.keys()))
144 for name in sorted(overlap):
145 reporter.check(EXPECTED[name].lower() == actual[name].lower(),
147 'Color mis-match for label {0} in {1}: expected {2}, found {3}',
148 name, repo_url, EXPECTED[name], actual[name])
151 def get_labels(repo_url):
153 Get actual labels from repository.
156 m = P_REPO_URL.match(repo_url)
157 require(m, 'repository URL {0} does not match expected pattern'.format(repo_url))
159 username = m.group(1)
160 require(username, 'empty username in repository URL {0}'.format(repo_url))
162 project_name = m.group(2)
163 require(username, 'empty project name in repository URL {0}'.format(repo_url))
165 url = F_API_URL.format(username, project_name)
166 r = requests.get(url)
167 require(r.status_code == 200,
168 'Request for {0} failed with {1}'.format(url, r.status_code))
171 for entry in r.json():
172 result[entry['name']] = entry['color']
176 if __name__ == '__main__':