Merging upstream version 2.5.1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
344ec6ad68
commit
46a56c0856
37 changed files with 457 additions and 213 deletions
|
@ -414,9 +414,9 @@ def test_autoupdate_local_hooks(in_git_dir, store):
|
|||
config = sample_local_config()
|
||||
add_config_to_repo('.', config)
|
||||
assert autoupdate(C.CONFIG_FILE, store, freeze=False, tags_only=False) == 0
|
||||
new_config_writen = read_config('.')
|
||||
assert len(new_config_writen['repos']) == 1
|
||||
assert new_config_writen['repos'][0] == config
|
||||
new_config_written = read_config('.')
|
||||
assert len(new_config_written['repos']) == 1
|
||||
assert new_config_written['repos'][0] == config
|
||||
|
||||
|
||||
def test_autoupdate_local_hooks_with_out_of_date_repo(
|
||||
|
@ -429,9 +429,9 @@ def test_autoupdate_local_hooks_with_out_of_date_repo(
|
|||
config = {'repos': [local_config, stale_config]}
|
||||
write_config('.', config)
|
||||
assert autoupdate(C.CONFIG_FILE, store, freeze=False, tags_only=False) == 0
|
||||
new_config_writen = read_config('.')
|
||||
assert len(new_config_writen['repos']) == 2
|
||||
assert new_config_writen['repos'][0] == local_config
|
||||
new_config_written = read_config('.')
|
||||
assert len(new_config_written['repos']) == 2
|
||||
assert new_config_written['repos'][0] == local_config
|
||||
|
||||
|
||||
def test_autoupdate_meta_hooks(tmpdir, store):
|
||||
|
@ -474,3 +474,23 @@ def test_updates_old_format_to_new_format(tmpdir, capsys, store):
|
|||
)
|
||||
out, _ = capsys.readouterr()
|
||||
assert out == 'Configuration has been migrated.\n'
|
||||
|
||||
|
||||
def test_maintains_rev_quoting_style(tmpdir, out_of_date, store):
|
||||
fmt = (
|
||||
'repos:\n'
|
||||
'- repo: {path}\n'
|
||||
' rev: "{rev}"\n'
|
||||
' hooks:\n'
|
||||
' - id: foo\n'
|
||||
'- repo: {path}\n'
|
||||
" rev: '{rev}'\n"
|
||||
' hooks:\n'
|
||||
' - id: foo\n'
|
||||
)
|
||||
cfg = tmpdir.join(C.CONFIG_FILE)
|
||||
cfg.write(fmt.format(path=out_of_date.path, rev=out_of_date.original_rev))
|
||||
|
||||
assert autoupdate(str(cfg), store, freeze=False, tags_only=False) == 0
|
||||
expected = fmt.format(path=out_of_date.path, rev=out_of_date.head_rev)
|
||||
assert cfg.read() == expected
|
||||
|
|
|
@ -96,6 +96,7 @@ def test_run_legacy_recursive(tmpdir):
|
|||
('pre-merge-commit', []),
|
||||
('pre-push', ['branch_name', 'remote_name']),
|
||||
('commit-msg', ['.git/COMMIT_EDITMSG']),
|
||||
('post-commit', []),
|
||||
('post-checkout', ['old_head', 'new_head', '1']),
|
||||
# multiple choices for commit-editmsg
|
||||
('prepare-commit-msg', ['.git/COMMIT_EDITMSG']),
|
||||
|
@ -117,7 +118,7 @@ def test_check_args_length_error_too_many_plural():
|
|||
)
|
||||
|
||||
|
||||
def test_check_args_length_error_too_many_singluar():
|
||||
def test_check_args_length_error_too_many_singular():
|
||||
with pytest.raises(SystemExit) as excinfo:
|
||||
hook_impl._check_args_length('commit-msg', [])
|
||||
msg, = excinfo.value.args
|
||||
|
@ -149,6 +150,13 @@ def test_run_ns_commit_msg():
|
|||
assert ns.commit_msg_filename == '.git/COMMIT_MSG'
|
||||
|
||||
|
||||
def test_run_ns_post_commit():
|
||||
ns = hook_impl._run_ns('post-commit', True, (), b'')
|
||||
assert ns is not None
|
||||
assert ns.hook_stage == 'post-commit'
|
||||
assert ns.color is True
|
||||
|
||||
|
||||
def test_run_ns_post_checkout():
|
||||
ns = hook_impl._run_ns('post-checkout', True, ('a', 'b', 'c'), b'')
|
||||
assert ns is not None
|
||||
|
|
|
@ -726,6 +726,32 @@ def test_commit_msg_legacy(commit_msg_repo, tempdir_factory, store):
|
|||
assert second_line.startswith('Must have "Signed off by:"...')
|
||||
|
||||
|
||||
def test_post_commit_integration(tempdir_factory, store):
|
||||
path = git_dir(tempdir_factory)
|
||||
config = [
|
||||
{
|
||||
'repo': 'local',
|
||||
'hooks': [{
|
||||
'id': 'post-commit',
|
||||
'name': 'Post commit',
|
||||
'entry': 'touch post-commit.tmp',
|
||||
'language': 'system',
|
||||
'always_run': True,
|
||||
'verbose': True,
|
||||
'stages': ['post-commit'],
|
||||
}],
|
||||
},
|
||||
]
|
||||
write_config(path, config)
|
||||
with cwd(path):
|
||||
_get_commit_output(tempdir_factory)
|
||||
assert not os.path.exists('post-commit.tmp')
|
||||
|
||||
install(C.CONFIG_FILE, store, hook_types=['post-commit'])
|
||||
_get_commit_output(tempdir_factory)
|
||||
assert os.path.exists('post-commit.tmp')
|
||||
|
||||
|
||||
def test_post_checkout_integration(tempdir_factory, store):
|
||||
path = git_dir(tempdir_factory)
|
||||
config = [
|
||||
|
@ -763,6 +789,37 @@ def test_post_checkout_integration(tempdir_factory, store):
|
|||
assert 'some_file' not in stderr
|
||||
|
||||
|
||||
def test_skips_post_checkout_unstaged_changes(tempdir_factory, store):
|
||||
path = git_dir(tempdir_factory)
|
||||
config = {
|
||||
'repo': 'local',
|
||||
'hooks': [{
|
||||
'id': 'fail',
|
||||
'name': 'fail',
|
||||
'entry': 'fail',
|
||||
'language': 'fail',
|
||||
'always_run': True,
|
||||
'stages': ['post-checkout'],
|
||||
}],
|
||||
}
|
||||
write_config(path, config)
|
||||
with cwd(path):
|
||||
cmd_output('git', 'add', '.')
|
||||
_get_commit_output(tempdir_factory)
|
||||
|
||||
install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
|
||||
install(C.CONFIG_FILE, store, hook_types=['post-checkout'])
|
||||
|
||||
# make an unstaged change so staged_files_only fires
|
||||
open('file', 'a').close()
|
||||
cmd_output('git', 'add', 'file')
|
||||
with open('file', 'w') as f:
|
||||
f.write('unstaged changes')
|
||||
|
||||
retc, out = _get_commit_output(tempdir_factory, all_files=False)
|
||||
assert retc == 0
|
||||
|
||||
|
||||
def test_prepare_commit_msg_integration_failing(
|
||||
failing_prepare_commit_msg_repo, tempdir_factory, store,
|
||||
):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import pytest
|
||||
|
||||
import pre_commit.constants as C
|
||||
from pre_commit.clientlib import InvalidConfigError
|
||||
from pre_commit.commands.migrate_config import _indent
|
||||
from pre_commit.commands.migrate_config import migrate_config
|
||||
|
||||
|
@ -147,10 +148,10 @@ def test_migrate_config_sha_to_rev(tmpdir):
|
|||
|
||||
|
||||
@pytest.mark.parametrize('contents', ('', '\n'))
|
||||
def test_empty_configuration_file_user_error(tmpdir, contents):
|
||||
def test_migrate_config_invalid_configuration(tmpdir, contents):
|
||||
cfg = tmpdir.join(C.CONFIG_FILE)
|
||||
cfg.write(contents)
|
||||
with tmpdir.as_cwd():
|
||||
assert not migrate_config(C.CONFIG_FILE)
|
||||
with tmpdir.as_cwd(), pytest.raises(InvalidConfigError):
|
||||
migrate_config(C.CONFIG_FILE)
|
||||
# even though the config is invalid, this should be a noop
|
||||
assert cfg.read() == contents
|
||||
|
|
|
@ -939,7 +939,7 @@ def test_classifier_normalizes_filenames_on_windows_to_forward_slashes(tmpdir):
|
|||
tmpdir.join('a/b/c').ensure()
|
||||
with mock.patch.object(os, 'altsep', '/'):
|
||||
with mock.patch.object(os, 'sep', '\\'):
|
||||
classifier = Classifier((r'a\b\c',))
|
||||
classifier = Classifier.from_config((r'a\b\c',), '', '^$')
|
||||
assert classifier.filenames == ['a/b/c']
|
||||
|
||||
|
||||
|
@ -947,7 +947,7 @@ def test_classifier_does_not_normalize_backslashes_non_windows(tmpdir):
|
|||
with mock.patch.object(os.path, 'lexists', return_value=True):
|
||||
with mock.patch.object(os, 'altsep', None):
|
||||
with mock.patch.object(os, 'sep', '/'):
|
||||
classifier = Classifier((r'a/b\c',))
|
||||
classifier = Classifier.from_config((r'a/b\c',), '', '^$')
|
||||
assert classifier.filenames == [r'a/b\c']
|
||||
|
||||
|
||||
|
@ -1022,3 +1022,18 @@ def test_args_hook_only(cap_out, store, repo_with_passing_hook):
|
|||
run_opts(hook='do_not_commit'),
|
||||
)
|
||||
assert b'identity-copy' not in printed
|
||||
|
||||
|
||||
def test_skipped_without_any_setup_for_post_checkout(in_git_dir, store):
|
||||
environ = {'_PRE_COMMIT_SKIP_POST_CHECKOUT': '1'}
|
||||
opts = run_opts(hook_stage='post-checkout')
|
||||
assert run(C.CONFIG_FILE, store, opts, environ=environ) == 0
|
||||
|
||||
|
||||
def test_pre_commit_env_variable_set(cap_out, store, repo_with_passing_hook):
|
||||
args = run_opts()
|
||||
environ: EnvironT = {}
|
||||
ret, printed = _do_run(
|
||||
cap_out, store, repo_with_passing_hook, args, environ,
|
||||
)
|
||||
assert environ['PRE_COMMIT'] == '1'
|
||||
|
|
|
@ -186,3 +186,8 @@ def test_no_git_env():
|
|||
'GIT_SSH': '/usr/bin/ssh',
|
||||
'GIT_SSH_COMMAND': 'ssh -o',
|
||||
}
|
||||
|
||||
|
||||
def test_init_repo_no_hooks(tmpdir):
|
||||
git.init_repo(str(tmpdir), remote='dne')
|
||||
assert not tmpdir.join('.git/hooks').exists()
|
||||
|
|
|
@ -78,5 +78,5 @@ def test_target_concurrency_cpu_count_not_implemented():
|
|||
|
||||
def test_shuffled_is_deterministic():
|
||||
seq = [str(i) for i in range(10)]
|
||||
expected = ['3', '7', '8', '2', '4', '6', '5', '1', '0', '9']
|
||||
expected = ['4', '0', '5', '1', '8', '6', '2', '3', '7', '9']
|
||||
assert helpers._shuffled(seq) == expected
|
||||
|
|
|
@ -5,10 +5,23 @@ from unittest import mock
|
|||
import pytest
|
||||
|
||||
import pre_commit.constants as C
|
||||
from pre_commit.envcontext import envcontext
|
||||
from pre_commit.languages import python
|
||||
from pre_commit.prefix import Prefix
|
||||
|
||||
|
||||
def test_read_pyvenv_cfg(tmpdir):
|
||||
pyvenv_cfg = tmpdir.join('pyvenv.cfg')
|
||||
pyvenv_cfg.write(
|
||||
'# I am a comment\n'
|
||||
'\n'
|
||||
'foo = bar\n'
|
||||
'version-info=123\n',
|
||||
)
|
||||
expected = {'foo': 'bar', 'version-info': '123'}
|
||||
assert python._read_pyvenv_cfg(pyvenv_cfg) == expected
|
||||
|
||||
|
||||
def test_norm_version_expanduser():
|
||||
home = os.path.expanduser('~')
|
||||
if os.name == 'nt': # pragma: nt cover
|
||||
|
@ -21,6 +34,10 @@ def test_norm_version_expanduser():
|
|||
assert result == expected_path
|
||||
|
||||
|
||||
def test_norm_version_of_default_is_sys_executable():
|
||||
assert python.norm_version('default') == os.path.realpath(sys.executable)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('v', ('python3.6', 'python3', 'python'))
|
||||
def test_sys_executable_matches(v):
|
||||
with mock.patch.object(sys, 'version_info', (3, 6, 7)):
|
||||
|
@ -49,27 +66,78 @@ def test_find_by_sys_executable(exe, realpath, expected):
|
|||
assert python._find_by_sys_executable() == expected
|
||||
|
||||
|
||||
def test_healthy_types_py_in_cwd(tmpdir):
|
||||
@pytest.fixture
|
||||
def python_dir(tmpdir):
|
||||
with tmpdir.as_cwd():
|
||||
prefix = tmpdir.join('prefix').ensure_dir()
|
||||
prefix.join('setup.py').write('import setuptools; setuptools.setup()')
|
||||
prefix = Prefix(str(prefix))
|
||||
yield prefix, tmpdir
|
||||
|
||||
|
||||
def test_healthy_default_creator(python_dir):
|
||||
prefix, tmpdir = python_dir
|
||||
|
||||
python.install_environment(prefix, C.DEFAULT, ())
|
||||
|
||||
# should be healthy right after creation
|
||||
assert python.healthy(prefix, C.DEFAULT) is True
|
||||
|
||||
# even if a `types.py` file exists, should still be healthy
|
||||
tmpdir.join('types.py').ensure()
|
||||
assert python.healthy(prefix, C.DEFAULT) is True
|
||||
|
||||
|
||||
def test_healthy_venv_creator(python_dir):
|
||||
# venv creator produces slightly different pyvenv.cfg
|
||||
prefix, tmpdir = python_dir
|
||||
|
||||
with envcontext((('VIRTUALENV_CREATOR', 'venv'),)):
|
||||
python.install_environment(prefix, C.DEFAULT, ())
|
||||
|
||||
# even if a `types.py` file exists, should still be healthy
|
||||
tmpdir.join('types.py').ensure()
|
||||
assert python.healthy(prefix, C.DEFAULT) is True
|
||||
assert python.healthy(prefix, C.DEFAULT) is True
|
||||
|
||||
|
||||
def test_healthy_python_goes_missing(tmpdir):
|
||||
with tmpdir.as_cwd():
|
||||
prefix = tmpdir.join('prefix').ensure_dir()
|
||||
prefix.join('setup.py').write('import setuptools; setuptools.setup()')
|
||||
prefix = Prefix(str(prefix))
|
||||
python.install_environment(prefix, C.DEFAULT, ())
|
||||
def test_unhealthy_python_goes_missing(python_dir):
|
||||
prefix, tmpdir = python_dir
|
||||
|
||||
exe_name = 'python' if sys.platform != 'win32' else 'python.exe'
|
||||
py_exe = prefix.path(python.bin_dir('py_env-default'), exe_name)
|
||||
os.remove(py_exe)
|
||||
python.install_environment(prefix, C.DEFAULT, ())
|
||||
|
||||
assert python.healthy(prefix, C.DEFAULT) is False
|
||||
exe_name = 'python' if sys.platform != 'win32' else 'python.exe'
|
||||
py_exe = prefix.path(python.bin_dir('py_env-default'), exe_name)
|
||||
os.remove(py_exe)
|
||||
|
||||
assert python.healthy(prefix, C.DEFAULT) is False
|
||||
|
||||
|
||||
def test_unhealthy_with_version_change(python_dir):
|
||||
prefix, tmpdir = python_dir
|
||||
|
||||
python.install_environment(prefix, C.DEFAULT, ())
|
||||
|
||||
with open(prefix.path('py_env-default/pyvenv.cfg'), 'w') as f:
|
||||
f.write('version_info = 1.2.3\n')
|
||||
|
||||
assert python.healthy(prefix, C.DEFAULT) is False
|
||||
|
||||
|
||||
def test_unhealthy_system_version_changes(python_dir):
|
||||
prefix, tmpdir = python_dir
|
||||
|
||||
python.install_environment(prefix, C.DEFAULT, ())
|
||||
|
||||
with open(prefix.path('py_env-default/pyvenv.cfg'), 'a') as f:
|
||||
f.write('base-executable = /does/not/exist\n')
|
||||
|
||||
assert python.healthy(prefix, C.DEFAULT) is False
|
||||
|
||||
|
||||
def test_unhealthy_old_virtualenv(python_dir):
|
||||
prefix, tmpdir = python_dir
|
||||
|
||||
python.install_environment(prefix, C.DEFAULT, ())
|
||||
|
||||
# simulate "old" virtualenv by deleting this file
|
||||
os.remove(prefix.path('py_env-default/pyvenv.cfg'))
|
||||
|
||||
assert python.healthy(prefix, C.DEFAULT) is False
|
||||
|
|
|
@ -33,7 +33,7 @@ from testing.util import cwd
|
|||
from testing.util import get_resource_path
|
||||
from testing.util import skipif_cant_run_docker
|
||||
from testing.util import skipif_cant_run_swift
|
||||
from testing.util import xfailif_no_venv
|
||||
from testing.util import xfailif_windows
|
||||
from testing.util import xfailif_windows_no_ruby
|
||||
|
||||
|
||||
|
@ -163,7 +163,6 @@ def test_python_hook_weird_setup_cfg(in_git_dir, tempdir_factory, store):
|
|||
)
|
||||
|
||||
|
||||
@xfailif_no_venv
|
||||
def test_python_venv(tempdir_factory, store): # pragma: no cover (no venv)
|
||||
_test_hook_repo(
|
||||
tempdir_factory, store, 'python_venv_hooks_repo',
|
||||
|
@ -243,6 +242,7 @@ def test_run_a_node_hook(tempdir_factory, store):
|
|||
)
|
||||
|
||||
|
||||
@xfailif_windows # pragma: win32 no cover
|
||||
def test_run_a_node_hook_default_version(tempdir_factory, store):
|
||||
# make sure that this continues to work for platforms where node is not
|
||||
# installed at the system
|
||||
|
@ -252,6 +252,7 @@ def test_run_a_node_hook_default_version(tempdir_factory, store):
|
|||
test_run_a_node_hook(tempdir_factory, store)
|
||||
|
||||
|
||||
@xfailif_windows # pragma: win32 no cover
|
||||
def test_run_versioned_node_hook(tempdir_factory, store):
|
||||
_test_hook_repo(
|
||||
tempdir_factory, store, 'node_versioned_hooks_repo',
|
||||
|
@ -534,6 +535,7 @@ def test_additional_ruby_dependencies_installed(tempdir_factory, store):
|
|||
assert 'tins' in output
|
||||
|
||||
|
||||
@xfailif_windows # pragma: win32 no cover
|
||||
def test_additional_node_dependencies_installed(tempdir_factory, store):
|
||||
path = make_repo(tempdir_factory, 'node_hooks_repo')
|
||||
config = make_config_from_repo(path)
|
||||
|
@ -880,7 +882,7 @@ def test_manifest_hooks(tempdir_factory, store):
|
|||
require_serial=False,
|
||||
stages=(
|
||||
'commit', 'merge-commit', 'prepare-commit-msg', 'commit-msg',
|
||||
'manual', 'post-checkout', 'push',
|
||||
'post-commit', 'manual', 'post-checkout', 'push',
|
||||
),
|
||||
types=['file'],
|
||||
verbose=False,
|
||||
|
|
|
@ -25,7 +25,8 @@ def test_our_session_fixture_works():
|
|||
def test_get_default_directory_defaults_to_home():
|
||||
# Not we use the module level one which is not mocked
|
||||
ret = _get_default_directory()
|
||||
assert ret == os.path.join(os.path.expanduser('~/.cache'), 'pre-commit')
|
||||
expected = os.path.realpath(os.path.expanduser('~/.cache/pre-commit'))
|
||||
assert ret == expected
|
||||
|
||||
|
||||
def test_adheres_to_xdg_specification():
|
||||
|
@ -33,7 +34,8 @@ def test_adheres_to_xdg_specification():
|
|||
os.environ, {'XDG_CACHE_HOME': '/tmp/fakehome'},
|
||||
):
|
||||
ret = _get_default_directory()
|
||||
assert ret == os.path.join('/tmp/fakehome', 'pre-commit')
|
||||
expected = os.path.realpath('/tmp/fakehome/pre-commit')
|
||||
assert ret == expected
|
||||
|
||||
|
||||
def test_uses_environment_variable_when_present():
|
||||
|
@ -41,7 +43,8 @@ def test_uses_environment_variable_when_present():
|
|||
os.environ, {'PRE_COMMIT_HOME': '/tmp/pre_commit_home'},
|
||||
):
|
||||
ret = _get_default_directory()
|
||||
assert ret == '/tmp/pre_commit_home'
|
||||
expected = os.path.realpath('/tmp/pre_commit_home')
|
||||
assert ret == expected
|
||||
|
||||
|
||||
def test_store_init(store):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue