Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-06-01 07:07:47

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 # Import this way to produce a more useful error message.
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 # Pattern to match Git command-line output for remotes => (user name, project name).
0024 P_GIT_REMOTE = re.compile(r'upstream\s+(?:https://|git@)github.com[:/]([^/]+)/([^.]+)(\.git)?\s+\(fetch\)')
0025 
0026 # Repository URL format string.
0027 F_REPO_URL = 'https://github.com/{0}/{1}/'
0028 
0029 # Pattern to match repository URLs => (user name, project name)
0030 P_REPO_URL = re.compile(r'https?://github\.com/([^.]+)/([^/]+)/?')
0031 
0032 # API URL format string.
0033 F_API_URL = 'https://api.github.com/repos/{0}/{1}/labels'
0034 
0035 # Expected labels and colors.
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     # Explicitly specified.
0100     if repo_url is not None:
0101         return repo_url
0102 
0103     # Guess.
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()