Skip to content

Commit 3e76cda

Browse files
committed
Enable map configurations (config v2).
1 parent ef8347c commit 3e76cda

File tree

11 files changed

+70
-52
lines changed

11 files changed

+70
-52
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
repos:
12
- repo: https://github.com/pre-commit/pre-commit-hooks.git
23
sha: v0.9.1
34
hooks:

pre_commit/clientlib.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from __future__ import unicode_literals
33

44
import argparse
5+
import collections
56
import functools
67

78
from aspy.yaml import ordered_load
@@ -125,7 +126,11 @@ def validate_manifest_main(argv=None):
125126
ensure_absent=True,
126127
),
127128
)
128-
CONFIG_SCHEMA = schema.Array(CONFIG_REPO_DICT)
129+
CONFIG_SCHEMA = schema.Map(
130+
'Config', None,
131+
132+
schema.RequiredRecurse('repos', schema.Array(CONFIG_REPO_DICT)),
133+
)
129134

130135

131136
def is_local_repo(repo_entry):
@@ -136,10 +141,19 @@ class InvalidConfigError(FatalError):
136141
pass
137142

138143

144+
def ordered_load_normalize_legacy_config(contents):
145+
data = ordered_load(contents)
146+
if isinstance(data, list):
147+
# TODO: Once happy, issue a deprecation warning and instructions
148+
return collections.OrderedDict([('repos', data)])
149+
else:
150+
return data
151+
152+
139153
load_config = functools.partial(
140154
schema.load_from_filename,
141155
schema=CONFIG_SCHEMA,
142-
load_strategy=ordered_load,
156+
load_strategy=ordered_load_normalize_legacy_config,
143157
exc_tp=InvalidConfigError,
144158
)
145159

pre_commit/commands/autoupdate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def autoupdate(runner, tags_only):
109109

110110
input_configs = load_config(runner.config_file_path)
111111

112-
for repo_config in input_configs:
112+
for repo_config in input_configs['repos']:
113113
if is_local_repo(repo_config):
114114
output_configs.append(repo_config)
115115
continue

pre_commit/commands/sample_config.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
SAMPLE_CONFIG = '''\
1111
# See http://pre-commit.com for more information
1212
# See http://pre-commit.com/hooks.html for more hooks
13+
repos:
1314
- repo: https://github.com/pre-commit/pre-commit-hooks
14-
sha: v0.9.1
15+
sha: v0.9.2
1516
hooks:
1617
- id: trailing-whitespace
1718
- id: end-of-file-fixer

pre_commit/runner.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ def config_file_path(self):
4040
@cached_property
4141
def repositories(self):
4242
"""Returns a tuple of the configured repositories."""
43-
config = load_config(self.config_file_path)
44-
repositories = tuple(Repository.create(x, self.store) for x in config)
45-
for repository in repositories:
46-
repository.require_installed()
47-
return repositories
43+
repos = load_config(self.config_file_path)['repos']
44+
repos = tuple(Repository.create(x, self.store) for x in repos)
45+
for repo in repos:
46+
repo.require_installed()
47+
return repos
4848

4949
def get_hook_path(self, hook_type):
5050
return os.path.join(self.git_dir, 'hooks', hook_type)

pre_commit/schema.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,13 @@ def check(self, v):
142142
raise ValidationError('Expected a {} map but got a {}'.format(
143143
self.object_name, type(v).__name__,
144144
))
145-
with validate_context('At {}({}={!r})'.format(
145+
if self.id_key is None:
146+
context = 'At {}()'.format(self.object_name)
147+
else:
148+
context = 'At {}({}={!r})'.format(
146149
self.object_name, self.id_key, v.get(self.id_key, MISSING),
147-
)):
150+
)
151+
with validate_context(context):
148152
for item in self.items:
149153
item.check(v)
150154

testing/fixtures.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,9 @@ def make_config_from_repo(repo_path, sha=None, hooks=None, check=True):
9292
))
9393

9494
if check:
95-
wrapped = validate([config], CONFIG_SCHEMA)
96-
config, = apply_defaults(wrapped, CONFIG_SCHEMA)
95+
wrapped = validate({'repos': [config]}, CONFIG_SCHEMA)
96+
wrapped = apply_defaults(wrapped, CONFIG_SCHEMA)
97+
config, = wrapped['repos']
9798
return config
9899
else:
99100
return config
@@ -106,9 +107,9 @@ def read_config(directory, config_file=C.CONFIG_FILE):
106107

107108

108109
def write_config(directory, config, config_file=C.CONFIG_FILE):
109-
if type(config) is not list:
110+
if type(config) is not list and 'repos' not in config:
110111
assert type(config) is OrderedDict
111-
config = [config]
112+
config = {'repos': [config]}
112113
with io.open(os.path.join(directory, config_file), 'w') as outfile:
113114
outfile.write(ordered_dump(config, **C.YAML_DUMP_KWARGS))
114115

tests/clientlib_test.py

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,15 @@ def test_validate_config_main(args, expected_output):
6060
('config_obj', 'expected'), (
6161
([], False),
6262
(
63-
[{
63+
{'repos': [{
6464
'repo': 'git@github.com:pre-commit/pre-commit-hooks',
6565
'sha': 'cd74dc150c142c3be70b24eaf0b02cae9d235f37',
6666
'hooks': [{'id': 'pyflakes', 'files': '\\.py$'}],
67-
}],
67+
}]},
6868
True,
6969
),
7070
(
71-
[{
71+
{'repos': [{
7272
'repo': 'git@github.com:pre-commit/pre-commit-hooks',
7373
'sha': 'cd74dc150c142c3be70b24eaf0b02cae9d235f37',
7474
'hooks': [
@@ -78,11 +78,11 @@ def test_validate_config_main(args, expected_output):
7878
'args': ['foo', 'bar', 'baz'],
7979
},
8080
],
81-
}],
81+
}]},
8282
True,
8383
),
8484
(
85-
[{
85+
{'repos': [{
8686
'repo': 'git@github.com:pre-commit/pre-commit-hooks',
8787
'sha': 'cd74dc150c142c3be70b24eaf0b02cae9d235f37',
8888
'hooks': [
@@ -94,7 +94,7 @@ def test_validate_config_main(args, expected_output):
9494
'args': ['foo', 'bar', 'baz'],
9595
},
9696
],
97-
}],
97+
}]},
9898
False,
9999
),
100100
),
@@ -104,29 +104,25 @@ def test_config_valid(config_obj, expected):
104104
assert ret is expected
105105

106106

107-
@pytest.mark.parametrize(
108-
'config_obj', (
109-
[{
110-
'repo': 'local',
111-
'sha': 'foo',
112-
'hooks': [{
113-
'id': 'do_not_commit',
114-
'name': 'Block if "DO NOT COMMIT" is found',
115-
'entry': 'DO NOT COMMIT',
116-
'language': 'pcre',
117-
'files': '^(.*)$',
118-
}],
107+
def test_config_with_local_hooks_definition_fails():
108+
config_obj = {'repos': [{
109+
'repo': 'local',
110+
'sha': 'foo',
111+
'hooks': [{
112+
'id': 'do_not_commit',
113+
'name': 'Block if "DO NOT COMMIT" is found',
114+
'entry': 'DO NOT COMMIT',
115+
'language': 'pcre',
116+
'files': '^(.*)$',
119117
}],
120-
),
121-
)
122-
def test_config_with_local_hooks_definition_fails(config_obj):
118+
}]}
123119
with pytest.raises(schema.ValidationError):
124120
schema.validate(config_obj, CONFIG_SCHEMA)
125121

126122

127123
@pytest.mark.parametrize(
128124
'config_obj', (
129-
[{
125+
{'repos': [{
130126
'repo': 'local',
131127
'hooks': [{
132128
'id': 'arg-per-line',
@@ -136,8 +132,8 @@ def test_config_with_local_hooks_definition_fails(config_obj):
136132
'files': '',
137133
'args': ['hello', 'world'],
138134
}],
139-
}],
140-
[{
135+
}]},
136+
{'repos': [{
141137
'repo': 'local',
142138
'hooks': [{
143139
'id': 'arg-per-line',
@@ -147,7 +143,7 @@ def test_config_with_local_hooks_definition_fails(config_obj):
147143
'files': '',
148144
'args': ['hello', 'world'],
149145
}],
150-
}],
146+
}]},
151147
),
152148
)
153149
def test_config_with_local_hooks_definition_passes(config_obj):

tests/commands/autoupdate_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ def test_autoupdate_local_hooks(tempdir_factory):
274274
assert autoupdate(runner, tags_only=False) == 0
275275
new_config_writen = load_config(runner.config_file_path)
276276
assert len(new_config_writen) == 1
277-
assert new_config_writen[0] == config
277+
assert new_config_writen['repos'][0] == config
278278

279279

280280
def test_autoupdate_local_hooks_with_out_of_date_repo(
@@ -289,5 +289,5 @@ def test_autoupdate_local_hooks_with_out_of_date_repo(
289289
runner = Runner('.', C.CONFIG_FILE)
290290
assert autoupdate(runner, tags_only=False) == 0
291291
new_config_writen = load_config(runner.config_file_path)
292-
assert len(new_config_writen) == 2
293-
assert new_config_writen[0] == local_config
292+
assert len(new_config_writen['repos']) == 2
293+
assert new_config_writen['repos'][0] == local_config

tests/commands/run_test.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ def test_always_run(
272272
cap_out, repo_with_passing_hook, mock_out_store_directory,
273273
):
274274
with modify_config() as config:
275-
config[0]['hooks'][0]['always_run'] = True
275+
config['repos'][0]['hooks'][0]['always_run'] = True
276276
_test_run(
277277
cap_out,
278278
repo_with_passing_hook,
@@ -288,7 +288,7 @@ def test_always_run_alt_config(
288288
):
289289
repo_root = '.'
290290
config = read_config(repo_root)
291-
config[0]['hooks'][0]['always_run'] = True
291+
config['repos'][0]['hooks'][0]['always_run'] = True
292292
alt_config_file = 'alternate_config.yaml'
293293
add_config_to_repo(repo_root, config, config_file=alt_config_file)
294294

@@ -428,7 +428,7 @@ def test_multiple_hooks_same_id(
428428
with cwd(repo_with_passing_hook):
429429
# Add bash hook on there again
430430
with modify_config() as config:
431-
config[0]['hooks'].append({'id': 'bash_hook'})
431+
config['repos'][0]['hooks'].append({'id': 'bash_hook'})
432432
stage_a_file()
433433

434434
ret, output = _do_run(cap_out, repo_with_passing_hook, _get_opts())
@@ -455,7 +455,7 @@ def test_stdout_write_bug_py26(
455455
):
456456
with cwd(repo_with_failing_hook):
457457
with modify_config() as config:
458-
config[0]['hooks'][0]['args'] = ['☃']
458+
config['repos'][0]['hooks'][0]['args'] = ['☃']
459459
stage_a_file()
460460

461461
install(Runner(repo_with_failing_hook, C.CONFIG_FILE))
@@ -505,7 +505,7 @@ def test_lots_of_files(mock_out_store_directory, tempdir_factory):
505505
with cwd(git_path):
506506
# Override files so we run against them
507507
with modify_config() as config:
508-
config[0]['hooks'][0]['files'] = ''
508+
config['repos'][0]['hooks'][0]['files'] = ''
509509

510510
# Write a crap ton of files
511511
for i in range(400):
@@ -660,7 +660,7 @@ def test_local_hook_fails(
660660
def modified_config_repo(repo_with_passing_hook):
661661
with modify_config(repo_with_passing_hook, commit=False) as config:
662662
# Some minor modification
663-
config[0]['hooks'][0]['files'] = ''
663+
config['repos'][0]['hooks'][0]['files'] = ''
664664
yield repo_with_passing_hook
665665

666666

@@ -721,8 +721,8 @@ def test_pass_filenames(
721721
expected_out,
722722
):
723723
with modify_config() as config:
724-
config[0]['hooks'][0]['pass_filenames'] = pass_filenames
725-
config[0]['hooks'][0]['args'] = hook_args
724+
config['repos'][0]['hooks'][0]['pass_filenames'] = pass_filenames
725+
config['repos'][0]['hooks'][0]['args'] = hook_args
726726
stage_a_file()
727727
ret, printed = _do_run(
728728
cap_out, repo_with_passing_hook, _get_opts(verbose=True),

0 commit comments

Comments
 (0)