Commit 9a5ab181 authored by Greg Wilson's avatar Greg Wilson
Browse files

Starting on tool to check repository settings.

1.  Created `bin/repo_check.py`.
2.  Moved `require()` to `util.py`.
3.  Updated `Makefile` with new target.
parent 9610f407
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -27,6 +27,11 @@ site : lesson-rmd
figures :
	@bin/extract_figures.py -s _episodes -p ${PARSER} > _includes/all_figures.html

# repo-check        : check repository settings.
repo-check :
	@bin/repo_check.py -s .


## clean            : clean up junk files.
clean :
	@rm -rf ${DST}
+1 −9
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@ import json
import re
from optparse import OptionParser

from util import Reporter, read_markdown, load_yaml, check_unwanted_files
from util import Reporter, read_markdown, load_yaml, check_unwanted_files, require

__version__ = '0.2'

@@ -252,14 +252,6 @@ def create_checker(args, filename, info):
            return cls(args, filename, **info)


def require(condition, message):
    """Fail if condition not met."""

    if not condition:
        print(message, file=sys.stderr)
        sys.exit(1)


class CheckBase(object):
    """Base class for checking Markdown files."""

bin/repo_check.py

0 → 100755
+139 −0
Original line number Diff line number Diff line
#!/usr/bin/env python

"""
Check repository settings.
"""

import sys
import os
import re
from optparse import OptionParser

from util import Reporter, load_yaml, require

# Import this way to produce a more useful error message.
try:
    import requests
except ImportError:
    print('Unable to import requests module: please install requests', file=sys.stderr)
    sys.exit(1)


# Pattern to match repository URLs and extract username and project name.
P_REPO_URL = re.compile(r'https?://github\.com/([^.]+)/([^/]+)/?')

# API URL format string.
F_API_URL = 'https://api.github.com/repos/{0}/{1}/labels'

# Expected labels and colors.
EXPECTED = {
    'bug' : 'bd2c00',
    'discussion' : 'fc8dc1',
    'enhancement' : '9cd6dc',
    'help-wanted' : 'f4fd9c',
    'instructor-training' : '6e5494',
    'newcomer-friendly' : 'eec275',
    'question' : '808040',
    'template-and-tools' : '2b3990',
    'work-in-progress' : '7ae78e'
}


def main():
    """
    Main driver.
    """

    args = parse_args()
    reporter = Reporter()
    repo_url = get_repo_url(args.source_dir)
    check_labels(reporter, repo_url)
    reporter.report()


def parse_args():
    """
    Parse command-line arguments.
    """

    parser = OptionParser()
    parser.add_option('-s', '--source',
                      default=os.curdir,
                      dest='source_dir',
                      help='source directory')

    args, extras = parser.parse_args()
    require(not extras,
            'Unexpected trailing command-line arguments "{0}"'.format(extras))

    return args


def get_repo_url(source_dir):
    """
    Figure out which repository to query.
    """

    config_file = os.path.join(source_dir, '_config.yml')
    config = load_yaml(config_file)
    if 'repo' not in config:
        print('"repo" not found in {0}'.format(config_file), file=sys.stderr)
        sys.exit(1)

    return config['repo']


def check_labels(reporter, repo_url):
    """
    Check labels in repository.
    """

    actual = get_labels(repo_url)
    extra = set(actual.keys()) - set(EXPECTED.keys())

    reporter.check(not extra,
                   None,
                   'Extra label(s) in repository {0}: {1}',
                   repo_url, ', '.join(sorted(extra)))

    missing = set(EXPECTED.keys()) - set(actual.keys())
    reporter.check(not missing,
                   None,
                   'Missing label(s) in repository {0}: {1}',
                   repo_url, ', '.join(sorted(missing)))

    overlap = set(EXPECTED.keys()).intersection(set(actual.keys()))
    for name in sorted(overlap):
        reporter.check(EXPECTED[name] == actual[name],
                       None,
                       'Color mis-match for label {0} in {1}: expected {2}, found {3}',
                       name, repo_url, EXPECTED[name], actual[name])


def get_labels(repo_url):
    """
    Get actual labels from repository.
    """

    m = P_REPO_URL.match(repo_url)
    require(m, 'repository URL {0} does not match expected pattern'.format(repo_url))

    username = m.group(1)
    require(username, 'empty username in repository URL {0}'.format(repo_url))

    project_name = m.group(2)
    require(username, 'empty project name in repository URL {0}'.format(repo_url))

    url = F_API_URL.format(username, project_name)
    r = requests.get(url)
    require(r.status_code == 200,
            'Request for {0} failed with {1}'.format(url, r.status_code))

    result = {}
    for entry in r.json():
        result[entry['name']] = entry['color']
    return result


if __name__ == '__main__':
    main()
+8 −0
Original line number Diff line number Diff line
@@ -151,3 +151,11 @@ def check_unwanted_files(dir_path, reporter):
        reporter.check(not os.path.exists(path),
                       path,
                       "Unwanted file found")


def require(condition, message):
    """Fail if condition not met."""

    if not condition:
        print(message, file=sys.stderr)
        sys.exit(1)