1
0
Fork 0

Merging upstream version 2.18.1.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-09 21:33:11 +01:00
parent 131d7bde70
commit 3396d2e509
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
116 changed files with 718 additions and 410 deletions

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import logging
import re

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import sys
from unittest import mock

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import shlex
from unittest import mock
@ -101,6 +103,24 @@ def test_rev_info_update_tags_only_does_not_pick_tip(tagged):
assert new_info.rev == 'v1.2.3'
def test_rev_info_update_tags_prefers_version_tag(tagged, out_of_date):
cmd_output('git', 'tag', 'latest', cwd=out_of_date.path)
config = make_config_from_repo(tagged.path, rev=tagged.original_rev)
info = RevInfo.from_config(config)
new_info = info.update(tags_only=True, freeze=False)
assert new_info.rev == 'v1.2.3'
def test_rev_info_update_tags_non_version_tag(out_of_date):
cmd_output('git', 'tag', 'latest', cwd=out_of_date.path)
config = make_config_from_repo(
out_of_date.path, rev=out_of_date.original_rev,
)
info = RevInfo.from_config(config)
new_info = info.update(tags_only=True, freeze=False)
assert new_info.rev == 'latest'
def test_rev_info_update_freeze_tag(tagged):
git_commit(cwd=tagged.path)
config = make_config_from_repo(tagged.path, rev=tagged.original_rev)

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
from unittest import mock

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os
import pre_commit.constants as C

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import subprocess
import sys
from unittest import mock

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
from unittest import mock

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
import re
@ -5,6 +7,7 @@ import re_assert
import pre_commit.constants as C
from pre_commit import git
from pre_commit.commands.install_uninstall import _hook_types
from pre_commit.commands.install_uninstall import CURRENT_HASH
from pre_commit.commands.install_uninstall import install
from pre_commit.commands.install_uninstall import install_hooks
@ -25,6 +28,36 @@ from testing.util import cwd
from testing.util import git_commit
def test_hook_types_explicitly_listed():
assert _hook_types(os.devnull, ['pre-push']) == ['pre-push']
def test_hook_types_default_value_when_not_specified():
assert _hook_types(os.devnull, None) == ['pre-commit']
def test_hook_types_configured(tmpdir):
cfg = tmpdir.join('t.cfg')
cfg.write('default_install_hook_types: [pre-push]\nrepos: []\n')
assert _hook_types(str(cfg), None) == ['pre-push']
def test_hook_types_configured_nonsense(tmpdir):
cfg = tmpdir.join('t.cfg')
cfg.write('default_install_hook_types: []\nrepos: []\n')
# hopefully the user doesn't do this, but the code allows it!
assert _hook_types(str(cfg), None) == []
def test_hook_types_configuration_has_error(tmpdir):
cfg = tmpdir.join('t.cfg')
cfg.write('[')
assert _hook_types(str(cfg), None) == ['pre-commit']
def test_is_not_script():
assert is_our_script('setup.py') is False
@ -59,7 +92,7 @@ def test_install_multiple_hooks_at_once(in_git_dir, store):
install(C.CONFIG_FILE, store, hook_types=['pre-commit', 'pre-push'])
assert in_git_dir.join('.git/hooks/pre-commit').exists()
assert in_git_dir.join('.git/hooks/pre-push').exists()
uninstall(hook_types=['pre-commit', 'pre-push'])
uninstall(C.CONFIG_FILE, hook_types=['pre-commit', 'pre-push'])
assert not in_git_dir.join('.git/hooks/pre-commit').exists()
assert not in_git_dir.join('.git/hooks/pre-push').exists()
@ -77,14 +110,14 @@ def test_install_hooks_dead_symlink(in_git_dir, store):
def test_uninstall_does_not_blow_up_when_not_there(in_git_dir):
assert uninstall(hook_types=['pre-commit']) == 0
assert uninstall(C.CONFIG_FILE, hook_types=['pre-commit']) == 0
def test_uninstall(in_git_dir, store):
assert not in_git_dir.join('.git/hooks/pre-commit').exists()
install(C.CONFIG_FILE, store, hook_types=['pre-commit'])
assert in_git_dir.join('.git/hooks/pre-commit').exists()
uninstall(hook_types=['pre-commit'])
uninstall(C.CONFIG_FILE, hook_types=['pre-commit'])
assert not in_git_dir.join('.git/hooks/pre-commit').exists()
@ -414,7 +447,7 @@ def test_uninstall_restores_legacy_hooks(tempdir_factory, store):
# Now install and uninstall pre-commit
assert install(C.CONFIG_FILE, store, hook_types=['pre-commit']) == 0
assert uninstall(hook_types=['pre-commit']) == 0
assert uninstall(C.CONFIG_FILE, hook_types=['pre-commit']) == 0
# Make sure we installed the "old" hook correctly
ret, output = _get_commit_output(tempdir_factory, touch_file='baz')
@ -449,7 +482,7 @@ def test_uninstall_doesnt_remove_not_our_hooks(in_git_dir):
pre_commit.write('#!/usr/bin/env bash\necho 1\n')
make_executable(pre_commit.strpath)
assert uninstall(hook_types=['pre-commit']) == 0
assert uninstall(C.CONFIG_FILE, hook_types=['pre-commit']) == 0
assert pre_commit.exists()
@ -1005,3 +1038,16 @@ def test_install_temporarily_allow_mising_config(tempdir_factory, store):
'Skipping `pre-commit`.'
)
assert expected in output
def test_install_uninstall_default_hook_types(in_git_dir, store):
cfg_src = 'default_install_hook_types: [pre-commit, pre-push]\nrepos: []\n'
in_git_dir.join(C.CONFIG_FILE).write(cfg_src)
assert not install(C.CONFIG_FILE, store, hook_types=None)
assert os.access(in_git_dir.join('.git/hooks/pre-commit').strpath, os.X_OK)
assert os.access(in_git_dir.join('.git/hooks/pre-push').strpath, os.X_OK)
assert not uninstall(C.CONFIG_FILE, hook_types=None)
assert not in_git_dir.join('.git/hooks/pre-commit').exists()
assert not in_git_dir.join('.git/hooks/pre-push').exists()

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import pre_commit.constants as C
from pre_commit.commands.migrate_config import migrate_config

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
import shlex
import sys

View file

@ -1,3 +1,5 @@
from __future__ import annotations
from pre_commit.commands.sample_config import sample_config

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
import re
import time

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import functools
import io
import logging

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os
from unittest import mock

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
import stat
import sys

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
import pytest
@ -19,6 +21,20 @@ def test_get_root_deeper(in_git_dir):
assert os.path.normcase(git.get_root()) == expected
def test_get_root_in_git_sub_dir(in_git_dir):
expected = os.path.normcase(in_git_dir.strpath)
with pytest.raises(FatalError):
with in_git_dir.join('.git/objects').ensure_dir().as_cwd():
assert os.path.normcase(git.get_root()) == expected
def test_get_root_not_in_working_dir(in_git_dir):
expected = os.path.normcase(in_git_dir.strpath)
with pytest.raises(FatalError):
with in_git_dir.join('..').ensure_dir().as_cwd():
assert os.path.normcase(git.get_root()) == expected
def test_in_exactly_dot_git(in_git_dir):
with in_git_dir.join('.git').as_cwd(), pytest.raises(FatalError):
git.get_root()
@ -38,6 +54,22 @@ def test_get_root_bare_worktree(tmpdir):
assert git.get_root() == os.path.abspath('.')
def test_get_git_dir(tmpdir):
"""Regression test for #1972"""
src = tmpdir.join('src').ensure_dir()
cmd_output('git', 'init', str(src))
git_commit(cwd=str(src))
worktree = tmpdir.join('worktree').ensure_dir()
cmd_output('git', 'worktree', 'add', '../worktree', cwd=src)
with worktree.as_cwd():
assert git.get_git_dir() == src.ensure_dir(
'.git/worktrees/worktree',
)
assert git.get_git_common_dir() == src.ensure_dir('.git')
def test_get_root_worktree_in_git(tmpdir):
src = tmpdir.join('src').ensure_dir()
cmd_output('git', 'init', str(src))

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest
from pre_commit import envcontext

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import builtins
import json
import ntpath

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest
from pre_commit.languages.golang import guess_go_dir

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import multiprocessing
import os.path
import sys
@ -86,7 +88,9 @@ def test_assert_no_additional_deps():
helpers.assert_no_additional_deps('lang', ['hmmm'])
msg, = excinfo.value.args
assert msg == (
'For now, pre-commit does not support additional_dependencies for lang'
'for now, pre-commit does not support additional_dependencies for '
'lang -- '
"you selected `additional_dependencies: ['hmmm']`"
)

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import json
import os
import shutil

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest
from pre_commit.languages import pygrep

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
import sys
from unittest import mock
@ -47,16 +49,16 @@ def test_norm_version_of_default_is_sys_executable():
assert python.norm_version('default') is None
@pytest.mark.parametrize('v', ('python3.6', 'python3', 'python'))
@pytest.mark.parametrize('v', ('python3.9', 'python3', 'python'))
def test_sys_executable_matches(v):
with mock.patch.object(sys, 'version_info', (3, 6, 7)):
with mock.patch.object(sys, 'version_info', (3, 9, 10)):
assert python._sys_executable_matches(v)
assert python.norm_version(v) is None
@pytest.mark.parametrize('v', ('notpython', 'python3.x'))
def test_sys_executable_matches_does_not_match(v):
with mock.patch.object(sys, 'version_info', (3, 6, 7)):
with mock.patch.object(sys, 'version_info', (3, 9, 10)):
assert not python._sys_executable_matches(v)
@ -65,7 +67,7 @@ def test_sys_executable_matches_does_not_match(v):
('/usr/bin/python3', '/usr/bin/python3.7', 'python3'),
('/usr/bin/python', '/usr/bin/python3.7', 'python3.7'),
('/usr/bin/python', '/usr/bin/python', None),
('/usr/bin/python3.6m', '/usr/bin/python3.6m', 'python3.6m'),
('/usr/bin/python3.7m', '/usr/bin/python3.7m', 'python3.7m'),
('v/bin/python', 'v/bin/pypy', 'pypy'),
),
)

View file

@ -1,7 +1,10 @@
from __future__ import annotations
import os.path
import pytest
from pre_commit import envcontext
from pre_commit.languages import r
from testing.fixtures import make_config_from_repo
from testing.fixtures import make_repo
@ -127,3 +130,14 @@ def test_r_parsing_file_local(tempdir_factory, store):
config=config,
expect_path_prefix=False,
)
def test_rscript_exec_relative_to_r_home():
expected = os.path.join('r_home_dir', 'bin', 'Rscript')
with envcontext.envcontext((('R_HOME', 'r_home_dir'),)):
assert r._rscript_exec() == expected
def test_path_rscript_exec_no_r_home_set():
with envcontext.envcontext((('R_HOME', envcontext.UNSET),)):
assert r._rscript_exec() == 'Rscript'

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
import tarfile
from unittest import mock

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import logging
from pre_commit import color

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import argparse
import os.path
from unittest import mock
@ -12,20 +14,6 @@ from testing.auto_namedtuple import auto_namedtuple
from testing.util import cwd
@pytest.mark.parametrize(
('argv', 'expected'),
(
((), ['f']),
(('--f', 'x'), ['x']),
(('--f', 'x', '--f', 'y'), ['x', 'y']),
),
)
def test_append_replace_default(argv, expected):
parser = argparse.ArgumentParser()
parser.add_argument('--f', action=main.AppendReplaceDefault, default=['f'])
assert parser.parse_args(argv).f == expected
def _args(**kwargs):
kwargs.setdefault('command', 'help')
kwargs.setdefault('config', C.CONFIG_FILE)
@ -170,7 +158,7 @@ def test_init_templatedir(mock_store_dir):
assert patch.call_count == 1
assert 'tdir' in patch.call_args[0]
assert patch.call_args[1]['hook_types'] == ['pre-commit']
assert patch.call_args[1]['hook_types'] is None
assert patch.call_args[1]['skip_on_missing_config'] is True

View file

@ -1,3 +1,5 @@
from __future__ import annotations
from pre_commit.meta_hooks import check_hooks_apply
from testing.fixtures import add_config_to_repo

View file

@ -1,3 +1,5 @@
from __future__ import annotations
from pre_commit import git
from pre_commit.meta_hooks import check_useless_excludes
from pre_commit.util import cmd_output

View file

@ -1,3 +1,5 @@
from __future__ import annotations
from pre_commit.meta_hooks import identity

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import io
from pre_commit import output

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import contextlib
import os.path
import shutil

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
import pytest

View file

@ -1,8 +1,8 @@
from __future__ import annotations
import os.path
import shutil
import sys
from typing import Any
from typing import Dict
from unittest import mock
import cfgv
@ -875,7 +875,7 @@ def test_tags_on_repositories(in_tmpdir, tempdir_factory, store):
@pytest.fixture
def local_python_config():
# Make a "local" hooks repo that just installs our other hooks repo
repo_path = get_resource_path('python_hooks_repo')
repo_path = get_resource_path('python3_hooks_repo')
manifest = load_manifest(os.path.join(repo_path, C.MANIFEST_FILE))
hooks = [
dict(hook, additional_dependencies=[repo_path]) for hook in manifest
@ -883,21 +883,27 @@ def local_python_config():
return {'repo': 'local', 'hooks': hooks}
@pytest.mark.xfail( # pragma: win32 no cover
sys.platform == 'win32',
reason='microsoft/azure-pipelines-image-generation#989',
)
def test_local_python_repo(store, local_python_config):
hook = _get_hook(local_python_config, store, 'foo')
hook = _get_hook(local_python_config, store, 'python3-hook')
# language_version should have been adjusted to the interpreter version
assert hook.language_version != C.DEFAULT
ret, out = _hook_run(hook, ('filename',), color=False)
assert ret == 0
assert _norm_out(out) == b"['filename']\nHello World\n"
assert _norm_out(out) == b"3\n['filename']\nHello World\n"
def test_local_python_repo_python2(store, local_python_config):
local_python_config['hooks'][0]['language_version'] = 'python2'
hook = _get_hook(local_python_config, store, 'python3-hook')
# language_version should have been adjusted to the interpreter version
assert hook.language_version != C.DEFAULT
ret, out = _hook_run(hook, ('filename',), color=False)
assert ret == 0
assert _norm_out(out) == b"2\n['filename']\nHello World\n"
def test_default_language_version(store, local_python_config):
config: Dict[str, Any] = {
config: dict[str, Any] = {
'default_language_version': {'python': 'fake'},
'default_stages': ['commit'],
'repos': [local_python_config],
@ -914,7 +920,7 @@ def test_default_language_version(store, local_python_config):
def test_default_stages(store, local_python_config):
config: Dict[str, Any] = {
config: dict[str, Any] = {
'default_language_version': {'python': C.DEFAULT},
'default_stages': ['commit'],
'repos': [local_python_config],

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import itertools
import os.path
import shutil

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
import sqlite3
import stat

View file

@ -1,3 +1,5 @@
from __future__ import annotations
import os.path
import stat
import subprocess

View file

@ -1,8 +1,9 @@
from __future__ import annotations
import concurrent.futures
import os
import sys
import time
from typing import Tuple
from unittest import mock
import pytest
@ -178,7 +179,7 @@ def test_thread_mapper_concurrency_uses_regular_map():
def test_xargs_propagate_kwargs_to_cmd():
env = {'PRE_COMMIT_TEST_VAR': 'Pre commit is awesome'}
cmd: Tuple[str, ...] = ('bash', '-c', 'echo $PRE_COMMIT_TEST_VAR', '--')
cmd: tuple[str, ...] = ('bash', '-c', 'echo $PRE_COMMIT_TEST_VAR', '--')
cmd = parse_shebang.normalize_cmd(cmd)
ret, stdout = xargs.xargs(cmd, ('1',), env=env)