1
0
Fork 0

Merging upstream version 2.16.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-09 21:31:47 +01:00
parent 2b79a68a34
commit ada93679f9
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
34 changed files with 301 additions and 126 deletions

2
.github/FUNDING.yml vendored
View file

@ -1,2 +0,0 @@
github: asottile
open_collective: pre-commit

41
.github/ISSUE_TEMPLATE/bug.yaml vendored Normal file
View file

@ -0,0 +1,41 @@
name: bug report
description: something went wrong
body:
- type: markdown
attributes:
value: |
this is for issues for `pre-commit` (the framework).
if you are reporting an issue for [pre-commit.ci] please report it at [pre-commit-ci/issues]
[pre-commit.ci]: https://pre-commit.ci
[pre-commit-ci/issues]: https://github.com/pre-commit-ci/issues
- type: textarea
id: freeform
attributes:
label: describe your issue
placeholder: 'I was doing ... I ran ... I expected ... I got ...'
validations:
required: true
- type: input
id: version
attributes:
label: pre-commit --version
placeholder: pre-commit x.x.x
validations:
required: true
- type: textarea
id: configuration
attributes:
label: .pre-commit-config.yaml
description: (auto-rendered as yaml, no need for backticks)
placeholder: 'repos: ...'
render: yaml
validations:
required: true
- type: textarea
id: error-log
attributes:
label: '~/.cache/pre-commit/pre-commit.log (if present)'
placeholder: "### version information\n..."
validations:
required: false

View file

@ -12,7 +12,7 @@ repos:
- id: requirements-txt-fixer
- id: double-quote-string-fixer
- repo: https://github.com/PyCQA/flake8
rev: 3.9.2
rev: 4.0.1
hooks:
- id: flake8
additional_dependencies: [flake8-typing-imports==1.10.0]
@ -21,11 +21,11 @@ repos:
hooks:
- id: autopep8
- repo: https://github.com/pre-commit/pre-commit
rev: v2.15.0
rev: v2.16.0
hooks:
- id: validate_manifest
- repo: https://github.com/asottile/pyupgrade
rev: v2.25.0
rev: v2.29.1
hooks:
- id: pyupgrade
args: [--py36-plus]
@ -35,16 +35,16 @@ repos:
- id: reorder-python-imports
args: [--py3-plus]
- repo: https://github.com/asottile/add-trailing-comma
rev: v2.1.0
rev: v2.2.1
hooks:
- id: add-trailing-comma
args: [--py36-plus]
- repo: https://github.com/asottile/setup-cfg-fmt
rev: v1.17.0
rev: v1.20.0
hooks:
- id: setup-cfg-fmt
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.910
rev: v0.910-1
hooks:
- id: mypy
additional_dependencies: [types-all]

View file

@ -1,3 +1,33 @@
2.16.0 - 2021-11-30
===================
### Features
- add warning for regexes containing `[\/]` or `[/\\]`.
- #2053 PR by @radek-sprta.
- #2043 issue by @asottile.
- move hook template back to `bash` resolving shebang-portability issues.
- #2065 PR by @asottile.
- add support for `fail_fast` at the individual hook level.
- #2097 PR by @colens3.
- #1143 issue by @potiuk.
- allow passthrough of `GIT_CONFIG_KEY_*`, `GIT_CONFIG_VALUE_*`, and
`GIT_CONFIG_COUNT`.
- #2136 PR by @emzeat.
### Fixes
- fix pre-commit autoupdate for `core.useBuiltinFSMonitor=true` on windows.
- #2047 PR by @asottile.
- #2046 issue by @lcnittl.
- fix temporary file stashing with for `submodule.recurse=1`.
- #2071 PR by @asottile.
- #2063 issue by @a666.
- ban broken importlib-resources versions.
- #2098 PR by @asottile.
- replace `exit(...)` with `raise SystemExit(...)` for portability.
- #2103 PR by @asottile.
- #2104 PR by @asottile.
2.15.0 - 2021-09-02
===================

View file

@ -2,4 +2,4 @@ from pre_commit.main import main
if __name__ == '__main__':
exit(main())
raise SystemExit(main())

View file

@ -70,6 +70,7 @@ MANIFEST_HOOK_DICT = cfgv.Map(
),
cfgv.Optional('args', cfgv.check_array(cfgv.check_string), []),
cfgv.Optional('always_run', cfgv.check_bool, False),
cfgv.Optional('fail_fast', cfgv.check_bool, False),
cfgv.Optional('pass_filenames', cfgv.check_bool, True),
cfgv.Optional('description', cfgv.check_string, ''),
cfgv.Optional('language_version', cfgv.check_string, C.DEFAULT),
@ -143,6 +144,18 @@ class OptionalSensibleRegexAtHook(cfgv.OptionalNoDefault):
f"regex, not a glob -- matching '/*' probably isn't what you "
f'want here',
)
if r'[\/]' in dct.get(self.key, ''):
logger.warning(
fr'pre-commit normalizes slashes in the {self.key!r} field '
fr'in hook {dct.get("id")!r} to forward slashes, so you '
fr'can use / instead of [\/]',
)
if r'[/\\]' in dct.get(self.key, ''):
logger.warning(
fr'pre-commit normalizes slashes in the {self.key!r} field '
fr'in hook {dct.get("id")!r} to forward slashes, so you '
fr'can use / instead of [/\\]',
)
class OptionalSensibleRegexAtTop(cfgv.OptionalNoDefault):
@ -154,6 +167,18 @@ class OptionalSensibleRegexAtTop(cfgv.OptionalNoDefault):
f'The top-level {self.key!r} field is a regex, not a glob -- '
f"matching '/*' probably isn't what you want here",
)
if r'[\/]' in dct.get(self.key, ''):
logger.warning(
fr'pre-commit normalizes the slashes in the top-level '
fr'{self.key!r} field to forward slashes, so you can use / '
fr'instead of [\/]',
)
if r'[/\\]' in dct.get(self.key, ''):
logger.warning(
fr'pre-commit normalizes the slashes in the top-level '
fr'{self.key!r} field to forward slashes, so you can use / '
fr'instead of [/\\]',
)
class MigrateShaToRev:

View file

@ -36,24 +36,36 @@ class RevInfo(NamedTuple):
return cls(config['repo'], config['rev'], None)
def update(self, tags_only: bool, freeze: bool) -> 'RevInfo':
git_cmd = ('git', *git.NO_FS_MONITOR)
if tags_only:
tag_cmd = ('git', 'describe', 'FETCH_HEAD', '--tags', '--abbrev=0')
tag_cmd = (
*git_cmd, 'describe',
'FETCH_HEAD', '--tags', '--abbrev=0',
)
else:
tag_cmd = ('git', 'describe', 'FETCH_HEAD', '--tags', '--exact')
tag_cmd = (
*git_cmd, 'describe',
'FETCH_HEAD', '--tags', '--exact',
)
with tmpdir() as tmp:
git.init_repo(tmp, self.repo)
cmd_output_b('git', 'fetch', 'origin', 'HEAD', '--tags', cwd=tmp)
cmd_output_b(
*git_cmd, 'fetch', 'origin', 'HEAD', '--tags',
cwd=tmp,
)
try:
rev = cmd_output(*tag_cmd, cwd=tmp)[1].strip()
except CalledProcessError:
cmd = ('git', 'rev-parse', 'FETCH_HEAD')
cmd = (*git_cmd, 'rev-parse', 'FETCH_HEAD')
rev = cmd_output(*cmd, cwd=tmp)[1].strip()
frozen = None
if freeze:
exact = cmd_output('git', 'rev-parse', rev, cwd=tmp)[1].strip()
exact_rev_cmd = (*git_cmd, 'rev-parse', rev)
exact = cmd_output(*exact_rev_cmd, cwd=tmp)[1].strip()
if exact != rev:
rev, frozen = exact, rev
return self._replace(rev=rev, frozen=frozen)

View file

@ -1,6 +1,7 @@
import itertools
import logging
import os.path
import shlex
import shutil
import sys
from typing import Optional
@ -100,19 +101,17 @@ def _install_hook_script(
args = ['hook-impl', f'--config={config_file}', f'--hook-type={hook_type}']
if skip_on_missing_config:
args.append('--skip-on-missing-config')
params = {'INSTALL_PYTHON': sys.executable, 'ARGS': args}
with open(hook_path, 'w') as hook_file:
contents = resource_text('hook-tmpl')
before, rest = contents.split(TEMPLATE_START)
to_template, after = rest.split(TEMPLATE_END)
before = before.replace('#!/usr/bin/env python3', shebang())
_, after = rest.split(TEMPLATE_END)
hook_file.write(before + TEMPLATE_START)
for line in to_template.splitlines():
var = line.split()[0]
hook_file.write(f'{var} = {params[var]!r}\n')
hook_file.write(f'INSTALL_PYTHON={shlex.quote(sys.executable)}\n')
# TODO: python3.8+: shlex.join
args_s = ' '.join(shlex.quote(part) for part in args)
hook_file.write(f'ARGS=({args_s})\n')
hook_file.write(TEMPLATE_END + after)
make_executable(hook_path)

View file

@ -290,7 +290,7 @@ def _run_hooks(
verbose=args.verbose, use_color=args.color,
)
retval |= current_retval
if retval and config['fail_fast']:
if retval and (config['fail_fast'] or hook.fail_fast):
break
if retval and args.show_diff_on_failure and prior_diff:
if args.all_files:

View file

@ -1,9 +1,9 @@
import sys
if sys.version_info < (3, 8): # pragma: no cover (<PY38)
import importlib_metadata
else: # pragma: no cover (PY38+)
if sys.version_info >= (3, 8): # pragma: >=3.8 cover
import importlib.metadata as importlib_metadata
else: # pragma: <3.8 cover
import importlib_metadata
CONFIG_FILE = '.pre-commit-config.yaml'
MANIFEST_FILE = '.pre-commit-hooks.yaml'

View file

@ -12,9 +12,11 @@ from pre_commit.util import CalledProcessError
from pre_commit.util import cmd_output
from pre_commit.util import cmd_output_b
logger = logging.getLogger(__name__)
# see #2046
NO_FS_MONITOR = ('-c', 'core.useBuiltinFSMonitor=false')
def zsplit(s: str) -> List[str]:
s = s.strip('\0')
@ -39,9 +41,10 @@ def no_git_env(
return {
k: v for k, v in _env.items()
if not k.startswith('GIT_') or
k.startswith(('GIT_CONFIG_KEY_', 'GIT_CONFIG_VALUE_')) or
k in {
'GIT_EXEC_PATH', 'GIT_SSH', 'GIT_SSH_COMMAND', 'GIT_SSL_CAINFO',
'GIT_SSL_NO_VERIFY',
'GIT_SSL_NO_VERIFY', 'GIT_CONFIG_COUNT',
}
}
@ -185,10 +188,11 @@ def init_repo(path: str, remote: str) -> None:
if os.path.isdir(remote):
remote = os.path.abspath(remote)
git = ('git', *NO_FS_MONITOR)
env = no_git_env()
# avoid the user's template so that hooks do not recurse
cmd_output_b('git', 'init', '--template=', path, env=env)
cmd_output_b('git', 'remote', 'add', 'origin', remote, cwd=path, env=env)
cmd_output_b(*git, 'init', '--template=', path, env=env)
cmd_output_b(*git, 'remote', 'add', 'origin', remote, cwd=path, env=env)
def commit(repo: str = '.') -> None:

View file

@ -27,6 +27,7 @@ class Hook(NamedTuple):
additional_dependencies: Sequence[str]
args: Sequence[str]
always_run: bool
fail_fast: bool
pass_filenames: bool
description: str
language_version: str

View file

@ -124,4 +124,4 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
if __name__ == '__main__':
exit(main())
raise SystemExit(main())

View file

@ -411,4 +411,4 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
if __name__ == '__main__':
exit(main())
raise SystemExit(main())

View file

@ -39,4 +39,4 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
if __name__ == '__main__':
exit(main())
raise SystemExit(main())

View file

@ -77,4 +77,4 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
if __name__ == '__main__':
exit(main())
raise SystemExit(main())

View file

@ -13,4 +13,4 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
if __name__ == '__main__':
exit(main())
raise SystemExit(main())

View file

@ -1,44 +1,20 @@
#!/usr/bin/env python3
#!/usr/bin/env bash
# File generated by pre-commit: https://pre-commit.com
# ID: 138fd403232d2ddd5efb44317e38bf03
import os
import sys
# we try our best, but the shebang of this script is difficult to determine:
# - macos doesn't ship with python3
# - windows executables are almost always `python.exe`
# therefore we continue to support python2 for this small script
if sys.version_info < (3, 3):
from distutils.spawn import find_executable as which
else:
from shutil import which
# work around https://github.com/Homebrew/homebrew-core/issues/30445
os.environ.pop('__PYVENV_LAUNCHER__', None)
# start templated
INSTALL_PYTHON = ''
ARGS = ['hook-impl']
INSTALL_PYTHON=''
ARGS=(hook-impl)
# end templated
ARGS.extend(('--hook-dir', os.path.realpath(os.path.dirname(__file__))))
ARGS.append('--')
ARGS.extend(sys.argv[1:])
DNE = '`pre-commit` not found. Did you forget to activate your virtualenv?'
if os.access(INSTALL_PYTHON, os.X_OK):
CMD = [INSTALL_PYTHON, '-mpre_commit']
elif which('pre-commit'):
CMD = ['pre-commit']
else:
raise SystemExit(DNE)
HERE="$(cd "$(dirname "$0")" && pwd)"
ARGS+=(--hook-dir "$HERE" -- "$@")
CMD.extend(ARGS)
if sys.platform == 'win32': # https://bugs.python.org/issue19124
import subprocess
if sys.version_info < (3, 7): # https://bugs.python.org/issue25942
raise SystemExit(subprocess.Popen(CMD).wait())
else:
raise SystemExit(subprocess.call(CMD))
else:
os.execvp(CMD[0], CMD)
if [ -x "$INSTALL_PYTHON" ]; then
exec "$INSTALL_PYTHON" -mpre_commit "${ARGS[@]}"
elif command -v pre-commit > /dev/null; then
exec pre-commit "${ARGS[@]}"
else
echo '`pre-commit` not found. Did you forget to activate your virtualenv?' 1>&2
exit 1
fi

View file

@ -13,6 +13,12 @@ from pre_commit.xargs import xargs
logger = logging.getLogger('pre_commit')
# without forcing submodule.recurse=0, changes in nested submodules will be
# discarded if `submodule.recurse=1` is configured
# we choose this instead of `--no-recurse-submodules` because it works on
# versions of git before that option was added to `git checkout`
_CHECKOUT_CMD = ('git', '-c', 'submodule.recurse=0', 'checkout', '--', '.')
def _git_apply(patch: str) -> None:
args = ('apply', '--whitespace=nowarn', patch)
@ -58,7 +64,7 @@ def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]:
# prevent recursive post-checkout hooks (#1418)
no_checkout_env = dict(os.environ, _PRE_COMMIT_SKIP_POST_CHECKOUT='1')
cmd_output_b('git', 'checkout', '--', '.', env=no_checkout_env)
cmd_output_b(*_CHECKOUT_CMD, env=no_checkout_env)
try:
yield
@ -74,7 +80,7 @@ def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]:
# We failed to apply the patch, presumably due to fixes made
# by hooks.
# Roll back the changes made by hooks.
cmd_output_b('git', 'checkout', '--', '.', env=no_checkout_env)
cmd_output_b(*_CHECKOUT_CMD, env=no_checkout_env)
_git_apply(patch_filename)
logger.info(f'Restored changes from {patch_filename}.')

View file

@ -21,10 +21,10 @@ import yaml
from pre_commit import parse_shebang
if sys.version_info >= (3, 7): # pragma: no cover (PY37+)
if sys.version_info >= (3, 7): # pragma: >=3.7 cover
from importlib.resources import open_binary
from importlib.resources import read_text
else: # pragma: no cover (<PY37)
else: # pragma: <3.7 cover
from importlib_resources import open_binary
from importlib_resources import read_text

View file

@ -1,4 +1,4 @@
covdefaults
covdefaults>=2.1
coverage
distlib
pytest

View file

@ -1,6 +1,6 @@
[metadata]
name = pre_commit
version = 2.15.0
version = 2.16.0
description = A framework for managing and maintaining multi-language pre-commit hooks.
long_description = file: README.md
long_description_content_type = text/markdown
@ -17,6 +17,7 @@ classifiers =
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: Implementation :: CPython
Programming Language :: Python :: Implementation :: PyPy
@ -30,7 +31,7 @@ install_requires =
toml
virtualenv>=20.0.8
importlib-metadata;python_version<"3.8"
importlib-resources;python_version<"3.7"
importlib-resources<5.3;python_version<"3.7"
python_requires = >=3.6.1
[options.packages.find]

View file

@ -25,4 +25,4 @@ def main() -> int:
if __name__ == '__main__':
exit(main())
raise SystemExit(main())

View file

@ -80,4 +80,4 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
if __name__ == '__main__':
exit(main())
raise SystemExit(main())

View file

@ -68,4 +68,4 @@ def main() -> int:
if __name__ == '__main__':
exit(main())
raise SystemExit(main())

View file

@ -106,4 +106,4 @@ def main() -> int:
if __name__ == '__main__':
exit(main())
raise SystemExit(main())

View file

@ -45,4 +45,4 @@ def main() -> int:
if __name__ == '__main__':
exit(main())
raise SystemExit(main())

View file

@ -247,38 +247,64 @@ def test_warn_mutable_rev_conditional():
cfgv.validate(config_obj, CONFIG_REPO_DICT)
def test_validate_optional_sensible_regex_at_hook_level(caplog):
config_obj = {
'id': 'flake8',
'files': 'dir/*.py',
}
cfgv.validate(config_obj, CONFIG_HOOK_DICT)
assert caplog.record_tuples == [
@pytest.mark.parametrize(
('regex', 'warning'),
(
(
'pre_commit',
logging.WARNING,
r'dir/*.py',
"The 'files' field in hook 'flake8' is a regex, not a glob -- "
"matching '/*' probably isn't what you want here",
),
]
def test_validate_optional_sensible_regex_at_top_level(caplog):
(
r'dir[\/].*\.py',
r"pre-commit normalizes slashes in the 'files' field in hook "
r"'flake8' to forward slashes, so you can use / instead of [\/]",
),
(
r'dir[/\\].*\.py',
r"pre-commit normalizes slashes in the 'files' field in hook "
r"'flake8' to forward slashes, so you can use / instead of [/\\]",
),
),
)
def test_validate_optional_sensible_regex_at_hook(caplog, regex, warning):
config_obj = {
'files': 'dir/*.py',
'id': 'flake8',
'files': regex,
}
cfgv.validate(config_obj, CONFIG_HOOK_DICT)
assert caplog.record_tuples == [('pre_commit', logging.WARNING, warning)]
@pytest.mark.parametrize(
('regex', 'warning'),
(
(
r'dir/*.py',
"The top-level 'files' field is a regex, not a glob -- "
"matching '/*' probably isn't what you want here",
),
(
r'dir[\/].*\.py',
r"pre-commit normalizes the slashes in the top-level 'files' "
r'field to forward slashes, so you can use / instead of [\/]',
),
(
r'dir[/\\].*\.py',
r"pre-commit normalizes the slashes in the top-level 'files' "
r'field to forward slashes, so you can use / instead of [/\\]',
),
),
)
def test_validate_optional_sensible_regex_at_top_level(caplog, regex, warning):
config_obj = {
'files': regex,
'repos': [],
}
cfgv.validate(config_obj, CONFIG_SCHEMA)
assert caplog.record_tuples == [
(
'pre_commit',
logging.WARNING,
"The top-level 'files' field is a regex, not a glob -- matching "
"'/*' probably isn't what you want here",
),
]
assert caplog.record_tuples == [('pre_commit', logging.WARNING, warning)]
@pytest.mark.parametrize('fn', (validate_config_main, validate_manifest_main))

View file

@ -5,6 +5,7 @@ import pytest
import yaml
import pre_commit.constants as C
from pre_commit import envcontext
from pre_commit import git
from pre_commit import util
from pre_commit.commands.autoupdate import _check_hooks_still_exist_at_rev
@ -176,6 +177,14 @@ def test_autoupdate_out_of_date_repo(out_of_date, tmpdir, store):
assert cfg.read() == fmt.format(out_of_date.path, out_of_date.head_rev)
def test_autoupdate_with_core_useBuiltinFSMonitor(out_of_date, tmpdir, store):
# force the setting on "globally" for git
home = tmpdir.join('fakehome').ensure_dir()
home.join('.gitconfig').write('[core]\nuseBuiltinFSMonitor = true\n')
with envcontext.envcontext((('HOME', str(home)),)):
test_autoupdate_out_of_date_repo(out_of_date, tmpdir, store)
def test_autoupdate_pure_yaml(out_of_date, tmpdir, store):
with mock.patch.object(util, 'Dumper', yaml.SafeDumper):
test_autoupdate_out_of_date_repo(out_of_date, tmpdir, store)

View file

@ -278,11 +278,7 @@ def test_environment_not_sourced(tempdir_factory, store):
hook = os.path.join(path, '.git/hooks/pre-commit')
with open(hook) as f:
src = f.read()
src = re.sub(
'\nINSTALL_PYTHON =.*\n',
'\nINSTALL_PYTHON = "/dne"\n',
src,
)
src = re.sub('\nINSTALL_PYTHON=.*\n', '\nINSTALL_PYTHON="/dne"\n', src)
with open(hook, 'w') as f:
f.write(src)

View file

@ -985,6 +985,18 @@ def test_fail_fast(cap_out, store, repo_with_failing_hook):
assert printed.count(b'Failing hook') == 1
def test_fail_fast_per_hook(cap_out, store, repo_with_failing_hook):
with modify_config() as config:
# More than one hook
config['repos'][0]['hooks'] *= 2
config['repos'][0]['hooks'][0]['fail_fast'] = True
stage_a_file()
ret, printed = _do_run(cap_out, store, repo_with_failing_hook, run_opts())
# it should have only run one hook
assert printed.count(b'Failing hook') == 1
def test_classifier_removes_dne():
classifier = Classifier(('this_file_does_not_exist',))
assert classifier.filenames == []

View file

@ -227,6 +227,11 @@ def test_no_git_env():
'GIT_SSH': '/usr/bin/ssh',
'GIT_SSH_COMMAND': 'ssh -o',
'GIT_DIR': '/none/shall/pass',
'GIT_CONFIG_KEY_0': 'user.name',
'GIT_CONFIG_VALUE_0': 'anthony',
'GIT_CONFIG_KEY_1': 'user.email',
'GIT_CONFIG_VALUE_1': 'asottile@example.com',
'GIT_CONFIG_COUNT': '2',
}
no_git_env = git.no_git_env(env)
assert no_git_env == {
@ -234,6 +239,11 @@ def test_no_git_env():
'GIT_EXEC_PATH': '/some/git/exec/path',
'GIT_SSH': '/usr/bin/ssh',
'GIT_SSH_COMMAND': 'ssh -o',
'GIT_CONFIG_KEY_0': 'user.name',
'GIT_CONFIG_VALUE_0': 'anthony',
'GIT_CONFIG_KEY_1': 'user.email',
'GIT_CONFIG_VALUE_1': 'asottile@example.com',
'GIT_CONFIG_COUNT': '2',
}

View file

@ -111,8 +111,8 @@ def test_local_conda_additional_dependencies(store):
'name': 'local-conda',
'entry': 'python',
'language': 'conda',
'args': ['-c', 'import tzdata; print("OK")'],
'additional_dependencies': ['python-tzdata'],
'args': ['-c', 'import botocore; print("OK")'],
'additional_dependencies': ['botocore'],
}],
}
hook = _get_hook(config, store, 'local-conda')
@ -164,7 +164,7 @@ def test_python_hook_weird_setup_cfg(in_git_dir, tempdir_factory, store):
)
def test_python_venv(tempdir_factory, store): # pragma: no cover (no venv)
def test_python_venv(tempdir_factory, store):
_test_hook_repo(
tempdir_factory, store, 'python_venv_hooks_repo',
'foo', [os.devnull],
@ -245,7 +245,6 @@ def test_run_a_docker_image_hook(tempdir_factory, store, hook_id):
)
@xfailif_windows # pragma: win32 no cover
def test_run_a_node_hook(tempdir_factory, store):
_test_hook_repo(
tempdir_factory, store, 'node_hooks_repo',
@ -253,7 +252,6 @@ 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
@ -263,7 +261,6 @@ 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',
@ -271,7 +268,6 @@ def test_run_versioned_node_hook(tempdir_factory, store):
)
@xfailif_windows # pragma: win32 no cover
def test_node_hook_with_npm_userconfig_set(tempdir_factory, store, tmpdir):
cfg = tmpdir.join('cfg')
cfg.write('cache=/dne\n')
@ -653,7 +649,6 @@ 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)
@ -1007,6 +1002,7 @@ def test_manifest_hooks(tempdir_factory, store):
types=['file'],
types_or=[],
verbose=False,
fail_fast=False,
)
@ -1025,13 +1021,13 @@ def test_local_perl_additional_dependencies(store):
'name': 'hello',
'entry': 'perltidy --version',
'language': 'perl',
'additional_dependencies': ['SHANCOCK/Perl-Tidy-20200110.tar.gz'],
'additional_dependencies': ['SHANCOCK/Perl-Tidy-20211029.tar.gz'],
}],
}
hook = _get_hook(config, store, 'hello')
ret, out = _hook_run(hook, (), color=False)
assert ret == 0
assert _norm_out(out).startswith(b'This is perltidy, v20200110')
assert _norm_out(out).startswith(b'This is perltidy, v20211029')
@pytest.mark.parametrize(

View file

@ -181,9 +181,11 @@ def test_img_conflict(img_staged, patch_dir):
@pytest.fixture
def submodule_with_commits(tempdir_factory):
def repo_with_commits(tempdir_factory):
path = git_dir(tempdir_factory)
with cwd(path):
open('foo', 'a+').close()
cmd_output('git', 'add', 'foo')
git_commit()
rev1 = cmd_output('git', 'rev-parse', 'HEAD')[1].strip()
git_commit()
@ -196,18 +198,21 @@ def checkout_submodule(rev):
@pytest.fixture
def sub_staged(submodule_with_commits, tempdir_factory):
def sub_staged(repo_with_commits, tempdir_factory):
path = git_dir(tempdir_factory)
with cwd(path):
open('bar', 'a+').close()
cmd_output('git', 'add', 'bar')
git_commit()
cmd_output(
'git', 'submodule', 'add', submodule_with_commits.path, 'sub',
'git', 'submodule', 'add', repo_with_commits.path, 'sub',
)
checkout_submodule(submodule_with_commits.rev1)
checkout_submodule(repo_with_commits.rev1)
cmd_output('git', 'add', 'sub')
yield auto_namedtuple(
path=path,
sub_path=os.path.join(path, 'sub'),
submodule=submodule_with_commits,
submodule=repo_with_commits,
)
@ -242,6 +247,34 @@ def test_sub_something_unstaged(sub_staged, patch_dir):
_test_sub_state(sub_staged, 'rev2', 'AM')
def test_submodule_does_not_discard_changes(sub_staged, patch_dir):
with open('bar', 'w') as f:
f.write('unstaged changes')
foo_path = os.path.join(sub_staged.sub_path, 'foo')
with open(foo_path, 'w') as f:
f.write('foo contents')
with staged_files_only(patch_dir):
with open('bar') as f:
assert f.read() == ''
with open(foo_path) as f:
assert f.read() == 'foo contents'
with open('bar') as f:
assert f.read() == 'unstaged changes'
with open(foo_path) as f:
assert f.read() == 'foo contents'
def test_submodule_does_not_discard_changes_recurse(sub_staged, patch_dir):
cmd_output('git', 'config', 'submodule.recurse', '1', cwd=sub_staged.path)
test_submodule_does_not_discard_changes(sub_staged, patch_dir)
def test_stage_utf8_changes(foo_staged, patch_dir):
contents = '\u2603'
with open('foo', 'w', encoding='UTF-8') as foo_file: