Merging upstream version 3.2.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
577069b57b
commit
bdf4a19272
23 changed files with 357 additions and 102 deletions
|
@ -30,7 +30,7 @@ repos:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: [--py38-plus]
|
args: [--py38-plus]
|
||||||
- repo: https://github.com/pre-commit/mirrors-autopep8
|
- repo: https://github.com/pre-commit/mirrors-autopep8
|
||||||
rev: v2.0.1
|
rev: v2.0.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: autopep8
|
- id: autopep8
|
||||||
- repo: https://github.com/PyCQA/flake8
|
- repo: https://github.com/PyCQA/flake8
|
||||||
|
@ -38,7 +38,7 @@ repos:
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: v1.0.1
|
rev: v1.1.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
additional_dependencies: [types-all]
|
additional_dependencies: [types-all]
|
||||||
|
|
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,3 +1,18 @@
|
||||||
|
3.2.0 - 2023-03-17
|
||||||
|
==================
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Allow `pre-commit`, `pre-push`, and `pre-merge-commit` as `stages`.
|
||||||
|
- #2732 issue by @asottile.
|
||||||
|
- #2808 PR by @asottile.
|
||||||
|
- Add `pre-rebase` hook support.
|
||||||
|
- #2582 issue by @BrutalSimplicity.
|
||||||
|
- #2725 PR by @mgaligniana.
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Remove bulky cargo cache from `language: rust` installs.
|
||||||
|
- #2820 PR by @asottile.
|
||||||
|
|
||||||
3.1.1 - 2023-02-27
|
3.1.1 - 2023-02-27
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import re
|
||||||
import shlex
|
import shlex
|
||||||
import sys
|
import sys
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
from typing import NamedTuple
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
|
||||||
import cfgv
|
import cfgv
|
||||||
|
@ -20,6 +21,21 @@ logger = logging.getLogger('pre_commit')
|
||||||
|
|
||||||
check_string_regex = cfgv.check_and(cfgv.check_string, cfgv.check_regex)
|
check_string_regex = cfgv.check_and(cfgv.check_string, cfgv.check_regex)
|
||||||
|
|
||||||
|
HOOK_TYPES = (
|
||||||
|
'commit-msg',
|
||||||
|
'post-checkout',
|
||||||
|
'post-commit',
|
||||||
|
'post-merge',
|
||||||
|
'post-rewrite',
|
||||||
|
'pre-commit',
|
||||||
|
'pre-merge-commit',
|
||||||
|
'pre-push',
|
||||||
|
'pre-rebase',
|
||||||
|
'prepare-commit-msg',
|
||||||
|
)
|
||||||
|
# `manual` is not invoked by any installed git hook. See #719
|
||||||
|
STAGES = (*HOOK_TYPES, 'manual')
|
||||||
|
|
||||||
|
|
||||||
def check_type_tag(tag: str) -> None:
|
def check_type_tag(tag: str) -> None:
|
||||||
if tag not in ALL_TAGS:
|
if tag not in ALL_TAGS:
|
||||||
|
@ -43,6 +59,46 @@ def check_min_version(version: str) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
_STAGES = {
|
||||||
|
'commit': 'pre-commit',
|
||||||
|
'merge-commit': 'pre-merge-commit',
|
||||||
|
'push': 'pre-push',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def transform_stage(stage: str) -> str:
|
||||||
|
return _STAGES.get(stage, stage)
|
||||||
|
|
||||||
|
|
||||||
|
class StagesMigrationNoDefault(NamedTuple):
|
||||||
|
key: str
|
||||||
|
default: Sequence[str]
|
||||||
|
|
||||||
|
def check(self, dct: dict[str, Any]) -> None:
|
||||||
|
if self.key not in dct:
|
||||||
|
return
|
||||||
|
|
||||||
|
val = dct[self.key]
|
||||||
|
cfgv.check_array(cfgv.check_any)(val)
|
||||||
|
|
||||||
|
val = [transform_stage(v) for v in val]
|
||||||
|
cfgv.check_array(cfgv.check_one_of(STAGES))(val)
|
||||||
|
|
||||||
|
def apply_default(self, dct: dict[str, Any]) -> None:
|
||||||
|
if self.key not in dct:
|
||||||
|
return
|
||||||
|
dct[self.key] = [transform_stage(v) for v in dct[self.key]]
|
||||||
|
|
||||||
|
def remove_default(self, dct: dict[str, Any]) -> None:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
class StagesMigration(StagesMigrationNoDefault):
|
||||||
|
def apply_default(self, dct: dict[str, Any]) -> None:
|
||||||
|
dct.setdefault(self.key, self.default)
|
||||||
|
super().apply_default(dct)
|
||||||
|
|
||||||
|
|
||||||
MANIFEST_HOOK_DICT = cfgv.Map(
|
MANIFEST_HOOK_DICT = cfgv.Map(
|
||||||
'Hook', 'id',
|
'Hook', 'id',
|
||||||
|
|
||||||
|
@ -70,7 +126,7 @@ MANIFEST_HOOK_DICT = cfgv.Map(
|
||||||
cfgv.Optional('log_file', cfgv.check_string, ''),
|
cfgv.Optional('log_file', cfgv.check_string, ''),
|
||||||
cfgv.Optional('minimum_pre_commit_version', cfgv.check_string, '0'),
|
cfgv.Optional('minimum_pre_commit_version', cfgv.check_string, '0'),
|
||||||
cfgv.Optional('require_serial', cfgv.check_bool, False),
|
cfgv.Optional('require_serial', cfgv.check_bool, False),
|
||||||
cfgv.Optional('stages', cfgv.check_array(cfgv.check_one_of(C.STAGES)), []),
|
StagesMigration('stages', []),
|
||||||
cfgv.Optional('verbose', cfgv.check_bool, False),
|
cfgv.Optional('verbose', cfgv.check_bool, False),
|
||||||
)
|
)
|
||||||
MANIFEST_SCHEMA = cfgv.Array(MANIFEST_HOOK_DICT)
|
MANIFEST_SCHEMA = cfgv.Array(MANIFEST_HOOK_DICT)
|
||||||
|
@ -241,7 +297,9 @@ CONFIG_HOOK_DICT = cfgv.Map(
|
||||||
cfgv.OptionalNoDefault(item.key, item.check_fn)
|
cfgv.OptionalNoDefault(item.key, item.check_fn)
|
||||||
for item in MANIFEST_HOOK_DICT.items
|
for item in MANIFEST_HOOK_DICT.items
|
||||||
if item.key != 'id'
|
if item.key != 'id'
|
||||||
|
if item.key != 'stages'
|
||||||
),
|
),
|
||||||
|
StagesMigrationNoDefault('stages', []),
|
||||||
OptionalSensibleRegexAtHook('files', cfgv.check_string),
|
OptionalSensibleRegexAtHook('files', cfgv.check_string),
|
||||||
OptionalSensibleRegexAtHook('exclude', cfgv.check_string),
|
OptionalSensibleRegexAtHook('exclude', cfgv.check_string),
|
||||||
)
|
)
|
||||||
|
@ -290,17 +348,13 @@ CONFIG_SCHEMA = cfgv.Map(
|
||||||
cfgv.RequiredRecurse('repos', cfgv.Array(CONFIG_REPO_DICT)),
|
cfgv.RequiredRecurse('repos', cfgv.Array(CONFIG_REPO_DICT)),
|
||||||
cfgv.Optional(
|
cfgv.Optional(
|
||||||
'default_install_hook_types',
|
'default_install_hook_types',
|
||||||
cfgv.check_array(cfgv.check_one_of(C.HOOK_TYPES)),
|
cfgv.check_array(cfgv.check_one_of(HOOK_TYPES)),
|
||||||
['pre-commit'],
|
['pre-commit'],
|
||||||
),
|
),
|
||||||
cfgv.OptionalRecurse(
|
cfgv.OptionalRecurse(
|
||||||
'default_language_version', DEFAULT_LANGUAGE_VERSION, {},
|
'default_language_version', DEFAULT_LANGUAGE_VERSION, {},
|
||||||
),
|
),
|
||||||
cfgv.Optional(
|
StagesMigration('default_stages', STAGES),
|
||||||
'default_stages',
|
|
||||||
cfgv.check_array(cfgv.check_one_of(C.STAGES)),
|
|
||||||
C.STAGES,
|
|
||||||
),
|
|
||||||
cfgv.Optional('files', check_string_regex, ''),
|
cfgv.Optional('files', check_string_regex, ''),
|
||||||
cfgv.Optional('exclude', check_string_regex, '^$'),
|
cfgv.Optional('exclude', check_string_regex, '^$'),
|
||||||
cfgv.Optional('fail_fast', cfgv.check_bool, False),
|
cfgv.Optional('fail_fast', cfgv.check_bool, False),
|
||||||
|
|
|
@ -73,6 +73,8 @@ def _ns(
|
||||||
local_branch: str | None = None,
|
local_branch: str | None = None,
|
||||||
from_ref: str | None = None,
|
from_ref: str | None = None,
|
||||||
to_ref: str | None = None,
|
to_ref: str | None = None,
|
||||||
|
pre_rebase_upstream: str | None = None,
|
||||||
|
pre_rebase_branch: str | None = None,
|
||||||
remote_name: str | None = None,
|
remote_name: str | None = None,
|
||||||
remote_url: str | None = None,
|
remote_url: str | None = None,
|
||||||
commit_msg_filename: str | None = None,
|
commit_msg_filename: str | None = None,
|
||||||
|
@ -84,11 +86,13 @@ def _ns(
|
||||||
) -> argparse.Namespace:
|
) -> argparse.Namespace:
|
||||||
return argparse.Namespace(
|
return argparse.Namespace(
|
||||||
color=color,
|
color=color,
|
||||||
hook_stage=hook_type.replace('pre-', ''),
|
hook_stage=hook_type,
|
||||||
remote_branch=remote_branch,
|
remote_branch=remote_branch,
|
||||||
local_branch=local_branch,
|
local_branch=local_branch,
|
||||||
from_ref=from_ref,
|
from_ref=from_ref,
|
||||||
to_ref=to_ref,
|
to_ref=to_ref,
|
||||||
|
pre_rebase_upstream=pre_rebase_upstream,
|
||||||
|
pre_rebase_branch=pre_rebase_branch,
|
||||||
remote_name=remote_name,
|
remote_name=remote_name,
|
||||||
remote_url=remote_url,
|
remote_url=remote_url,
|
||||||
commit_msg_filename=commit_msg_filename,
|
commit_msg_filename=commit_msg_filename,
|
||||||
|
@ -185,6 +189,12 @@ def _check_args_length(hook_type: str, args: Sequence[str]) -> None:
|
||||||
f'hook-impl for {hook_type} expected 1, 2, or 3 arguments '
|
f'hook-impl for {hook_type} expected 1, 2, or 3 arguments '
|
||||||
f'but got {len(args)}: {args}',
|
f'but got {len(args)}: {args}',
|
||||||
)
|
)
|
||||||
|
elif hook_type == 'pre-rebase':
|
||||||
|
if len(args) < 1 or len(args) > 2:
|
||||||
|
raise SystemExit(
|
||||||
|
f'hook-impl for {hook_type} expected 1 or 2 arguments '
|
||||||
|
f'but got {len(args)}: {args}',
|
||||||
|
)
|
||||||
elif hook_type in _EXPECTED_ARG_LENGTH_BY_HOOK:
|
elif hook_type in _EXPECTED_ARG_LENGTH_BY_HOOK:
|
||||||
expected = _EXPECTED_ARG_LENGTH_BY_HOOK[hook_type]
|
expected = _EXPECTED_ARG_LENGTH_BY_HOOK[hook_type]
|
||||||
if len(args) != expected:
|
if len(args) != expected:
|
||||||
|
@ -231,6 +241,13 @@ def _run_ns(
|
||||||
return _ns(hook_type, color, is_squash_merge=args[0])
|
return _ns(hook_type, color, is_squash_merge=args[0])
|
||||||
elif hook_type == 'post-rewrite':
|
elif hook_type == 'post-rewrite':
|
||||||
return _ns(hook_type, color, rewrite_command=args[0])
|
return _ns(hook_type, color, rewrite_command=args[0])
|
||||||
|
elif hook_type == 'pre-rebase' and len(args) == 1:
|
||||||
|
return _ns(hook_type, color, pre_rebase_upstream=args[0])
|
||||||
|
elif hook_type == 'pre-rebase' and len(args) == 2:
|
||||||
|
return _ns(
|
||||||
|
hook_type, color, pre_rebase_upstream=args[0],
|
||||||
|
pre_rebase_branch=args[1],
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise AssertionError(f'unexpected hook type: {hook_type}')
|
raise AssertionError(f'unexpected hook type: {hook_type}')
|
||||||
|
|
||||||
|
|
|
@ -254,6 +254,7 @@ def _all_filenames(args: argparse.Namespace) -> Collection[str]:
|
||||||
# these hooks do not operate on files
|
# these hooks do not operate on files
|
||||||
if args.hook_stage in {
|
if args.hook_stage in {
|
||||||
'post-checkout', 'post-commit', 'post-merge', 'post-rewrite',
|
'post-checkout', 'post-commit', 'post-merge', 'post-rewrite',
|
||||||
|
'pre-rebase',
|
||||||
}:
|
}:
|
||||||
return ()
|
return ()
|
||||||
elif args.hook_stage in {'prepare-commit-msg', 'commit-msg'}:
|
elif args.hook_stage in {'prepare-commit-msg', 'commit-msg'}:
|
||||||
|
@ -389,6 +390,10 @@ def run(
|
||||||
environ['PRE_COMMIT_FROM_REF'] = args.from_ref
|
environ['PRE_COMMIT_FROM_REF'] = args.from_ref
|
||||||
environ['PRE_COMMIT_TO_REF'] = args.to_ref
|
environ['PRE_COMMIT_TO_REF'] = args.to_ref
|
||||||
|
|
||||||
|
if args.pre_rebase_upstream and args.pre_rebase_branch:
|
||||||
|
environ['PRE_COMMIT_PRE_REBASE_UPSTREAM'] = args.pre_rebase_upstream
|
||||||
|
environ['PRE_COMMIT_PRE_REBASE_BRANCH'] = args.pre_rebase_branch
|
||||||
|
|
||||||
if (
|
if (
|
||||||
args.remote_name and args.remote_url and
|
args.remote_name and args.remote_url and
|
||||||
args.remote_branch and args.local_branch
|
args.remote_branch and args.local_branch
|
||||||
|
|
|
@ -10,17 +10,4 @@ LOCAL_REPO_VERSION = '1'
|
||||||
|
|
||||||
VERSION = importlib.metadata.version('pre_commit')
|
VERSION = importlib.metadata.version('pre_commit')
|
||||||
|
|
||||||
# `manual` is not invoked by any installed git hook. See #719
|
|
||||||
STAGES = (
|
|
||||||
'commit', 'merge-commit', 'prepare-commit-msg', 'commit-msg',
|
|
||||||
'post-commit', 'manual', 'post-checkout', 'push', 'post-merge',
|
|
||||||
'post-rewrite',
|
|
||||||
)
|
|
||||||
|
|
||||||
HOOK_TYPES = (
|
|
||||||
'pre-commit', 'pre-merge-commit', 'pre-push', 'prepare-commit-msg',
|
|
||||||
'commit-msg', 'post-commit', 'post-checkout', 'post-merge',
|
|
||||||
'post-rewrite',
|
|
||||||
)
|
|
||||||
|
|
||||||
DEFAULT = 'default'
|
DEFAULT = 'default'
|
||||||
|
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
|
||||||
|
@ -26,7 +27,7 @@ def get_env_patch(env: str) -> PatchesT:
|
||||||
# $CONDA_PREFIX/Scripts and $CONDA_PREFIX. Whereas the latter only
|
# $CONDA_PREFIX/Scripts and $CONDA_PREFIX. Whereas the latter only
|
||||||
# seems to be used for python.exe.
|
# seems to be used for python.exe.
|
||||||
path: SubstitutionT = (os.path.join(env, 'bin'), os.pathsep, Var('PATH'))
|
path: SubstitutionT = (os.path.join(env, 'bin'), os.pathsep, Var('PATH'))
|
||||||
if os.name == 'nt': # pragma: no cover (platform specific)
|
if sys.platform == 'win32': # pragma: win32 cover
|
||||||
path = (env, os.pathsep, *path)
|
path = (env, os.pathsep, *path)
|
||||||
path = (os.path.join(env, 'Scripts'), os.pathsep, *path)
|
path = (os.path.join(env, 'Scripts'), os.pathsep, *path)
|
||||||
path = (os.path.join(env, 'Library', 'bin'), os.pathsep, *path)
|
path = (os.path.join(env, 'Library', 'bin'), os.pathsep, *path)
|
||||||
|
|
|
@ -48,7 +48,7 @@ def _read_pyvenv_cfg(filename: str) -> dict[str, str]:
|
||||||
|
|
||||||
def bin_dir(venv: str) -> str:
|
def bin_dir(venv: str) -> str:
|
||||||
"""On windows there's a different directory for the virtualenv"""
|
"""On windows there's a different directory for the virtualenv"""
|
||||||
bin_part = 'Scripts' if os.name == 'nt' else 'bin'
|
bin_part = 'Scripts' if sys.platform == 'win32' else 'bin'
|
||||||
return os.path.join(venv, bin_part)
|
return os.path.join(venv, bin_part)
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ def norm_version(version: str) -> str | None:
|
||||||
elif _sys_executable_matches(version): # virtualenv defaults to our exe
|
elif _sys_executable_matches(version): # virtualenv defaults to our exe
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if os.name == 'nt': # pragma: no cover (windows)
|
if sys.platform == 'win32': # pragma: no cover (windows)
|
||||||
version_exec = _find_by_py_launcher(version)
|
version_exec = _find_by_py_launcher(version)
|
||||||
if version_exec:
|
if version_exec:
|
||||||
return version_exec
|
return version_exec
|
||||||
|
|
|
@ -50,7 +50,6 @@ def _rust_toolchain(language_version: str) -> str:
|
||||||
|
|
||||||
def get_env_patch(target_dir: str, version: str) -> PatchesT:
|
def get_env_patch(target_dir: str, version: str) -> PatchesT:
|
||||||
return (
|
return (
|
||||||
('CARGO_HOME', target_dir),
|
|
||||||
('PATH', (os.path.join(target_dir, 'bin'), os.pathsep, Var('PATH'))),
|
('PATH', (os.path.join(target_dir, 'bin'), os.pathsep, Var('PATH'))),
|
||||||
# Only set RUSTUP_TOOLCHAIN if we don't want use the system's default
|
# Only set RUSTUP_TOOLCHAIN if we don't want use the system's default
|
||||||
# toolchain
|
# toolchain
|
||||||
|
|
|
@ -7,6 +7,7 @@ import sys
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
|
from pre_commit import clientlib
|
||||||
from pre_commit import git
|
from pre_commit import git
|
||||||
from pre_commit.color import add_color_option
|
from pre_commit.color import add_color_option
|
||||||
from pre_commit.commands.autoupdate import autoupdate
|
from pre_commit.commands.autoupdate import autoupdate
|
||||||
|
@ -52,7 +53,7 @@ def _add_config_option(parser: argparse.ArgumentParser) -> None:
|
||||||
def _add_hook_type_option(parser: argparse.ArgumentParser) -> None:
|
def _add_hook_type_option(parser: argparse.ArgumentParser) -> None:
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-t', '--hook-type',
|
'-t', '--hook-type',
|
||||||
choices=C.HOOK_TYPES, action='append', dest='hook_types',
|
choices=clientlib.HOOK_TYPES, action='append', dest='hook_types',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,7 +74,10 @@ def _add_run_options(parser: argparse.ArgumentParser) -> None:
|
||||||
help='When hooks fail, run `git diff` directly afterward.',
|
help='When hooks fail, run `git diff` directly afterward.',
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--hook-stage', choices=C.STAGES, default='commit',
|
'--hook-stage',
|
||||||
|
choices=clientlib.STAGES,
|
||||||
|
type=clientlib.transform_stage,
|
||||||
|
default='pre-commit',
|
||||||
help='The stage during which the hook is fired. One of %(choices)s',
|
help='The stage during which the hook is fired. One of %(choices)s',
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
@ -103,6 +107,17 @@ def _add_run_options(parser: argparse.ArgumentParser) -> None:
|
||||||
'now checked out.'
|
'now checked out.'
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--pre-rebase-upstream', help=(
|
||||||
|
'The upstream from which the series was forked.'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--pre-rebase-branch', help=(
|
||||||
|
'The branch being rebased, and is not set when '
|
||||||
|
'rebasing the current branch.'
|
||||||
|
),
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--commit-msg-filename',
|
'--commit-msg-filename',
|
||||||
help='Filename to check when running during `commit-msg`',
|
help='Filename to check when running during `commit-msg`',
|
||||||
|
|
|
@ -119,7 +119,7 @@ def cmd_output(*cmd: str, **kwargs: Any) -> tuple[int, str, str | None]:
|
||||||
return returncode, stdout, stderr
|
return returncode, stdout, stderr
|
||||||
|
|
||||||
|
|
||||||
if os.name != 'nt': # pragma: win32 no cover
|
if sys.platform != 'win32': # pragma: win32 no cover
|
||||||
from os import openpty
|
from os import openpty
|
||||||
import termios
|
import termios
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[metadata]
|
[metadata]
|
||||||
name = pre_commit
|
name = pre_commit
|
||||||
version = 3.1.1
|
version = 3.2.0
|
||||||
description = A framework for managing and maintaining multi-language pre-commit hooks.
|
description = A framework for managing and maintaining multi-language pre-commit hooks.
|
||||||
long_description = file: README.md
|
long_description = file: README.md
|
||||||
long_description_content_type = text/markdown
|
long_description_content_type = text/markdown
|
||||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
||||||
import contextlib
|
import contextlib
|
||||||
import os.path
|
import os.path
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ def cmd_output_mocked_pre_commit_home(
|
||||||
return ret, out.replace('\r\n', '\n'), None
|
return ret, out.replace('\r\n', '\n'), None
|
||||||
|
|
||||||
|
|
||||||
xfailif_windows = pytest.mark.xfail(os.name == 'nt', reason='windows')
|
xfailif_windows = pytest.mark.xfail(sys.platform == 'win32', reason='windows')
|
||||||
|
|
||||||
|
|
||||||
def run_opts(
|
def run_opts(
|
||||||
|
@ -43,9 +44,11 @@ def run_opts(
|
||||||
local_branch='',
|
local_branch='',
|
||||||
from_ref='',
|
from_ref='',
|
||||||
to_ref='',
|
to_ref='',
|
||||||
|
pre_rebase_upstream='',
|
||||||
|
pre_rebase_branch='',
|
||||||
remote_name='',
|
remote_name='',
|
||||||
remote_url='',
|
remote_url='',
|
||||||
hook_stage='commit',
|
hook_stage='pre-commit',
|
||||||
show_diff_on_failure=False,
|
show_diff_on_failure=False,
|
||||||
commit_msg_filename='',
|
commit_msg_filename='',
|
||||||
prepare_commit_message_source='',
|
prepare_commit_message_source='',
|
||||||
|
@ -66,6 +69,8 @@ def run_opts(
|
||||||
local_branch=local_branch,
|
local_branch=local_branch,
|
||||||
from_ref=from_ref,
|
from_ref=from_ref,
|
||||||
to_ref=to_ref,
|
to_ref=to_ref,
|
||||||
|
pre_rebase_upstream=pre_rebase_upstream,
|
||||||
|
pre_rebase_branch=pre_rebase_branch,
|
||||||
remote_name=remote_name,
|
remote_name=remote_name,
|
||||||
remote_url=remote_url,
|
remote_url=remote_url,
|
||||||
hook_stage=hook_stage,
|
hook_stage=hook_stage,
|
||||||
|
|
|
@ -12,6 +12,7 @@ from pre_commit.clientlib import CONFIG_HOOK_DICT
|
||||||
from pre_commit.clientlib import CONFIG_REPO_DICT
|
from pre_commit.clientlib import CONFIG_REPO_DICT
|
||||||
from pre_commit.clientlib import CONFIG_SCHEMA
|
from pre_commit.clientlib import CONFIG_SCHEMA
|
||||||
from pre_commit.clientlib import DEFAULT_LANGUAGE_VERSION
|
from pre_commit.clientlib import DEFAULT_LANGUAGE_VERSION
|
||||||
|
from pre_commit.clientlib import MANIFEST_HOOK_DICT
|
||||||
from pre_commit.clientlib import MANIFEST_SCHEMA
|
from pre_commit.clientlib import MANIFEST_SCHEMA
|
||||||
from pre_commit.clientlib import META_HOOK_DICT
|
from pre_commit.clientlib import META_HOOK_DICT
|
||||||
from pre_commit.clientlib import OptionalSensibleRegexAtHook
|
from pre_commit.clientlib import OptionalSensibleRegexAtHook
|
||||||
|
@ -416,3 +417,50 @@ def test_warn_additional(schema):
|
||||||
x for x in schema.items if isinstance(x, cfgv.WarnAdditionalKeys)
|
x for x in schema.items if isinstance(x, cfgv.WarnAdditionalKeys)
|
||||||
)
|
)
|
||||||
assert allowed_keys == set(warn_additional.keys)
|
assert allowed_keys == set(warn_additional.keys)
|
||||||
|
|
||||||
|
|
||||||
|
def test_stages_migration_for_default_stages():
|
||||||
|
cfg = {
|
||||||
|
'default_stages': ['commit-msg', 'push', 'commit', 'merge-commit'],
|
||||||
|
'repos': [],
|
||||||
|
}
|
||||||
|
cfgv.validate(cfg, CONFIG_SCHEMA)
|
||||||
|
cfg = cfgv.apply_defaults(cfg, CONFIG_SCHEMA)
|
||||||
|
assert cfg['default_stages'] == [
|
||||||
|
'commit-msg', 'pre-push', 'pre-commit', 'pre-merge-commit',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_manifest_stages_defaulting():
|
||||||
|
dct = {
|
||||||
|
'id': 'fake-hook',
|
||||||
|
'name': 'fake-hook',
|
||||||
|
'entry': 'fake-hook',
|
||||||
|
'language': 'system',
|
||||||
|
'stages': ['commit-msg', 'push', 'commit', 'merge-commit'],
|
||||||
|
}
|
||||||
|
cfgv.validate(dct, MANIFEST_HOOK_DICT)
|
||||||
|
dct = cfgv.apply_defaults(dct, MANIFEST_HOOK_DICT)
|
||||||
|
assert dct['stages'] == [
|
||||||
|
'commit-msg', 'pre-push', 'pre-commit', 'pre-merge-commit',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_config_hook_stages_defaulting_missing():
|
||||||
|
dct = {'id': 'fake-hook'}
|
||||||
|
cfgv.validate(dct, CONFIG_HOOK_DICT)
|
||||||
|
dct = cfgv.apply_defaults(dct, CONFIG_HOOK_DICT)
|
||||||
|
assert dct == {'id': 'fake-hook'}
|
||||||
|
|
||||||
|
|
||||||
|
def test_config_hook_stages_defaulting():
|
||||||
|
dct = {
|
||||||
|
'id': 'fake-hook',
|
||||||
|
'stages': ['commit-msg', 'push', 'commit', 'merge-commit'],
|
||||||
|
}
|
||||||
|
cfgv.validate(dct, CONFIG_HOOK_DICT)
|
||||||
|
dct = cfgv.apply_defaults(dct, CONFIG_HOOK_DICT)
|
||||||
|
assert dct == {
|
||||||
|
'id': 'fake-hook',
|
||||||
|
'stages': ['commit-msg', 'pre-push', 'pre-commit', 'pre-merge-commit'],
|
||||||
|
}
|
||||||
|
|
|
@ -100,6 +100,8 @@ def test_run_legacy_recursive(tmpdir):
|
||||||
('commit-msg', ['.git/COMMIT_EDITMSG']),
|
('commit-msg', ['.git/COMMIT_EDITMSG']),
|
||||||
('post-commit', []),
|
('post-commit', []),
|
||||||
('post-merge', ['1']),
|
('post-merge', ['1']),
|
||||||
|
('pre-rebase', ['main', 'topic']),
|
||||||
|
('pre-rebase', ['main']),
|
||||||
('post-checkout', ['old_head', 'new_head', '1']),
|
('post-checkout', ['old_head', 'new_head', '1']),
|
||||||
('post-rewrite', ['amend']),
|
('post-rewrite', ['amend']),
|
||||||
# multiple choices for commit-editmsg
|
# multiple choices for commit-editmsg
|
||||||
|
@ -139,13 +141,36 @@ def test_check_args_length_prepare_commit_msg_error():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_check_args_length_pre_rebase_error():
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
hook_impl._check_args_length('pre-rebase', [])
|
||||||
|
msg, = excinfo.value.args
|
||||||
|
assert msg == 'hook-impl for pre-rebase expected 1 or 2 arguments but got 0: []' # noqa: E501
|
||||||
|
|
||||||
|
|
||||||
def test_run_ns_pre_commit():
|
def test_run_ns_pre_commit():
|
||||||
ns = hook_impl._run_ns('pre-commit', True, (), b'')
|
ns = hook_impl._run_ns('pre-commit', True, (), b'')
|
||||||
assert ns is not None
|
assert ns is not None
|
||||||
assert ns.hook_stage == 'commit'
|
assert ns.hook_stage == 'pre-commit'
|
||||||
assert ns.color is True
|
assert ns.color is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_run_ns_pre_rebase():
|
||||||
|
ns = hook_impl._run_ns('pre-rebase', True, ('main', 'topic'), b'')
|
||||||
|
assert ns is not None
|
||||||
|
assert ns.hook_stage == 'pre-rebase'
|
||||||
|
assert ns.color is True
|
||||||
|
assert ns.pre_rebase_upstream == 'main'
|
||||||
|
assert ns.pre_rebase_branch == 'topic'
|
||||||
|
|
||||||
|
ns = hook_impl._run_ns('pre-rebase', True, ('main',), b'')
|
||||||
|
assert ns is not None
|
||||||
|
assert ns.hook_stage == 'pre-rebase'
|
||||||
|
assert ns.color is True
|
||||||
|
assert ns.pre_rebase_upstream == 'main'
|
||||||
|
assert ns.pre_rebase_branch is None
|
||||||
|
|
||||||
|
|
||||||
def test_run_ns_commit_msg():
|
def test_run_ns_commit_msg():
|
||||||
ns = hook_impl._run_ns('commit-msg', False, ('.git/COMMIT_MSG',), b'')
|
ns = hook_impl._run_ns('commit-msg', False, ('.git/COMMIT_MSG',), b'')
|
||||||
assert ns is not None
|
assert ns is not None
|
||||||
|
@ -245,7 +270,7 @@ def test_run_ns_pre_push_updating_branch(push_example):
|
||||||
ns = hook_impl._run_ns('pre-push', False, args, stdin)
|
ns = hook_impl._run_ns('pre-push', False, args, stdin)
|
||||||
|
|
||||||
assert ns is not None
|
assert ns is not None
|
||||||
assert ns.hook_stage == 'push'
|
assert ns.hook_stage == 'pre-push'
|
||||||
assert ns.color is False
|
assert ns.color is False
|
||||||
assert ns.remote_name == 'origin'
|
assert ns.remote_name == 'origin'
|
||||||
assert ns.remote_url == src
|
assert ns.remote_url == src
|
||||||
|
|
|
@ -810,6 +810,46 @@ def test_post_merge_integration(tempdir_factory, store):
|
||||||
assert os.path.exists('post-merge.tmp')
|
assert os.path.exists('post-merge.tmp')
|
||||||
|
|
||||||
|
|
||||||
|
def test_pre_rebase_integration(tempdir_factory, store):
|
||||||
|
path = git_dir(tempdir_factory)
|
||||||
|
config = {
|
||||||
|
'repos': [
|
||||||
|
{
|
||||||
|
'repo': 'local',
|
||||||
|
'hooks': [{
|
||||||
|
'id': 'pre-rebase',
|
||||||
|
'name': 'Pre rebase',
|
||||||
|
'entry': 'touch pre-rebase.tmp',
|
||||||
|
'language': 'system',
|
||||||
|
'always_run': True,
|
||||||
|
'verbose': True,
|
||||||
|
'stages': ['pre-rebase'],
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
write_config(path, config)
|
||||||
|
with cwd(path):
|
||||||
|
install(C.CONFIG_FILE, store, hook_types=['pre-rebase'])
|
||||||
|
open('foo', 'a').close()
|
||||||
|
cmd_output('git', 'add', '.')
|
||||||
|
git_commit()
|
||||||
|
|
||||||
|
cmd_output('git', 'checkout', '-b', 'branch')
|
||||||
|
open('bar', 'a').close()
|
||||||
|
cmd_output('git', 'add', '.')
|
||||||
|
git_commit()
|
||||||
|
|
||||||
|
cmd_output('git', 'checkout', 'master')
|
||||||
|
open('baz', 'a').close()
|
||||||
|
cmd_output('git', 'add', '.')
|
||||||
|
git_commit()
|
||||||
|
|
||||||
|
cmd_output('git', 'checkout', 'branch')
|
||||||
|
cmd_output('git', 'rebase', 'master', 'branch')
|
||||||
|
assert os.path.exists('pre-rebase.tmp')
|
||||||
|
|
||||||
|
|
||||||
def test_post_rewrite_integration(tempdir_factory, store):
|
def test_post_rewrite_integration(tempdir_factory, store):
|
||||||
path = git_dir(tempdir_factory)
|
path = git_dir(tempdir_factory)
|
||||||
config = {
|
config = {
|
||||||
|
|
|
@ -354,13 +354,13 @@ def test_show_diff_on_failure(
|
||||||
({'hook': 'bash_hook'}, (b'Bash hook', b'Passed'), 0, True),
|
({'hook': 'bash_hook'}, (b'Bash hook', b'Passed'), 0, True),
|
||||||
(
|
(
|
||||||
{'hook': 'nope'},
|
{'hook': 'nope'},
|
||||||
(b'No hook with id `nope` in stage `commit`',),
|
(b'No hook with id `nope` in stage `pre-commit`',),
|
||||||
1,
|
1,
|
||||||
True,
|
True,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
{'hook': 'nope', 'hook_stage': 'push'},
|
{'hook': 'nope', 'hook_stage': 'pre-push'},
|
||||||
(b'No hook with id `nope` in stage `push`',),
|
(b'No hook with id `nope` in stage `pre-push`',),
|
||||||
1,
|
1,
|
||||||
True,
|
True,
|
||||||
),
|
),
|
||||||
|
@ -563,6 +563,16 @@ def test_merge_conflict_resolved(cap_out, store, in_merge_conflict):
|
||||||
assert msg in printed
|
assert msg in printed
|
||||||
|
|
||||||
|
|
||||||
|
def test_rebase(cap_out, store, repo_with_passing_hook):
|
||||||
|
args = run_opts(pre_rebase_upstream='master', pre_rebase_branch='topic')
|
||||||
|
environ: MutableMapping[str, str] = {}
|
||||||
|
ret, printed = _do_run(
|
||||||
|
cap_out, store, repo_with_passing_hook, args, environ,
|
||||||
|
)
|
||||||
|
assert environ['PRE_COMMIT_PRE_REBASE_UPSTREAM'] == 'master'
|
||||||
|
assert environ['PRE_COMMIT_PRE_REBASE_BRANCH'] == 'topic'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
('hooks', 'expected'),
|
('hooks', 'expected'),
|
||||||
(
|
(
|
||||||
|
@ -818,7 +828,7 @@ def test_stages(cap_out, store, repo_with_passing_hook):
|
||||||
'language': 'pygrep',
|
'language': 'pygrep',
|
||||||
'stages': [stage],
|
'stages': [stage],
|
||||||
}
|
}
|
||||||
for i, stage in enumerate(('commit', 'push', 'manual'), 1)
|
for i, stage in enumerate(('pre-commit', 'pre-push', 'manual'), 1)
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
add_config_to_repo(repo_with_passing_hook, config)
|
add_config_to_repo(repo_with_passing_hook, config)
|
||||||
|
@ -833,8 +843,8 @@ def test_stages(cap_out, store, repo_with_passing_hook):
|
||||||
assert printed.count(b'hook ') == 1
|
assert printed.count(b'hook ') == 1
|
||||||
return printed
|
return printed
|
||||||
|
|
||||||
assert _run_for_stage('commit').startswith(b'hook 1...')
|
assert _run_for_stage('pre-commit').startswith(b'hook 1...')
|
||||||
assert _run_for_stage('push').startswith(b'hook 2...')
|
assert _run_for_stage('pre-push').startswith(b'hook 2...')
|
||||||
assert _run_for_stage('manual').startswith(b'hook 3...')
|
assert _run_for_stage('manual').startswith(b'hook 3...')
|
||||||
|
|
||||||
|
|
||||||
|
@ -1173,7 +1183,7 @@ def test_args_hook_only(cap_out, store, repo_with_passing_hook):
|
||||||
),
|
),
|
||||||
'language': 'system',
|
'language': 'system',
|
||||||
'files': r'\.py$',
|
'files': r'\.py$',
|
||||||
'stages': ['commit'],
|
'stages': ['pre-commit'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id': 'do_not_commit',
|
'id': 'do_not_commit',
|
||||||
|
|
|
@ -36,10 +36,10 @@ def test_read_pyvenv_cfg_non_utf8(tmpdir):
|
||||||
|
|
||||||
def test_norm_version_expanduser():
|
def test_norm_version_expanduser():
|
||||||
home = os.path.expanduser('~')
|
home = os.path.expanduser('~')
|
||||||
if os.name == 'nt': # pragma: nt cover
|
if sys.platform == 'win32': # pragma: win32 cover
|
||||||
path = r'~\python343'
|
path = r'~\python343'
|
||||||
expected_path = fr'{home}\python343'
|
expected_path = fr'{home}\python343'
|
||||||
else: # pragma: nt no cover
|
else: # pragma: win32 no cover
|
||||||
path = '~/.pyenv/versions/3.4.3/bin/python'
|
path = '~/.pyenv/versions/3.4.3/bin/python'
|
||||||
expected_path = f'{home}/.pyenv/versions/3.4.3/bin/python'
|
expected_path = f'{home}/.pyenv/versions/3.4.3/bin/python'
|
||||||
result = python.norm_version(path)
|
result = python.norm_version(path)
|
||||||
|
@ -233,3 +233,54 @@ setup(
|
||||||
return_value=False,
|
return_value=False,
|
||||||
):
|
):
|
||||||
assert run_language(tmp_path, python, 'myexe') == (0, b'ohai\n')
|
assert run_language(tmp_path, python, 'myexe') == (0, b'ohai\n')
|
||||||
|
|
||||||
|
|
||||||
|
def _make_hello_hello(tmp_path):
|
||||||
|
setup_py = '''\
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='socks',
|
||||||
|
version='0.0.0',
|
||||||
|
py_modules=['socks'],
|
||||||
|
entry_points={'console_scripts': ['socks = socks:main']},
|
||||||
|
)
|
||||||
|
'''
|
||||||
|
|
||||||
|
main_py = '''\
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print(repr(sys.argv[1:]))
|
||||||
|
print('hello hello')
|
||||||
|
return 0
|
||||||
|
'''
|
||||||
|
tmp_path.joinpath('setup.py').write_text(setup_py)
|
||||||
|
tmp_path.joinpath('socks.py').write_text(main_py)
|
||||||
|
|
||||||
|
|
||||||
|
def test_simple_python_hook(tmp_path):
|
||||||
|
_make_hello_hello(tmp_path)
|
||||||
|
|
||||||
|
ret = run_language(tmp_path, python, 'socks', [os.devnull])
|
||||||
|
assert ret == (0, f'[{os.devnull!r}]\nhello hello\n'.encode())
|
||||||
|
|
||||||
|
|
||||||
|
def test_simple_python_hook_default_version(tmp_path):
|
||||||
|
# make sure that this continues to work for platforms where default
|
||||||
|
# language detection does not work
|
||||||
|
with mock.patch.object(
|
||||||
|
python,
|
||||||
|
'get_default_version',
|
||||||
|
return_value=C.DEFAULT,
|
||||||
|
):
|
||||||
|
test_simple_python_hook(tmp_path)
|
||||||
|
|
||||||
|
|
||||||
|
def test_python_hook_weird_setup_cfg(tmp_path):
|
||||||
|
_make_hello_hello(tmp_path)
|
||||||
|
setup_cfg = '[install]\ninstall_scripts=/usr/sbin'
|
||||||
|
tmp_path.joinpath('setup.cfg').write_text(setup_cfg)
|
||||||
|
|
||||||
|
ret = run_language(tmp_path, python, 'socks', [os.devnull])
|
||||||
|
assert ret == (0, f'[{os.devnull!r}]\nhello hello\n'.encode())
|
||||||
|
|
|
@ -216,3 +216,9 @@ def test_expected_fatal_error_no_git_repo(in_tmpdir, cap_out, mock_store_dir):
|
||||||
'Is it installed, and are you in a Git repository directory?'
|
'Is it installed, and are you in a Git repository directory?'
|
||||||
)
|
)
|
||||||
assert cap_out_lines[-1] == f'Check the log at {log_file}'
|
assert cap_out_lines[-1] == f'Check the log at {log_file}'
|
||||||
|
|
||||||
|
|
||||||
|
def test_hook_stage_migration(mock_store_dir):
|
||||||
|
with mock.patch.object(main, 'run') as mck:
|
||||||
|
main.main(('run', '--hook-stage', 'commit'))
|
||||||
|
assert mck.call_args[0][2].hook_stage == 'pre-commit'
|
||||||
|
|
|
@ -94,7 +94,7 @@ def test_normexe_does_not_exist_sep():
|
||||||
assert excinfo.value.args == ('Executable `./i-dont-exist-lol` not found',)
|
assert excinfo.value.args == ('Executable `./i-dont-exist-lol` not found',)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail(os.name == 'nt', reason='posix only')
|
@pytest.mark.xfail(sys.platform == 'win32', reason='posix only')
|
||||||
def test_normexe_not_executable(tmpdir): # pragma: win32 no cover
|
def test_normexe_not_executable(tmpdir): # pragma: win32 no cover
|
||||||
tmpdir.join('exe').ensure()
|
tmpdir.join('exe').ensure()
|
||||||
with tmpdir.as_cwd(), pytest.raises(OSError) as excinfo:
|
with tmpdir.as_cwd(), pytest.raises(OSError) as excinfo:
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
import shlex
|
||||||
import shutil
|
import shutil
|
||||||
|
import sys
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
@ -16,6 +18,7 @@ from pre_commit.clientlib import CONFIG_SCHEMA
|
||||||
from pre_commit.clientlib import load_manifest
|
from pre_commit.clientlib import load_manifest
|
||||||
from pre_commit.hook import Hook
|
from pre_commit.hook import Hook
|
||||||
from pre_commit.languages import python
|
from pre_commit.languages import python
|
||||||
|
from pre_commit.languages import system
|
||||||
from pre_commit.prefix import Prefix
|
from pre_commit.prefix import Prefix
|
||||||
from pre_commit.repository import _hook_installed
|
from pre_commit.repository import _hook_installed
|
||||||
from pre_commit.repository import all_hooks
|
from pre_commit.repository import all_hooks
|
||||||
|
@ -79,51 +82,6 @@ def _test_hook_repo(
|
||||||
assert out == expected
|
assert out == expected
|
||||||
|
|
||||||
|
|
||||||
def test_python_hook(tempdir_factory, store):
|
|
||||||
_test_hook_repo(
|
|
||||||
tempdir_factory, store, 'python_hooks_repo',
|
|
||||||
'foo', [os.devnull],
|
|
||||||
f'[{os.devnull!r}]\nHello World\n'.encode(),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_python_hook_default_version(tempdir_factory, store):
|
|
||||||
# make sure that this continues to work for platforms where default
|
|
||||||
# language detection does not work
|
|
||||||
with mock.patch.object(
|
|
||||||
python,
|
|
||||||
'get_default_version',
|
|
||||||
return_value=C.DEFAULT,
|
|
||||||
):
|
|
||||||
test_python_hook(tempdir_factory, store)
|
|
||||||
|
|
||||||
|
|
||||||
def test_python_hook_args_with_spaces(tempdir_factory, store):
|
|
||||||
_test_hook_repo(
|
|
||||||
tempdir_factory, store, 'python_hooks_repo',
|
|
||||||
'foo',
|
|
||||||
[],
|
|
||||||
b"['i have spaces', 'and\"\\'quotes', '$and !this']\n"
|
|
||||||
b'Hello World\n',
|
|
||||||
config_kwargs={
|
|
||||||
'hooks': [{
|
|
||||||
'id': 'foo',
|
|
||||||
'args': ['i have spaces', 'and"\'quotes', '$and !this'],
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_python_hook_weird_setup_cfg(in_git_dir, tempdir_factory, store):
|
|
||||||
in_git_dir.join('setup.cfg').write('[install]\ninstall_scripts=/usr/sbin')
|
|
||||||
|
|
||||||
_test_hook_repo(
|
|
||||||
tempdir_factory, store, 'python_hooks_repo',
|
|
||||||
'foo', [os.devnull],
|
|
||||||
f'[{os.devnull!r}]\nHello World\n'.encode(),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_python_venv_deprecation(store, caplog):
|
def test_python_venv_deprecation(store, caplog):
|
||||||
config = {
|
config = {
|
||||||
'repo': 'local',
|
'repo': 'local',
|
||||||
|
@ -198,7 +156,7 @@ def test_intermixed_stdout_stderr(tempdir_factory, store):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail(os.name == 'nt', reason='ptys are posix-only')
|
@pytest.mark.xfail(sys.platform == 'win32', reason='ptys are posix-only')
|
||||||
def test_output_isatty(tempdir_factory, store):
|
def test_output_isatty(tempdir_factory, store):
|
||||||
_test_hook_repo(
|
_test_hook_repo(
|
||||||
tempdir_factory, store, 'stdout_stderr_repo',
|
tempdir_factory, store, 'stdout_stderr_repo',
|
||||||
|
@ -430,7 +388,7 @@ def test_local_python_repo(store, local_python_config):
|
||||||
def test_default_language_version(store, local_python_config):
|
def test_default_language_version(store, local_python_config):
|
||||||
config: dict[str, Any] = {
|
config: dict[str, Any] = {
|
||||||
'default_language_version': {'python': 'fake'},
|
'default_language_version': {'python': 'fake'},
|
||||||
'default_stages': ['commit'],
|
'default_stages': ['pre-commit'],
|
||||||
'repos': [local_python_config],
|
'repos': [local_python_config],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,18 +405,18 @@ def test_default_language_version(store, local_python_config):
|
||||||
def test_default_stages(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_language_version': {'python': C.DEFAULT},
|
||||||
'default_stages': ['commit'],
|
'default_stages': ['pre-commit'],
|
||||||
'repos': [local_python_config],
|
'repos': [local_python_config],
|
||||||
}
|
}
|
||||||
|
|
||||||
# `stages` was not set, should default
|
# `stages` was not set, should default
|
||||||
hook, = all_hooks(config, store)
|
hook, = all_hooks(config, store)
|
||||||
assert hook.stages == ['commit']
|
assert hook.stages == ['pre-commit']
|
||||||
|
|
||||||
# `stages` is set, should not default
|
# `stages` is set, should not default
|
||||||
config['repos'][0]['hooks'][0]['stages'] = ['push']
|
config['repos'][0]['hooks'][0]['stages'] = ['pre-push']
|
||||||
hook, = all_hooks(config, store)
|
hook, = all_hooks(config, store)
|
||||||
assert hook.stages == ['push']
|
assert hook.stages == ['pre-push']
|
||||||
|
|
||||||
|
|
||||||
def test_hook_id_not_present(tempdir_factory, store, caplog):
|
def test_hook_id_not_present(tempdir_factory, store, caplog):
|
||||||
|
@ -526,11 +484,19 @@ def test_manifest_hooks(tempdir_factory, store):
|
||||||
name='Bash hook',
|
name='Bash hook',
|
||||||
pass_filenames=True,
|
pass_filenames=True,
|
||||||
require_serial=False,
|
require_serial=False,
|
||||||
stages=(
|
stages=[
|
||||||
'commit', 'merge-commit', 'prepare-commit-msg', 'commit-msg',
|
'commit-msg',
|
||||||
'post-commit', 'manual', 'post-checkout', 'push', 'post-merge',
|
'post-checkout',
|
||||||
|
'post-commit',
|
||||||
|
'post-merge',
|
||||||
'post-rewrite',
|
'post-rewrite',
|
||||||
),
|
'pre-commit',
|
||||||
|
'pre-merge-commit',
|
||||||
|
'pre-push',
|
||||||
|
'pre-rebase',
|
||||||
|
'prepare-commit-msg',
|
||||||
|
'manual',
|
||||||
|
],
|
||||||
types=['file'],
|
types=['file'],
|
||||||
types_or=[],
|
types_or=[],
|
||||||
verbose=False,
|
verbose=False,
|
||||||
|
@ -582,3 +548,14 @@ def test_non_installable_hook_error_for_additional_dependencies(store, caplog):
|
||||||
'using language `system` which does not install an environment. '
|
'using language `system` which does not install an environment. '
|
||||||
'Perhaps you meant to use a specific language?'
|
'Perhaps you meant to use a specific language?'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_args_with_spaces_and_quotes(tmp_path):
|
||||||
|
ret = run_language(
|
||||||
|
tmp_path, system,
|
||||||
|
f"{shlex.quote(sys.executable)} -c 'import sys; print(sys.argv[1:])'",
|
||||||
|
('i have spaces', 'and"\'quotes', '$and !this'),
|
||||||
|
)
|
||||||
|
|
||||||
|
expected = b"['i have spaces', 'and\"\\'quotes', '$and !this']\n"
|
||||||
|
assert ret == (0, expected)
|
||||||
|
|
|
@ -187,7 +187,7 @@ def test_xargs_propagate_kwargs_to_cmd():
|
||||||
assert b'Pre commit is awesome' in stdout
|
assert b'Pre commit is awesome' in stdout
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail(os.name == 'nt', reason='posix only')
|
@pytest.mark.xfail(sys.platform == 'win32', reason='posix only')
|
||||||
def test_xargs_color_true_makes_tty():
|
def test_xargs_color_true_makes_tty():
|
||||||
retcode, out = xargs.xargs(
|
retcode, out = xargs.xargs(
|
||||||
(sys.executable, '-c', 'import sys; print(sys.stdout.isatty())'),
|
(sys.executable, '-c', 'import sys; print(sys.stdout.isatty())'),
|
||||||
|
|
2
tox.ini
2
tox.ini
|
@ -6,7 +6,7 @@ deps = -rrequirements-dev.txt
|
||||||
passenv = *
|
passenv = *
|
||||||
commands =
|
commands =
|
||||||
coverage erase
|
coverage erase
|
||||||
coverage run -m pytest {posargs:tests} --ignore=tests/languages
|
coverage run -m pytest {posargs:tests} --ignore=tests/languages --durations=20
|
||||||
coverage report --omit=pre_commit/languages/*,tests/languages/*
|
coverage report --omit=pre_commit/languages/*,tests/languages/*
|
||||||
|
|
||||||
[testenv:pre-commit]
|
[testenv:pre-commit]
|
||||||
|
|
Loading…
Add table
Reference in a new issue