Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ed86307

Browse files
committed
Merge pull request #151 from pre-commit/dont_dict_pre_commit_config
Allow multiple hooks with same id in .pre-commit-config.yaml
2 parents 32b662c + e1429ec commit ed86307

6 files changed

Lines changed: 43 additions & 23 deletions

File tree

.coveragerc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ omit =
77
/usr/*
88
*/tmp*
99
setup.py
10+
# Don't complain if non-runnable code isn't run
11+
*/__main__.py
1012

1113
[report]
1214
exclude_lines =

pre_commit/commands/autoupdate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def _update_repository(repo_config, runner):
4343
new_repo = Repository.create(new_config, runner.store)
4444

4545
# See if any of our hooks were deleted with the new commits
46-
hooks = set(repo.hooks.keys())
46+
hooks = set(hook_id for hook_id, _ in repo.hooks)
4747
hooks_missing = hooks - (hooks & set(new_repo.manifest.hooks.keys()))
4848
if hooks_missing:
4949
raise RepositoryCannotBeUpdatedError(

pre_commit/commands/run.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,16 @@ def _print_user_skipped(hook, write, args):
4747
))
4848

4949

50-
def _run_single_hook(runner, repository, hook_id, args, write, skips=set()):
50+
def _run_single_hook(runner, repository, hook, args, write, skips=set()):
5151
if args.all_files:
5252
get_filenames = git.get_all_files_matching
5353
elif git.is_in_merge_conflict():
5454
get_filenames = git.get_conflicted_files_matching
5555
else:
5656
get_filenames = git.get_staged_files_matching
5757

58-
hook = repository.hooks[hook_id]
59-
6058
filenames = get_filenames(hook['files'], hook['exclude'])
61-
if hook_id in skips:
59+
if hook['id'] in skips:
6260
_print_user_skipped(hook, write, args)
6361
return 0
6462
elif not filenames:
@@ -70,9 +68,9 @@ def _run_single_hook(runner, repository, hook_id, args, write, skips=set()):
7068
write(get_hook_message(_hook_msg_start(hook, args.verbose), end_len=6))
7169
sys.stdout.flush()
7270

73-
retcode, stdout, stderr = repository.run_hook(hook_id, filenames)
71+
retcode, stdout, stderr = repository.run_hook(hook, filenames)
7472

75-
if retcode != repository.hooks[hook_id]['expected_return_value']:
73+
if retcode != hook['expected_return_value']:
7674
retcode = 1
7775
print_color = color.RED
7876
pass_fail = 'Failed'
@@ -101,9 +99,9 @@ def _run_hooks(runner, args, write, environ):
10199
skips = _get_skips(environ)
102100

103101
for repo in runner.repositories:
104-
for hook_id in repo.hooks:
102+
for _, hook in repo.hooks:
105103
retval |= _run_single_hook(
106-
runner, repo, hook_id, args, write, skips=skips,
104+
runner, repo, hook, args, write, skips=skips,
107105
)
108106

109107
return retval
@@ -112,8 +110,11 @@ def _run_hooks(runner, args, write, environ):
112110
def _run_hook(runner, args, write):
113111
hook_id = args.hook
114112
for repo in runner.repositories:
115-
if hook_id in repo.hooks:
116-
return _run_single_hook(runner, repo, hook_id, args, write=write)
113+
for hook_id_in_repo, hook in repo.hooks:
114+
if hook_id == hook_id_in_repo:
115+
return _run_single_hook(
116+
runner, repo, hook, args, write=write,
117+
)
117118
else:
118119
write('No hook with id `{0}`\n'.format(hook_id))
119120
return 1

pre_commit/repository.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
from pre_commit.languages.all import languages
66
from pre_commit.manifest import Manifest
7-
from pre_commit.ordereddict import OrderedDict
87
from pre_commit.prefixed_command_runner import PrefixedCommandRunner
98

109

@@ -33,13 +32,13 @@ def sha(self):
3332
def languages(self):
3433
return set(
3534
(hook['language'], hook['language_version'])
36-
for hook in self.hooks.values()
35+
for _, hook in self.hooks
3736
)
3837

3938
@cached_property
4039
def hooks(self):
4140
# TODO: merging in manifest dicts is a smell imo
42-
return OrderedDict(
41+
return tuple(
4342
(hook['id'], dict(self.manifest.hooks[hook['id']], **hook))
4443
for hook in self.repo_config['hooks']
4544
)
@@ -71,15 +70,14 @@ def install(self):
7170
continue
7271
language.install_environment(self.cmd_runner, language_version)
7372

74-
def run_hook(self, hook_id, file_args):
73+
def run_hook(self, hook, file_args):
7574
"""Run a hook.
7675
7776
Args:
78-
hook_id - Id of the hook
77+
hook - Hook dictionary
7978
file_args - List of files to run
8079
"""
8180
self.require_installed()
82-
hook = self.hooks[hook_id]
8381
return languages[hook['language']].run_hook(
8482
self.cmd_runner, hook, file_args,
8583
)

tests/commands/run_test.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import unicode_literals
22

3+
import io
34
import mock
45
import os
56
import os.path
@@ -205,7 +206,22 @@ def test_hook_id_not_in_non_verbose_output(
205206

206207

207208
def test_hook_id_in_verbose_output(
208-
repo_with_passing_hook, mock_out_store_directory
209+
repo_with_passing_hook, mock_out_store_directory,
209210
):
210211
ret, printed = _do_run(repo_with_passing_hook, _get_opts(verbose=True))
211212
assert '[bash_hook] Bash hook' in printed
213+
214+
215+
def test_multiple_hooks_same_id(
216+
repo_with_passing_hook, mock_out_store_directory,
217+
):
218+
with local.cwd(repo_with_passing_hook):
219+
# Add bash hook on there again
220+
with io.open('.pre-commit-config.yaml', 'a+') as config_file:
221+
config_file.write(' - id: bash_hook\n')
222+
local['git']('add', '.pre-commit-config.yaml')
223+
stage_a_file()
224+
225+
ret, output = _do_run(repo_with_passing_hook, _get_opts())
226+
assert ret == 0
227+
assert output.count('Bash hook') == 2

tests/repository_test.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ def _test_hook_repo(
2929
path = make_repo(tmpdir_factory, repo_path)
3030
config = make_config_from_repo(path)
3131
repo = Repository.create(config, store)
32-
ret = repo.run_hook(hook_id, args)
32+
hook_dict = [
33+
hook for repo_hook_id, hook in repo.hooks if repo_hook_id == hook_id
34+
][0]
35+
ret = repo.run_hook(hook_dict, args)
3336
assert ret[0] == expected_return_code
3437
assert ret[1] == expected
3538

@@ -261,11 +264,11 @@ def test_config_overrides_repo_specifics(tmpdir_factory, store):
261264
config = make_config_from_repo(path)
262265

263266
repo = Repository.create(config, store)
264-
assert repo.hooks['bash_hook']['files'] == ''
267+
assert repo.hooks[0][1]['files'] == ''
265268
# Set the file regex to something else
266269
config['hooks'][0]['files'] = '\\.sh$'
267270
repo = Repository.create(config, store)
268-
assert repo.hooks['bash_hook']['files'] == '\\.sh$'
271+
assert repo.hooks[0][1]['files'] == '\\.sh$'
269272

270273

271274
def _create_repo_with_tags(tmpdir_factory, src, tag):
@@ -286,13 +289,13 @@ def test_tags_on_repositories(in_tmpdir, tmpdir_factory, store):
286289
repo_1 = Repository.create(
287290
make_config_from_repo(git_dir_1, sha=tag), store,
288291
)
289-
ret = repo_1.run_hook('prints_cwd', ['-L'])
292+
ret = repo_1.run_hook(repo_1.hooks[0][1], ['-L'])
290293
assert ret[0] == 0
291294
assert ret[1].strip() == in_tmpdir
292295

293296
repo_2 = Repository.create(
294297
make_config_from_repo(git_dir_2, sha=tag), store,
295298
)
296-
ret = repo_2.run_hook('bash_hook', ['bar'])
299+
ret = repo_2.run_hook(repo_2.hooks[0][1], ['bar'])
297300
assert ret[0] == 0
298301
assert ret[1] == 'bar\nHello World\n'

0 commit comments

Comments
 (0)