File indexing completed on 2025-01-18 10:18:37
0001 """
0002 Check repository settings.
0003 """
0004
0005
0006 import sys
0007 import os
0008 from subprocess import Popen, PIPE
0009 import re
0010 from argparse import ArgumentParser
0011
0012 from util import require
0013 from reporter import Reporter
0014
0015
0016 try:
0017 import requests
0018 except ImportError:
0019 print('Unable to import requests module: please install requests', file=sys.stderr)
0020 sys.exit(1)
0021
0022
0023
0024 P_GIT_REMOTE = re.compile(r'upstream\s+(?:https://|git@)github.com[:/]([^/]+)/([^.]+)(\.git)?\s+\(fetch\)')
0025
0026
0027 F_REPO_URL = 'https://github.com/{0}/{1}/'
0028
0029
0030 P_REPO_URL = re.compile(r'https?://github\.com/([^.]+)/([^/]+)/?')
0031
0032
0033 F_API_URL = 'https://api.github.com/repos/{0}/{1}/labels'
0034
0035
0036 EXPECTED = {
0037 'help wanted': 'dcecc7',
0038 'status:in progress': '9bcc65',
0039 'status:changes requested': '679f38',
0040 'status:wait': 'fff2df',
0041 'status:refer to cac': 'ffdfb2',
0042 'status:need more info': 'ee6c00',
0043 'status:blocked': 'e55100',
0044 'status:out of scope': 'eeeeee',
0045 'status:duplicate': 'bdbdbd',
0046 'type:typo text': 'f8bad0',
0047 'type:bug': 'eb3f79',
0048 'type:formatting': 'ac1357',
0049 'type:template and tools': '7985cb',
0050 'type:instructor guide': '00887a',
0051 'type:discussion': 'b2e5fc',
0052 'type:enhancement': '7fdeea',
0053 'type:clarification': '00acc0',
0054 'type:teaching example': 'ced8dc',
0055 'good first issue': 'ffeb3a',
0056 'high priority': 'd22e2e'
0057 }
0058
0059
0060 def main():
0061 """
0062 Main driver.
0063 """
0064
0065 args = parse_args()
0066 reporter = Reporter()
0067 repo_url = get_repo_url(args.repo_url)
0068 check_labels(reporter, repo_url)
0069 reporter.report()
0070
0071
0072 def parse_args():
0073 """
0074 Parse command-line arguments.
0075 """
0076
0077 parser = ArgumentParser(description="""Check repository settings.""")
0078 parser.add_argument('-r', '--repo',
0079 default=None,
0080 dest='repo_url',
0081 help='repository URL')
0082 parser.add_argument('-s', '--source',
0083 default=os.curdir,
0084 dest='source_dir',
0085 help='source directory')
0086
0087 args, extras = parser.parse_known_args()
0088 require(not extras,
0089 'Unexpected trailing command-line arguments "{0}"'.format(extras))
0090
0091 return args
0092
0093
0094 def get_repo_url(repo_url):
0095 """
0096 Figure out which repository to query.
0097 """
0098
0099
0100 if repo_url is not None:
0101 return repo_url
0102
0103
0104 cmd = 'git remote -v'
0105 p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE,
0106 close_fds=True, universal_newlines=True, encoding='utf-8')
0107 stdout_data, stderr_data = p.communicate()
0108 stdout_data = stdout_data.split('\n')
0109 matches = [P_GIT_REMOTE.match(line) for line in stdout_data]
0110 matches = [m for m in matches if m is not None]
0111 require(len(matches) == 1,
0112 'Unexpected output from git remote command: "{0}"'.format(matches))
0113
0114 username = matches[0].group(1)
0115 require(
0116 username, 'empty username in git remote output {0}'.format(matches[0]))
0117
0118 project_name = matches[0].group(2)
0119 require(
0120 username, 'empty project name in git remote output {0}'.format(matches[0]))
0121
0122 url = F_REPO_URL.format(username, project_name)
0123 return url
0124
0125
0126 def check_labels(reporter, repo_url):
0127 """
0128 Check labels in repository.
0129 """
0130
0131 actual = get_labels(repo_url)
0132 extra = set(actual.keys()) - set(EXPECTED.keys())
0133
0134 reporter.check(not extra,
0135 None,
0136 'Extra label(s) in repository {0}: {1}',
0137 repo_url, ', '.join(sorted(extra)))
0138
0139 missing = set(EXPECTED.keys()) - set(actual.keys())
0140 reporter.check(not missing,
0141 None,
0142 'Missing label(s) in repository {0}: {1}',
0143 repo_url, ', '.join(sorted(missing)))
0144
0145 overlap = set(EXPECTED.keys()).intersection(set(actual.keys()))
0146 for name in sorted(overlap):
0147 reporter.check(EXPECTED[name].lower() == actual[name].lower(),
0148 None,
0149 'Color mis-match for label {0} in {1}: expected {2}, found {3}',
0150 name, repo_url, EXPECTED[name], actual[name])
0151
0152
0153 def get_labels(repo_url):
0154 """
0155 Get actual labels from repository.
0156 """
0157
0158 m = P_REPO_URL.match(repo_url)
0159 require(
0160 m, 'repository URL {0} does not match expected pattern'.format(repo_url))
0161
0162 username = m.group(1)
0163 require(username, 'empty username in repository URL {0}'.format(repo_url))
0164
0165 project_name = m.group(2)
0166 require(
0167 username, 'empty project name in repository URL {0}'.format(repo_url))
0168
0169 url = F_API_URL.format(username, project_name)
0170 r = requests.get(url)
0171 require(r.status_code == 200,
0172 'Request for {0} failed with {1}'.format(url, r.status_code))
0173
0174 result = {}
0175 for entry in r.json():
0176 result[entry['name']] = entry['color']
0177 return result
0178
0179
0180 if __name__ == '__main__':
0181 main()