check hex color using lowercase
[rnaseq-cwl-training.git] / bin / repo_check.py
1 #!/usr/bin/env python
2
3 """
4 Check repository settings.
5 """
6
7 from __future__ import print_function
8 import sys
9 import os
10 from subprocess import Popen, PIPE
11 import re
12 from optparse import OptionParser
13
14 from util import Reporter, load_yaml, require
15
16 # Import this way to produce a more useful error message.
17 try:
18     import requests
19 except ImportError:
20     print('Unable to import requests module: please install requests', file=sys.stderr)
21     sys.exit(1)
22
23
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\)')
26
27 # Repository URL format string.
28 F_REPO_URL = 'https://github.com/{0}/{1}/'
29
30 # Pattern to match repository URLs => (user name, project name)
31 P_REPO_URL = re.compile(r'https?://github\.com/([^.]+)/([^/]+)/?')
32
33 # API URL format string.
34 F_API_URL = 'https://api.github.com/repos/{0}/{1}/labels'
35
36 # Expected labels and colors.
37 EXPECTED = {
38     'bug' : 'bd2c00',
39     'discussion' : 'fc8dc1',
40     'enhancement' : '9cd6dc',
41     'help-wanted' : 'f4fd9c',
42     'instructor-training' : '6e5494',
43     'newcomer-friendly' : 'eec275',
44     'question' : '808040',
45     'template-and-tools' : '2b3990',
46     'work-in-progress' : '7ae78e'
47 }
48
49
50 def main():
51     """
52     Main driver.
53     """
54
55     args = parse_args()
56     reporter = Reporter()
57     repo_url = get_repo_url(args.source_dir, args.repo_url)
58     check_labels(reporter, repo_url)
59     reporter.report()
60
61
62 def parse_args():
63     """
64     Parse command-line arguments.
65     """
66
67     parser = OptionParser()
68     parser.add_option('-r', '--repo',
69                       default=None,
70                       dest='repo_url',
71                       help='repository URL')
72     parser.add_option('-s', '--source',
73                       default=os.curdir,
74                       dest='source_dir',
75                       help='source directory')
76
77     args, extras = parser.parse_args()
78     require(not extras,
79             'Unexpected trailing command-line arguments "{0}"'.format(extras))
80
81     return args
82
83
84 def get_repo_url(source_dir, repo_url):
85     """
86     Figure out which repository to query.
87     """
88
89     # Explicitly specified.
90     if repo_url is not None:
91         return repo_url
92
93     # Guess.
94     cmd = 'git remote -v'
95     p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, close_fds=True, universal_newlines=True)
96     stdout_data, stderr_data = p.communicate()
97     stdout_data = stdout_data.split('\n')
98     matches = [P_GIT_REMOTE.match(line) for line in stdout_data]
99     matches = [m for m in matches if m is not None]
100     require(len(matches) == 1,
101             'Unexpected output from git remote command: "{0}"'.format(matches))
102
103     username = matches[0].group(1)
104     require(username, 'empty username in git remote output {0}'.format(matches[0]))
105
106     project_name = matches[0].group(2)
107     require(username, 'empty project name in git remote output {0}'.format(matches[0]))
108
109     url = F_REPO_URL.format(username, project_name)
110     return url
111
112
113 def check_labels(reporter, repo_url):
114     """
115     Check labels in repository.
116     """
117
118     actual = get_labels(repo_url)
119     extra = set(actual.keys()) - set(EXPECTED.keys())
120
121     reporter.check(not extra,
122                    None,
123                    'Extra label(s) in repository {0}: {1}',
124                    repo_url, ', '.join(sorted(extra)))
125
126     missing = set(EXPECTED.keys()) - set(actual.keys())
127     reporter.check(not missing,
128                    None,
129                    'Missing label(s) in repository {0}: {1}',
130                    repo_url, ', '.join(sorted(missing)))
131
132     overlap = set(EXPECTED.keys()).intersection(set(actual.keys()))
133     for name in sorted(overlap):
134         reporter.check(EXPECTED[name].lower() == actual[name].lower(),
135                        None,
136                        'Color mis-match for label {0} in {1}: expected {2}, found {3}',
137                        name, repo_url, EXPECTED[name], actual[name])
138
139
140 def get_labels(repo_url):
141     """
142     Get actual labels from repository.
143     """
144
145     m = P_REPO_URL.match(repo_url)
146     require(m, 'repository URL {0} does not match expected pattern'.format(repo_url))
147
148     username = m.group(1)
149     require(username, 'empty username in repository URL {0}'.format(repo_url))
150
151     project_name = m.group(2)
152     require(username, 'empty project name in repository URL {0}'.format(repo_url))
153
154     url = F_API_URL.format(username, project_name)
155     r = requests.get(url)
156     require(r.status_code == 200,
157             'Request for {0} failed with {1}'.format(url, r.status_code))
158
159     result = {}
160     for entry in r.json():
161         result[entry['name']] = entry['color']
162     return result
163
164
165 if __name__ == '__main__':
166     main()