add support for top-level map manifest

This commit is contained in:
Anthony Sottile 2025-11-19 16:14:54 -05:00 committed by anthony sottile
parent 9c7ea88ab9
commit 7cad9ec27f
10 changed files with 156 additions and 61 deletions

View file

@ -12,7 +12,6 @@ from pre_commit.clientlib import CONFIG_HOOK_DICT
from pre_commit.clientlib import CONFIG_REPO_DICT
from pre_commit.clientlib import CONFIG_SCHEMA
from pre_commit.clientlib import DEFAULT_LANGUAGE_VERSION
from pre_commit.clientlib import InvalidManifestError
from pre_commit.clientlib import load_manifest
from pre_commit.clientlib import MANIFEST_HOOK_DICT
from pre_commit.clientlib import MANIFEST_SCHEMA
@ -405,30 +404,40 @@ def test_unsupported_language_migration_language_required():
@pytest.mark.parametrize(
'manifest_obj',
(
[{
'id': 'a',
'name': 'b',
'entry': 'c',
'language': 'python',
'files': r'\.py$',
}],
[{
'id': 'a',
'name': 'b',
'entry': 'c',
'language': 'python',
'language_version': 'python3.4',
'files': r'\.py$',
}],
{
'hooks': {
'a': {
'name': 'b',
'entry': 'c',
'language': 'python',
'files': r'\.py$',
},
},
},
{
'hooks': {
'a': {
'name': 'b',
'entry': 'c',
'language': 'python',
'language_version': 'python3.4',
'files': r'\.py$',
},
},
},
# A regression in 0.13.5: always_run and files are permissible
[{
'id': 'a',
'name': 'b',
'entry': 'c',
'language': 'python',
'files': '',
'always_run': True,
}],
{
'hooks': {
'a': {
'id': 'a',
'name': 'b',
'entry': 'c',
'language': 'python',
'files': '',
'always_run': True,
},
},
},
),
)
def test_valid_manifests(manifest_obj):
@ -592,16 +601,31 @@ def test_config_hook_stages_defaulting():
}
def test_manifest_v5_forward_compat(tmp_path):
def test_manifest_backward_compat(tmp_path):
src = '''\
- id: example
name: example
language: unsupported
entry: echo
'''
manifest = tmp_path.joinpath('.pre-commit-hooks.yaml')
manifest.write_text('hooks: {}')
manifest.write_text(src)
with pytest.raises(InvalidManifestError) as excinfo:
load_manifest(manifest)
assert str(excinfo.value) == (
f'\n'
f'==> File {manifest}\n'
f'=====> \n'
f'=====> pre-commit version 5 is required but version {C.VERSION} '
f'is installed. Perhaps run `pip install --upgrade pre-commit`.'
)
ret = load_manifest(manifest)
# just to make the assertion easier
assert 'id' not in ret['hooks']['example']
for k in tuple(ret['hooks']['example']):
if k not in {'name', 'language', 'entry'}:
ret['hooks']['example'].pop(k)
assert ret == {
'minimum_pre_commit_version': '0',
'hooks': {
'example': {
'name': 'example',
'language': 'unsupported',
'entry': 'echo',
},
},
}

View file

@ -344,7 +344,8 @@ def local_python_config():
repo_path = get_resource_path('python_hooks_repo')
manifest = load_manifest(os.path.join(repo_path, C.MANIFEST_FILE))
hooks = [
dict(hook, additional_dependencies=[repo_path]) for hook in manifest
{'id': hook_id, **hook, 'additional_dependencies': [repo_path]}
for hook_id, hook in manifest['hooks'].items()
]
return {'repo': 'local', 'hooks': hooks}

View file

@ -144,6 +144,48 @@ def test_warning_for_deprecated_stages_on_init(store, tempdir_factory, caplog):
assert caplog.record_tuples == []
def test_warning_for_deprecated_stages_v5_manifest(
store, tempdir_factory, caplog,
):
manifest = '''\
hooks:
hook1:
name: hook1
language: system
entry: echo hook1
stages: [commit, push]
hook2:
name: hook2
language: system
entry: echo hook2
stages: [push, merge-commit]
'''
path = git_dir(tempdir_factory)
with open(os.path.join(path, C.MANIFEST_FILE), 'w') as f:
f.write(manifest)
cmd_output('git', 'add', '.', cwd=path)
git_commit(cwd=path)
rev = git.head_rev(path)
store.clone(path, rev)
assert caplog.record_tuples[1] == (
'pre_commit',
logging.WARNING,
f'repo `{path}` uses deprecated stage names '
f'(commit, push, merge-commit) which will be removed in a future '
f'version. '
f'Hint: often `pre-commit autoupdate --repo {shlex.quote(path)}` '
f'will fix this. '
f'if it does not -- consider reporting an issue to that repo.',
)
# should not re-warn
caplog.clear()
store.clone(path, rev)
assert caplog.record_tuples == []
def test_no_warning_for_non_deprecated_stages_on_init(
store, tempdir_factory, caplog,
):