Skip to content

Commit b096c0b

Browse files
committed
Allow aliasing a hook and calling it by it's alias
1 parent c5c0a06 commit b096c0b

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

pre_commit/clientlib.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,28 @@ def _make_argparser(filenames_help):
2929
return parser
3030

3131

32+
class OptionalAlias(object):
33+
34+
def check(self, dct):
35+
if 'alias' in dct:
36+
cfgv.check_string(dct['alias'])
37+
38+
def apply_default(self, dct):
39+
if 'alias' not in dct:
40+
dct['alias'] = dct['id']
41+
42+
def remove_default(self, dct):
43+
pass
44+
45+
3246
MANIFEST_HOOK_DICT = cfgv.Map(
3347
'Hook', 'id',
3448

3549
cfgv.Required('id', cfgv.check_string),
3650
cfgv.Required('name', cfgv.check_string),
3751
cfgv.Required('entry', cfgv.check_string),
3852
cfgv.Required('language', cfgv.check_one_of(all_languages)),
53+
cfgv.OptionalNoDefault('alias', cfgv.check_string),
3954

4055
cfgv.Optional(
4156
'files', cfgv.check_and(cfgv.check_string, cfgv.check_regex), '',
@@ -125,6 +140,7 @@ def remove_default(self, dct):
125140
'Hook', 'id',
126141

127142
cfgv.Required('id', cfgv.check_string),
143+
OptionalAlias(),
128144

129145
# All keys in manifest hook dict are valid in a config hook dict, but
130146
# are optional.
@@ -133,7 +149,7 @@ def remove_default(self, dct):
133149
*[
134150
cfgv.OptionalNoDefault(item.key, item.check_fn)
135151
for item in MANIFEST_HOOK_DICT.items
136-
if item.key != 'id'
152+
if item.key not in ('id', 'alias')
137153
]
138154
)
139155
CONFIG_REPO_DICT = cfgv.Map(

pre_commit/commands/run.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,13 +257,17 @@ def run(config_file, store, args, environ=os.environ):
257257
for repo in repositories(config, store):
258258
for _, hook in repo.hooks:
259259
if (
260-
(not args.hook or hook['id'] == args.hook) and
260+
(not args.hook or hook['id'] == args.hook or (
261+
hook['alias'] and hook['alias'] == args.hook
262+
)) and
261263
(not hook['stages'] or args.hook_stage in hook['stages'])
262264
):
263265
repo_hooks.append((repo, hook))
264266

265267
if args.hook and not repo_hooks:
266-
output.write_line('No hook with id `{}`'.format(args.hook))
268+
output.write_line(
269+
'No hook with id or alias `{}`'.format(args.hook),
270+
)
267271
return 1
268272

269273
for repo in {repo for repo, _ in repo_hooks}:

tests/commands/run_test.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,32 @@ def test_multiple_hooks_same_id(cap_out, store, repo_with_passing_hook):
416416
assert output.count(b'Bash hook') == 2
417417

418418

419+
def test_aliased_hook_run(cap_out, store, repo_with_passing_hook):
420+
with cwd(repo_with_passing_hook):
421+
# Add bash hook on there again, aliased
422+
with modify_config() as config:
423+
config['repos'][0]['hooks'].append(
424+
{'id': 'bash_hook', 'alias': 'foo_bash'},
425+
)
426+
stage_a_file()
427+
428+
ret, output = _do_run(
429+
cap_out, store, repo_with_passing_hook,
430+
run_opts(verbose=True, hook='bash_hook'),
431+
)
432+
assert ret == 0
433+
# Both hooks will run since they share the same ID
434+
assert output.count(b'Bash hook') == 2
435+
436+
ret, output = _do_run(
437+
cap_out, store, repo_with_passing_hook,
438+
run_opts(verbose=True, hook='foo_bash'),
439+
)
440+
assert ret == 0
441+
# Only the aliased hook runs
442+
assert output.count(b'Bash hook') == 1
443+
444+
419445
def test_non_ascii_hook_id(repo_with_passing_hook, tempdir_factory):
420446
with cwd(repo_with_passing_hook):
421447
_, stdout, _ = cmd_output_mocked_pre_commit_home(

0 commit comments

Comments
 (0)