Add mechanism to skip hooks. Closes #40.

This commit is contained in:
Anthony Sottile 2014-04-19 11:00:38 -07:00
parent a60b3a3971
commit 744b883b01
2 changed files with 86 additions and 26 deletions

View file

@ -144,7 +144,42 @@ def clean(runner):
return 0 return 0
def _run_single_hook(runner, repository, hook_id, args, write): def _get_skips(environ):
skips = environ.get('SKIP', '')
return set(skip.strip() for skip in skips.split(',') if skip.strip())
def _print_no_files_skipped(hook, write, args):
no_files_msg = '(no files to check) '
skipped_msg = 'Skipped'
write(
'{0}{1}{2}{3}\n'.format(
hook['name'],
'.' * (
COLS -
len(hook['name']) -
len(no_files_msg) -
len(skipped_msg) -
6
),
no_files_msg,
color.format_color(skipped_msg, color.TURQUOISE, args.color),
)
)
def _print_user_skipped(hook, write, args):
skipped_msg = 'Skipped'
write(
'{0}{1}{2}\n'.format(
hook['name'],
'.' * (COLS - len(hook['name']) - len(skipped_msg) - 6),
color.format_color(skipped_msg, color.YELLOW, args.color),
),
)
def _run_single_hook(runner, repository, hook_id, args, write, skips=set()):
if args.all_files: if args.all_files:
get_filenames = git.get_all_files_matching get_filenames = git.get_all_files_matching
elif git.is_in_merge_conflict(): elif git.is_in_merge_conflict():
@ -155,23 +190,11 @@ def _run_single_hook(runner, repository, hook_id, args, write):
hook = repository.hooks[hook_id] hook = repository.hooks[hook_id]
filenames = get_filenames(hook['files'], hook['exclude']) filenames = get_filenames(hook['files'], hook['exclude'])
if not filenames: if hook_id in skips:
no_files_msg = '(no files to check) ' _print_user_skipped(hook, write, args)
skipped_msg = 'Skipped' return 0
write( elif not filenames:
'{0}{1}{2}{3}\n'.format( _print_no_files_skipped(hook, write, args)
hook['name'],
'.' * (
COLS -
len(hook['name']) -
len(no_files_msg) -
len(skipped_msg) -
6
),
no_files_msg,
color.format_color(skipped_msg, color.TURQUOISE, args.color),
)
)
return 0 return 0
# Print the hook and the dots first in case the hook takes hella long to # Print the hook and the dots first in case the hook takes hella long to
@ -211,18 +234,23 @@ def _run_single_hook(runner, repository, hook_id, args, write):
return retcode return retcode
def _run_hooks(runner, args, write): def _run_hooks(runner, args, write, environ):
"""Actually run the hooks.""" """Actually run the hooks."""
retval = 0 retval = 0
skips = _get_skips(environ)
for repo in runner.repositories: for repo in runner.repositories:
for hook_id in repo.hooks: for hook_id in repo.hooks:
retval |= _run_single_hook(runner, repo, hook_id, args, write=write) retval |= _run_single_hook(
runner, repo, hook_id, args, write, skips=skips,
)
return retval return retval
def _run_hook(runner, hook_id, args, write): def _run_hook(runner, args, write):
hook_id = args.hook
for repo in runner.repositories: for repo in runner.repositories:
if hook_id in repo.hooks: if hook_id in repo.hooks:
return _run_single_hook(runner, repo, hook_id, args, write=write) return _run_single_hook(runner, repo, hook_id, args, write=write)
@ -236,7 +264,7 @@ def _has_unmerged_paths(runner):
return bool(stdout.strip()) return bool(stdout.strip())
def run(runner, args, write=sys.stdout.write): def run(runner, args, write=sys.stdout.write, environ=os.environ):
# Set up our logging handler # Set up our logging handler
logger.addHandler(LoggingHandler(args.color, write=write)) logger.addHandler(LoggingHandler(args.color, write=write))
logger.setLevel(logging.INFO) logger.setLevel(logging.INFO)
@ -253,6 +281,6 @@ def run(runner, args, write=sys.stdout.write):
with ctx: with ctx:
if args.hook: if args.hook:
return _run_hook(runner, args.hook, args, write=write) return _run_hook(runner, args, write=write)
else: else:
return _run_hooks(runner, args, write=write) return _run_hooks(runner, args, write=write, environ=environ)

View file

@ -201,10 +201,10 @@ def _get_opts(all_files=False, color=False, verbose=False, hook=None, no_stash=F
) )
def _do_run(repo, args): def _do_run(repo, args, environ={}):
runner = Runner(repo) runner = Runner(repo)
write_mock = mock.Mock() write_mock = mock.Mock()
ret = commands.run(runner, args, write=write_mock) ret = commands.run(runner, args, write=write_mock, environ=environ)
printed = get_write_mock_output(write_mock) printed = get_write_mock_output(write_mock)
return ret, printed return ret, printed
@ -298,3 +298,35 @@ def test_merge_conflict_modified(in_merge_conflict):
ret, printed = _do_run(in_merge_conflict, _get_opts()) ret, printed = _do_run(in_merge_conflict, _get_opts())
assert ret == 1 assert ret == 1
assert 'Unmerged files. Resolve before committing.' in printed assert 'Unmerged files. Resolve before committing.' in printed
def test_merge_conflict_resolved(in_merge_conflict):
local['git']['add', '.']()
ret, printed = _do_run(in_merge_conflict, _get_opts())
for msg in ('Checking merge-conflict files only.', 'Bash hook', 'Passed'):
assert msg in printed
@pytest.mark.parametrize(
('environ', 'expected_output'),
(
({}, set([])),
({'SKIP': ''}, set([])),
({'SKIP': ','}, set([])),
({'SKIP': ',foo'}, set(['foo'])),
({'SKIP': 'foo'}, set(['foo'])),
({'SKIP': 'foo,bar'}, set(['foo', 'bar'])),
({'SKIP': ' foo , bar'}, set(['foo', 'bar'])),
),
)
def test_get_skips(environ, expected_output):
ret = commands._get_skips(environ)
assert ret == expected_output
def test_skip_hook(repo_with_passing_hook):
ret, printed = _do_run(
repo_with_passing_hook, _get_opts(), {'SKIP': 'bash_hook'},
)
for msg in ('Bash hook', 'Skipped'):
assert msg in printed