2025-02-09 21:32:53 +01:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2025-02-09 21:51:25 +01:00
|
|
|
from unittest import mock
|
|
|
|
|
2025-02-09 21:35:53 +01:00
|
|
|
import pytest
|
2025-02-09 21:51:25 +01:00
|
|
|
import yaml
|
2025-02-09 21:35:53 +01:00
|
|
|
|
2025-02-09 21:10:22 +01:00
|
|
|
import pre_commit.constants as C
|
2025-02-09 21:35:53 +01:00
|
|
|
from pre_commit.clientlib import InvalidConfigError
|
2025-02-09 21:10:22 +01:00
|
|
|
from pre_commit.commands.migrate_config import migrate_config
|
2025-02-09 21:51:25 +01:00
|
|
|
from pre_commit.yaml import yaml_compose
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(autouse=True, params=['c', 'pure'])
|
|
|
|
def switch_pyyaml_impl(request):
|
|
|
|
if request.param == 'c':
|
|
|
|
yield
|
|
|
|
else:
|
|
|
|
with mock.patch.dict(
|
|
|
|
yaml_compose.keywords,
|
|
|
|
{'Loader': yaml.SafeLoader},
|
|
|
|
):
|
|
|
|
yield
|
2025-02-09 21:10:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_migrate_config_normal_format(tmpdir, capsys):
|
|
|
|
cfg = tmpdir.join(C.CONFIG_FILE)
|
|
|
|
cfg.write(
|
|
|
|
'- repo: local\n'
|
|
|
|
' hooks:\n'
|
|
|
|
' - id: foo\n'
|
|
|
|
' name: foo\n'
|
|
|
|
' entry: ./bin/foo.sh\n'
|
|
|
|
' language: script\n',
|
|
|
|
)
|
|
|
|
with tmpdir.as_cwd():
|
|
|
|
assert not migrate_config(C.CONFIG_FILE)
|
|
|
|
out, _ = capsys.readouterr()
|
|
|
|
assert out == 'Configuration has been migrated.\n'
|
|
|
|
contents = cfg.read()
|
|
|
|
assert contents == (
|
|
|
|
'repos:\n'
|
|
|
|
'- repo: local\n'
|
|
|
|
' hooks:\n'
|
|
|
|
' - id: foo\n'
|
|
|
|
' name: foo\n'
|
|
|
|
' entry: ./bin/foo.sh\n'
|
|
|
|
' language: script\n'
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def test_migrate_config_document_marker(tmpdir):
|
|
|
|
cfg = tmpdir.join(C.CONFIG_FILE)
|
|
|
|
cfg.write(
|
|
|
|
'# comment\n'
|
|
|
|
'\n'
|
|
|
|
'---\n'
|
|
|
|
'- repo: local\n'
|
|
|
|
' hooks:\n'
|
|
|
|
' - id: foo\n'
|
|
|
|
' name: foo\n'
|
|
|
|
' entry: ./bin/foo.sh\n'
|
|
|
|
' language: script\n',
|
|
|
|
)
|
|
|
|
with tmpdir.as_cwd():
|
|
|
|
assert not migrate_config(C.CONFIG_FILE)
|
|
|
|
contents = cfg.read()
|
|
|
|
assert contents == (
|
|
|
|
'# comment\n'
|
|
|
|
'\n'
|
|
|
|
'---\n'
|
|
|
|
'repos:\n'
|
|
|
|
'- repo: local\n'
|
|
|
|
' hooks:\n'
|
|
|
|
' - id: foo\n'
|
|
|
|
' name: foo\n'
|
|
|
|
' entry: ./bin/foo.sh\n'
|
|
|
|
' language: script\n'
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def test_migrate_config_list_literal(tmpdir):
|
|
|
|
cfg = tmpdir.join(C.CONFIG_FILE)
|
|
|
|
cfg.write(
|
|
|
|
'[{\n'
|
|
|
|
' repo: local,\n'
|
|
|
|
' hooks: [{\n'
|
|
|
|
' id: foo, name: foo, entry: ./bin/foo.sh,\n'
|
|
|
|
' language: script,\n'
|
|
|
|
' }]\n'
|
|
|
|
'}]',
|
|
|
|
)
|
|
|
|
with tmpdir.as_cwd():
|
|
|
|
assert not migrate_config(C.CONFIG_FILE)
|
|
|
|
contents = cfg.read()
|
|
|
|
assert contents == (
|
|
|
|
'repos:\n'
|
|
|
|
' [{\n'
|
|
|
|
' repo: local,\n'
|
|
|
|
' hooks: [{\n'
|
|
|
|
' id: foo, name: foo, entry: ./bin/foo.sh,\n'
|
|
|
|
' language: script,\n'
|
|
|
|
' }]\n'
|
|
|
|
' }]'
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def test_already_migrated_configuration_noop(tmpdir, capsys):
|
|
|
|
contents = (
|
|
|
|
'repos:\n'
|
|
|
|
'- repo: local\n'
|
|
|
|
' hooks:\n'
|
|
|
|
' - id: foo\n'
|
|
|
|
' name: foo\n'
|
|
|
|
' entry: ./bin/foo.sh\n'
|
|
|
|
' language: script\n'
|
|
|
|
)
|
|
|
|
cfg = tmpdir.join(C.CONFIG_FILE)
|
|
|
|
cfg.write(contents)
|
|
|
|
with tmpdir.as_cwd():
|
|
|
|
assert not migrate_config(C.CONFIG_FILE)
|
|
|
|
out, _ = capsys.readouterr()
|
|
|
|
assert out == 'Configuration is already migrated.\n'
|
|
|
|
assert cfg.read() == contents
|
|
|
|
|
|
|
|
|
|
|
|
def test_migrate_config_sha_to_rev(tmpdir):
|
|
|
|
contents = (
|
|
|
|
'repos:\n'
|
|
|
|
'- repo: https://github.com/pre-commit/pre-commit-hooks\n'
|
|
|
|
' sha: v1.2.0\n'
|
|
|
|
' hooks: []\n'
|
|
|
|
'- repo: https://github.com/pre-commit/pre-commit-hooks\n'
|
|
|
|
' sha: v1.2.0\n'
|
|
|
|
' hooks: []\n'
|
|
|
|
)
|
|
|
|
cfg = tmpdir.join(C.CONFIG_FILE)
|
|
|
|
cfg.write(contents)
|
|
|
|
with tmpdir.as_cwd():
|
|
|
|
assert not migrate_config(C.CONFIG_FILE)
|
|
|
|
contents = cfg.read()
|
|
|
|
assert contents == (
|
|
|
|
'repos:\n'
|
|
|
|
'- repo: https://github.com/pre-commit/pre-commit-hooks\n'
|
|
|
|
' rev: v1.2.0\n'
|
|
|
|
' hooks: []\n'
|
|
|
|
'- repo: https://github.com/pre-commit/pre-commit-hooks\n'
|
|
|
|
' rev: v1.2.0\n'
|
|
|
|
' hooks: []\n'
|
|
|
|
)
|
2025-02-09 21:35:53 +01:00
|
|
|
|
|
|
|
|
2025-02-09 21:51:25 +01:00
|
|
|
def test_migrate_config_sha_to_rev_json(tmp_path):
|
|
|
|
contents = """\
|
|
|
|
{"repos": [{
|
|
|
|
"repo": "https://github.com/pre-commit/pre-commit-hooks",
|
|
|
|
"sha": "v1.2.0",
|
|
|
|
"hooks": []
|
|
|
|
}]}
|
|
|
|
"""
|
|
|
|
expected = """\
|
|
|
|
{"repos": [{
|
|
|
|
"repo": "https://github.com/pre-commit/pre-commit-hooks",
|
|
|
|
"rev": "v1.2.0",
|
|
|
|
"hooks": []
|
|
|
|
}]}
|
|
|
|
"""
|
|
|
|
cfg = tmp_path.joinpath('cfg.yaml')
|
|
|
|
cfg.write_text(contents)
|
|
|
|
assert not migrate_config(str(cfg))
|
|
|
|
assert cfg.read_text() == expected
|
|
|
|
|
|
|
|
|
2025-02-09 21:37:46 +01:00
|
|
|
def test_migrate_config_language_python_venv(tmp_path):
|
|
|
|
src = '''\
|
|
|
|
repos:
|
|
|
|
- repo: local
|
|
|
|
hooks:
|
|
|
|
- id: example
|
|
|
|
name: example
|
|
|
|
entry: example
|
|
|
|
language: python_venv
|
|
|
|
- id: example
|
|
|
|
name: example
|
|
|
|
entry: example
|
|
|
|
language: system
|
|
|
|
'''
|
|
|
|
expected = '''\
|
|
|
|
repos:
|
|
|
|
- repo: local
|
|
|
|
hooks:
|
|
|
|
- id: example
|
|
|
|
name: example
|
|
|
|
entry: example
|
|
|
|
language: python
|
|
|
|
- id: example
|
|
|
|
name: example
|
|
|
|
entry: example
|
|
|
|
language: system
|
|
|
|
'''
|
|
|
|
cfg = tmp_path.joinpath('cfg.yaml')
|
|
|
|
cfg.write_text(src)
|
|
|
|
assert migrate_config(str(cfg)) == 0
|
|
|
|
assert cfg.read_text() == expected
|
|
|
|
|
|
|
|
|
2025-02-09 21:51:25 +01:00
|
|
|
def test_migrate_config_quoted_python_venv(tmp_path):
|
|
|
|
src = '''\
|
|
|
|
repos:
|
|
|
|
- repo: local
|
|
|
|
hooks:
|
|
|
|
- id: example
|
|
|
|
name: example
|
|
|
|
entry: example
|
|
|
|
language: "python_venv"
|
|
|
|
'''
|
|
|
|
expected = '''\
|
|
|
|
repos:
|
|
|
|
- repo: local
|
|
|
|
hooks:
|
|
|
|
- id: example
|
|
|
|
name: example
|
|
|
|
entry: example
|
|
|
|
language: "python"
|
|
|
|
'''
|
|
|
|
cfg = tmp_path.joinpath('cfg.yaml')
|
|
|
|
cfg.write_text(src)
|
|
|
|
assert migrate_config(str(cfg)) == 0
|
|
|
|
assert cfg.read_text() == expected
|
|
|
|
|
|
|
|
|
|
|
|
def test_migrate_config_default_stages(tmp_path):
|
|
|
|
src = '''\
|
|
|
|
default_stages: [commit, push, merge-commit, commit-msg]
|
|
|
|
repos: []
|
|
|
|
'''
|
|
|
|
expected = '''\
|
|
|
|
default_stages: [pre-commit, pre-push, pre-merge-commit, commit-msg]
|
|
|
|
repos: []
|
|
|
|
'''
|
|
|
|
cfg = tmp_path.joinpath('cfg.yaml')
|
|
|
|
cfg.write_text(src)
|
|
|
|
assert migrate_config(str(cfg)) == 0
|
|
|
|
assert cfg.read_text() == expected
|
|
|
|
|
|
|
|
|
|
|
|
def test_migrate_config_hook_stages(tmp_path):
|
|
|
|
src = '''\
|
|
|
|
repos:
|
|
|
|
- repo: local
|
|
|
|
hooks:
|
|
|
|
- id: example
|
|
|
|
name: example
|
|
|
|
entry: example
|
|
|
|
language: system
|
|
|
|
stages: ["commit", "push", "merge-commit", "commit-msg"]
|
|
|
|
'''
|
|
|
|
expected = '''\
|
|
|
|
repos:
|
|
|
|
- repo: local
|
|
|
|
hooks:
|
|
|
|
- id: example
|
|
|
|
name: example
|
|
|
|
entry: example
|
|
|
|
language: system
|
|
|
|
stages: ["pre-commit", "pre-push", "pre-merge-commit", "commit-msg"]
|
|
|
|
'''
|
|
|
|
cfg = tmp_path.joinpath('cfg.yaml')
|
|
|
|
cfg.write_text(src)
|
|
|
|
assert migrate_config(str(cfg)) == 0
|
|
|
|
assert cfg.read_text() == expected
|
|
|
|
|
|
|
|
|
2025-02-09 21:35:53 +01:00
|
|
|
def test_migrate_config_invalid_yaml(tmpdir):
|
|
|
|
contents = '['
|
|
|
|
cfg = tmpdir.join(C.CONFIG_FILE)
|
|
|
|
cfg.write(contents)
|
|
|
|
with tmpdir.as_cwd(), pytest.raises(InvalidConfigError) as excinfo:
|
|
|
|
migrate_config(C.CONFIG_FILE)
|
|
|
|
expected = '\n==> File .pre-commit-config.yaml\n=====> '
|
|
|
|
assert str(excinfo.value).startswith(expected)
|