4 Check repository settings.
9 from subprocess import Popen, PIPE
11 from optparse import OptionParser
13 from util import Reporter, load_yaml, require
15 # Import this way to produce a more useful error message.
19 print('Unable to import requests module: please install requests', file=sys.stderr)
23 # Pattern to match Git command-line output for remotes => (user name, project name).
24 P_GIT_REMOTE = re.compile(r'upstream\s+[^:]+:([^/]+)/([^.]+)\.git\s+\(fetch\)')
26 # Repository URL format string.
27 F_REPO_URL = 'https://github.com/{0}/{1}/'
29 # Pattern to match repository URLs => (user name, project name)
30 P_REPO_URL = re.compile(r'https?://github\.com/([^.]+)/([^/]+)/?')
32 # API URL format string.
33 F_API_URL = 'https://api.github.com/repos/{0}/{1}/labels'
35 # Expected labels and colors.
38 'discussion' : 'fc8dc1',
39 'enhancement' : '9cd6dc',
40 'help-wanted' : 'f4fd9c',
41 'instructor-training' : '6e5494',
42 'newcomer-friendly' : 'eec275',
43 'question' : '808040',
44 'template-and-tools' : '2b3990',
45 'work-in-progress' : '7ae78e'
56 repo_url = get_repo_url(args.source_dir, args.repo_url)
57 check_labels(reporter, repo_url)
63 Parse command-line arguments.
66 parser = OptionParser()
67 parser.add_option('-r', '--repo',
70 help='repository URL')
71 parser.add_option('-s', '--source',
74 help='source directory')
76 args, extras = parser.parse_args()
78 'Unexpected trailing command-line arguments "{0}"'.format(extras))
83 def get_repo_url(source_dir, repo_url):
85 Figure out which repository to query.
88 # Explicitly specified.
89 if repo_url is not None:
94 p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, close_fds=True, universal_newlines=True)
95 stdout_data, stderr_data = p.communicate()
96 stdout_data = stdout_data.split('\n')
97 matches = [P_GIT_REMOTE.match(line) for line in stdout_data]
98 matches = [m for m in matches if m is not None]
99 require(len(matches) == 1,
100 'Unexpected output from git remote command: "{0}"'.format(matches))
102 username = matches[0].group(1)
103 require(username, 'empty username in git remote output {0}'.format(matches[0]))
105 project_name = matches[0].group(2)
106 require(username, 'empty project name in git remote output {0}'.format(matches[0]))
108 url = F_REPO_URL.format(username, project_name)
112 def check_labels(reporter, repo_url):
114 Check labels in repository.
117 actual = get_labels(repo_url)
118 extra = set(actual.keys()) - set(EXPECTED.keys())
120 reporter.check(not extra,
122 'Extra label(s) in repository {0}: {1}',
123 repo_url, ', '.join(sorted(extra)))
125 missing = set(EXPECTED.keys()) - set(actual.keys())
126 reporter.check(not missing,
128 'Missing label(s) in repository {0}: {1}',
129 repo_url, ', '.join(sorted(missing)))
131 overlap = set(EXPECTED.keys()).intersection(set(actual.keys()))
132 for name in sorted(overlap):
133 reporter.check(EXPECTED[name] == actual[name],
135 'Color mis-match for label {0} in {1}: expected {2}, found {3}',
136 name, repo_url, EXPECTED[name], actual[name])
139 def get_labels(repo_url):
141 Get actual labels from repository.
144 m = P_REPO_URL.match(repo_url)
145 require(m, 'repository URL {0} does not match expected pattern'.format(repo_url))
147 username = m.group(1)
148 require(username, 'empty username in repository URL {0}'.format(repo_url))
150 project_name = m.group(2)
151 require(username, 'empty project name in repository URL {0}'.format(repo_url))
153 url = F_API_URL.format(username, project_name)
154 r = requests.get(url)
155 require(r.status_code == 200,
156 'Request for {0} failed with {1}'.format(url, r.status_code))
159 for entry in r.json():
160 result[entry['name']] = entry['color']
164 if __name__ == '__main__':