Merging upstream version 2.3.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
c869774b2b
commit
ac2b33dbed
17 changed files with 261 additions and 37 deletions
|
@ -17,34 +17,34 @@ repos:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
additional_dependencies: [flake8-typing-imports==1.6.0]
|
additional_dependencies: [flake8-typing-imports==1.6.0]
|
||||||
- repo: https://github.com/pre-commit/mirrors-autopep8
|
- repo: https://github.com/pre-commit/mirrors-autopep8
|
||||||
rev: v1.5
|
rev: v1.5.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: autopep8
|
- id: autopep8
|
||||||
- repo: https://github.com/pre-commit/pre-commit
|
- repo: https://github.com/pre-commit/pre-commit
|
||||||
rev: v2.1.1
|
rev: v2.2.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: validate_manifest
|
- id: validate_manifest
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v2.0.1
|
rev: v2.1.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: [--py36-plus]
|
args: [--py36-plus]
|
||||||
- repo: https://github.com/asottile/reorder_python_imports
|
- repo: https://github.com/asottile/reorder_python_imports
|
||||||
rev: v1.9.0
|
rev: v2.1.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: reorder-python-imports
|
- id: reorder-python-imports
|
||||||
args: [--py3-plus]
|
args: [--py3-plus]
|
||||||
- repo: https://github.com/asottile/add-trailing-comma
|
- repo: https://github.com/asottile/add-trailing-comma
|
||||||
rev: v1.5.0
|
rev: v2.0.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: add-trailing-comma
|
- id: add-trailing-comma
|
||||||
args: [--py36-plus]
|
args: [--py36-plus]
|
||||||
- repo: https://github.com/asottile/setup-cfg-fmt
|
- repo: https://github.com/asottile/setup-cfg-fmt
|
||||||
rev: v1.6.0
|
rev: v1.8.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: setup-cfg-fmt
|
- id: setup-cfg-fmt
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: v0.761
|
rev: v0.770
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
exclude: ^testing/resources/
|
exclude: ^testing/resources/
|
||||||
|
|
27
CHANGELOG.md
27
CHANGELOG.md
|
@ -1,9 +1,34 @@
|
||||||
|
2.3.0 - 2020-04-22
|
||||||
|
==================
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Calculate character width using `east_asian_width`
|
||||||
|
- #1378 PR by @sophgn.
|
||||||
|
- Use `language_version: system` by default for `node` hooks if `node` / `npm`
|
||||||
|
are globally installed.
|
||||||
|
- #1388 PR by @asottile.
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- No longer use a hard-coded user id for docker hooks on windows
|
||||||
|
- #1371 PR by @killuazhu.
|
||||||
|
- Fix colors on windows during `git commit`
|
||||||
|
- #1381 issue by @Cielquan.
|
||||||
|
- #1382 PR by @asottile.
|
||||||
|
- Produce readable error message for incorrect argument count to `hook-impl`
|
||||||
|
- #1394 issue by @pip9ball.
|
||||||
|
- #1395 PR by @asottile.
|
||||||
|
- Fix installations which involve an upgrade of `pip` on windows
|
||||||
|
- #1398 issue by @xiaohuazi123.
|
||||||
|
- #1399 PR by @asottile.
|
||||||
|
- Preserve line endings in `pre-commit autoupdate`
|
||||||
|
- #1402 PR by @utek.
|
||||||
|
|
||||||
2.2.0 - 2020-03-12
|
2.2.0 - 2020-03-12
|
||||||
==================
|
==================
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
- Add support for the `post-checkout` hook
|
- Add support for the `post-checkout` hook
|
||||||
- #1210 issue by @domenkozar.
|
- #1120 issue by @domenkozar.
|
||||||
- #1339 PR by @andrewhare.
|
- #1339 PR by @andrewhare.
|
||||||
- Add more readable `--from-ref` / `--to-ref` aliases for `--source` /
|
- Add more readable `--from-ref` / `--to-ref` aliases for `--source` /
|
||||||
`--origin`
|
`--origin`
|
||||||
|
|
|
@ -11,7 +11,7 @@ if sys.platform == 'win32': # pragma: no cover (windows)
|
||||||
from ctypes.wintypes import DWORD
|
from ctypes.wintypes import DWORD
|
||||||
from ctypes.wintypes import HANDLE
|
from ctypes.wintypes import HANDLE
|
||||||
|
|
||||||
STD_OUTPUT_HANDLE = -11
|
STD_ERROR_HANDLE = -12
|
||||||
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
|
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
|
||||||
|
|
||||||
def bool_errcheck(result, func, args):
|
def bool_errcheck(result, func, args):
|
||||||
|
@ -40,9 +40,9 @@ if sys.platform == 'win32': # pragma: no cover (windows)
|
||||||
#
|
#
|
||||||
# More info on the escape sequences supported:
|
# More info on the escape sequences supported:
|
||||||
# https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx
|
# https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx
|
||||||
stdout = GetStdHandle(STD_OUTPUT_HANDLE)
|
stderr = GetStdHandle(STD_ERROR_HANDLE)
|
||||||
flags = GetConsoleMode(stdout)
|
flags = GetConsoleMode(stderr)
|
||||||
SetConsoleMode(stdout, flags | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
SetConsoleMode(stderr, flags | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
_enable()
|
_enable()
|
||||||
|
@ -90,7 +90,7 @@ def use_color(setting: str) -> bool:
|
||||||
return (
|
return (
|
||||||
setting == 'always' or (
|
setting == 'always' or (
|
||||||
setting == 'auto' and
|
setting == 'auto' and
|
||||||
sys.stdout.isatty() and
|
sys.stderr.isatty() and
|
||||||
terminal_supports_color and
|
terminal_supports_color and
|
||||||
os.getenv('TERM') != 'dumb'
|
os.getenv('TERM') != 'dumb'
|
||||||
)
|
)
|
||||||
|
|
|
@ -93,7 +93,7 @@ def _original_lines(
|
||||||
retry: bool = False,
|
retry: bool = False,
|
||||||
) -> Tuple[List[str], List[int]]:
|
) -> Tuple[List[str], List[int]]:
|
||||||
"""detect `rev:` lines or reformat the file"""
|
"""detect `rev:` lines or reformat the file"""
|
||||||
with open(path) as f:
|
with open(path, newline='') as f:
|
||||||
original = f.read()
|
original = f.read()
|
||||||
|
|
||||||
lines = original.splitlines(True)
|
lines = original.splitlines(True)
|
||||||
|
@ -126,7 +126,7 @@ def _write_new_config(path: str, rev_infos: List[Optional[RevInfo]]) -> None:
|
||||||
comment = match[4]
|
comment = match[4]
|
||||||
lines[idx] = f'{match[1]}rev:{match[2]}{new_rev}{comment}{match[5]}'
|
lines[idx] = f'{match[1]}rev:{match[2]}{new_rev}{comment}{match[5]}'
|
||||||
|
|
||||||
with open(path, 'w') as f:
|
with open(path, 'w', newline='') as f:
|
||||||
f.write(''.join(lines))
|
f.write(''.join(lines))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -147,15 +147,44 @@ def _pre_push_ns(
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
_EXPECTED_ARG_LENGTH_BY_HOOK = {
|
||||||
|
'commit-msg': 1,
|
||||||
|
'post-checkout': 3,
|
||||||
|
'pre-commit': 0,
|
||||||
|
'pre-merge-commit': 0,
|
||||||
|
'pre-push': 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _check_args_length(hook_type: str, args: Sequence[str]) -> None:
|
||||||
|
if hook_type == 'prepare-commit-msg':
|
||||||
|
if len(args) < 1 or len(args) > 3:
|
||||||
|
raise SystemExit(
|
||||||
|
f'hook-impl for {hook_type} expected 1, 2, or 3 arguments '
|
||||||
|
f'but got {len(args)}: {args}',
|
||||||
|
)
|
||||||
|
elif hook_type in _EXPECTED_ARG_LENGTH_BY_HOOK:
|
||||||
|
expected = _EXPECTED_ARG_LENGTH_BY_HOOK[hook_type]
|
||||||
|
if len(args) != expected:
|
||||||
|
arguments_s = 'argument' if expected == 1 else 'arguments'
|
||||||
|
raise SystemExit(
|
||||||
|
f'hook-impl for {hook_type} expected {expected} {arguments_s} '
|
||||||
|
f'but got {len(args)}: {args}',
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise AssertionError(f'unexpected hook type: {hook_type}')
|
||||||
|
|
||||||
|
|
||||||
def _run_ns(
|
def _run_ns(
|
||||||
hook_type: str,
|
hook_type: str,
|
||||||
color: bool,
|
color: bool,
|
||||||
args: Sequence[str],
|
args: Sequence[str],
|
||||||
stdin: bytes,
|
stdin: bytes,
|
||||||
) -> Optional[argparse.Namespace]:
|
) -> Optional[argparse.Namespace]:
|
||||||
|
_check_args_length(hook_type, args)
|
||||||
if hook_type == 'pre-push':
|
if hook_type == 'pre-push':
|
||||||
return _pre_push_ns(color, args, stdin)
|
return _pre_push_ns(color, args, stdin)
|
||||||
elif hook_type in {'prepare-commit-msg', 'commit-msg'}:
|
elif hook_type in {'commit-msg', 'prepare-commit-msg'}:
|
||||||
return _ns(hook_type, color, commit_msg_filename=args[0])
|
return _ns(hook_type, color, commit_msg_filename=args[0])
|
||||||
elif hook_type in {'pre-merge-commit', 'pre-commit'}:
|
elif hook_type in {'pre-merge-commit', 'pre-commit'}:
|
||||||
return _ns(hook_type, color)
|
return _ns(hook_type, color)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
|
import unicodedata
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Collection
|
from typing import Collection
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
@ -33,8 +34,13 @@ from pre_commit.util import EnvironT
|
||||||
logger = logging.getLogger('pre_commit')
|
logger = logging.getLogger('pre_commit')
|
||||||
|
|
||||||
|
|
||||||
|
def _len_cjk(msg: str) -> int:
|
||||||
|
widths = {'A': 1, 'F': 2, 'H': 1, 'N': 1, 'Na': 1, 'W': 2}
|
||||||
|
return sum(widths[unicodedata.east_asian_width(c)] for c in msg)
|
||||||
|
|
||||||
|
|
||||||
def _start_msg(*, start: str, cols: int, end_len: int) -> str:
|
def _start_msg(*, start: str, cols: int, end_len: int) -> str:
|
||||||
dots = '.' * (cols - len(start) - end_len - 1)
|
dots = '.' * (cols - _len_cjk(start) - end_len - 1)
|
||||||
return f'{start}{dots}'
|
return f'{start}{dots}'
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,7 +53,7 @@ def _full_msg(
|
||||||
use_color: bool,
|
use_color: bool,
|
||||||
postfix: str = '',
|
postfix: str = '',
|
||||||
) -> str:
|
) -> str:
|
||||||
dots = '.' * (cols - len(start) - len(postfix) - len(end_msg) - 1)
|
dots = '.' * (cols - _len_cjk(start) - len(postfix) - len(end_msg) - 1)
|
||||||
end = color.format_color(end_msg, end_color, use_color)
|
end = color.format_color(end_msg, end_color, use_color)
|
||||||
return f'{start}{dots}{postfix}{end}\n'
|
return f'{start}{dots}{postfix}{end}\n'
|
||||||
|
|
||||||
|
@ -206,7 +212,7 @@ def _compute_cols(hooks: Sequence[Hook]) -> int:
|
||||||
Hook name...(no files to check) Skipped
|
Hook name...(no files to check) Skipped
|
||||||
"""
|
"""
|
||||||
if hooks:
|
if hooks:
|
||||||
name_len = max(len(hook.name) for hook in hooks)
|
name_len = max(_len_cjk(hook.name) for hook in hooks)
|
||||||
else:
|
else:
|
||||||
name_len = 0
|
name_len = 0
|
||||||
|
|
||||||
|
|
|
@ -76,18 +76,18 @@ def install_environment(
|
||||||
os.mkdir(directory)
|
os.mkdir(directory)
|
||||||
|
|
||||||
|
|
||||||
def get_docker_user() -> str: # pragma: win32 no cover
|
def get_docker_user() -> Tuple[str, ...]: # pragma: win32 no cover
|
||||||
try:
|
try:
|
||||||
return f'{os.getuid()}:{os.getgid()}'
|
return ('-u', f'{os.getuid()}:{os.getgid()}')
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return '1000:1000'
|
return ()
|
||||||
|
|
||||||
|
|
||||||
def docker_cmd() -> Tuple[str, ...]: # pragma: win32 no cover
|
def docker_cmd() -> Tuple[str, ...]: # pragma: win32 no cover
|
||||||
return (
|
return (
|
||||||
'docker', 'run',
|
'docker', 'run',
|
||||||
'--rm',
|
'--rm',
|
||||||
'-u', get_docker_user(),
|
*get_docker_user(),
|
||||||
# https://docs.docker.com/engine/reference/commandline/run/#mount-volumes-from-container-volumes-from
|
# https://docs.docker.com/engine/reference/commandline/run/#mount-volumes-from-container-volumes-from
|
||||||
# The `Z` option tells Docker to label the content with a private
|
# The `Z` option tells Docker to label the content with a private
|
||||||
# unshared label. Only the current container can use a private volume.
|
# unshared label. Only the current container can use a private volume.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import functools
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
|
@ -6,6 +7,7 @@ from typing import Sequence
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
|
from pre_commit import parse_shebang
|
||||||
from pre_commit.envcontext import envcontext
|
from pre_commit.envcontext import envcontext
|
||||||
from pre_commit.envcontext import PatchesT
|
from pre_commit.envcontext import PatchesT
|
||||||
from pre_commit.envcontext import Var
|
from pre_commit.envcontext import Var
|
||||||
|
@ -18,10 +20,22 @@ from pre_commit.util import cmd_output
|
||||||
from pre_commit.util import cmd_output_b
|
from pre_commit.util import cmd_output_b
|
||||||
|
|
||||||
ENVIRONMENT_DIR = 'node_env'
|
ENVIRONMENT_DIR = 'node_env'
|
||||||
get_default_version = helpers.basic_get_default_version
|
|
||||||
healthy = helpers.basic_healthy
|
healthy = helpers.basic_healthy
|
||||||
|
|
||||||
|
|
||||||
|
@functools.lru_cache(maxsize=1)
|
||||||
|
def get_default_version() -> str:
|
||||||
|
# nodeenv does not yet support `-n system` on windows
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
return C.DEFAULT
|
||||||
|
# if node is already installed, we can save a bunch of setup time by
|
||||||
|
# using the installed version
|
||||||
|
elif all(parse_shebang.find_executable(exe) for exe in ('node', 'npm')):
|
||||||
|
return 'system'
|
||||||
|
else:
|
||||||
|
return C.DEFAULT
|
||||||
|
|
||||||
|
|
||||||
def _envdir(prefix: Prefix, version: str) -> str:
|
def _envdir(prefix: Prefix, version: str) -> str:
|
||||||
directory = helpers.environment_dir(ENVIRONMENT_DIR, version)
|
directory = helpers.environment_dir(ENVIRONMENT_DIR, version)
|
||||||
return prefix.path(directory)
|
return prefix.path(directory)
|
||||||
|
|
|
@ -182,8 +182,8 @@ def py_interface(
|
||||||
version: str,
|
version: str,
|
||||||
additional_dependencies: Sequence[str],
|
additional_dependencies: Sequence[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
additional_dependencies = tuple(additional_dependencies)
|
|
||||||
directory = helpers.environment_dir(_dir, version)
|
directory = helpers.environment_dir(_dir, version)
|
||||||
|
install = ('python', '-mpip', 'install', '.', *additional_dependencies)
|
||||||
|
|
||||||
env_dir = prefix.path(directory)
|
env_dir = prefix.path(directory)
|
||||||
with clean_path_on_failure(env_dir):
|
with clean_path_on_failure(env_dir):
|
||||||
|
@ -193,9 +193,7 @@ def py_interface(
|
||||||
python = os.path.realpath(sys.executable)
|
python = os.path.realpath(sys.executable)
|
||||||
_make_venv(env_dir, python)
|
_make_venv(env_dir, python)
|
||||||
with in_env(prefix, version):
|
with in_env(prefix, version):
|
||||||
helpers.run_setup_cmd(
|
helpers.run_setup_cmd(prefix, install)
|
||||||
prefix, ('pip', 'install', '.') + additional_dependencies,
|
|
||||||
)
|
|
||||||
|
|
||||||
return in_env, healthy, run_hook, install_environment
|
return in_env, healthy, run_hook, install_environment
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[metadata]
|
[metadata]
|
||||||
name = pre_commit
|
name = pre_commit
|
||||||
version = 2.2.0
|
version = 2.3.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
|
||||||
|
|
|
@ -29,26 +29,26 @@ def test_use_color_always():
|
||||||
|
|
||||||
|
|
||||||
def test_use_color_no_tty():
|
def test_use_color_no_tty():
|
||||||
with mock.patch.object(sys.stdout, 'isatty', return_value=False):
|
with mock.patch.object(sys.stderr, 'isatty', return_value=False):
|
||||||
assert use_color('auto') is False
|
assert use_color('auto') is False
|
||||||
|
|
||||||
|
|
||||||
def test_use_color_tty_with_color_support():
|
def test_use_color_tty_with_color_support():
|
||||||
with mock.patch.object(sys.stdout, 'isatty', return_value=True):
|
with mock.patch.object(sys.stderr, 'isatty', return_value=True):
|
||||||
with mock.patch('pre_commit.color.terminal_supports_color', True):
|
with mock.patch('pre_commit.color.terminal_supports_color', True):
|
||||||
with envcontext.envcontext((('TERM', envcontext.UNSET),)):
|
with envcontext.envcontext((('TERM', envcontext.UNSET),)):
|
||||||
assert use_color('auto') is True
|
assert use_color('auto') is True
|
||||||
|
|
||||||
|
|
||||||
def test_use_color_tty_without_color_support():
|
def test_use_color_tty_without_color_support():
|
||||||
with mock.patch.object(sys.stdout, 'isatty', return_value=True):
|
with mock.patch.object(sys.stderr, 'isatty', return_value=True):
|
||||||
with mock.patch('pre_commit.color.terminal_supports_color', False):
|
with mock.patch('pre_commit.color.terminal_supports_color', False):
|
||||||
with envcontext.envcontext((('TERM', envcontext.UNSET),)):
|
with envcontext.envcontext((('TERM', envcontext.UNSET),)):
|
||||||
assert use_color('auto') is False
|
assert use_color('auto') is False
|
||||||
|
|
||||||
|
|
||||||
def test_use_color_dumb_term():
|
def test_use_color_dumb_term():
|
||||||
with mock.patch.object(sys.stdout, 'isatty', return_value=True):
|
with mock.patch.object(sys.stderr, 'isatty', return_value=True):
|
||||||
with mock.patch('pre_commit.color.terminal_supports_color', True):
|
with mock.patch('pre_commit.color.terminal_supports_color', True):
|
||||||
with envcontext.envcontext((('TERM', 'dumb'),)):
|
with envcontext.envcontext((('TERM', 'dumb'),)):
|
||||||
assert use_color('auto') is False
|
assert use_color('auto') is False
|
||||||
|
|
|
@ -263,6 +263,45 @@ def test_does_not_reformat(tmpdir, out_of_date, store):
|
||||||
assert cfg.read() == expected
|
assert cfg.read() == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_does_not_change_mixed_endlines_read(up_to_date, tmpdir, store):
|
||||||
|
fmt = (
|
||||||
|
'repos:\n'
|
||||||
|
'- repo: {}\n'
|
||||||
|
' rev: {} # definitely the version I want!\r\n'
|
||||||
|
' hooks:\r\n'
|
||||||
|
' - id: foo\n'
|
||||||
|
' # These args are because reasons!\r\n'
|
||||||
|
' args: [foo, bar, baz]\r\n'
|
||||||
|
)
|
||||||
|
cfg = tmpdir.join(C.CONFIG_FILE)
|
||||||
|
|
||||||
|
expected = fmt.format(up_to_date, git.head_rev(up_to_date)).encode()
|
||||||
|
cfg.write_binary(expected)
|
||||||
|
|
||||||
|
assert autoupdate(str(cfg), store, freeze=False, tags_only=False) == 0
|
||||||
|
assert cfg.read_binary() == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_does_not_change_mixed_endlines_write(tmpdir, out_of_date, store):
|
||||||
|
fmt = (
|
||||||
|
'repos:\n'
|
||||||
|
'- repo: {}\n'
|
||||||
|
' rev: {} # definitely the version I want!\r\n'
|
||||||
|
' hooks:\r\n'
|
||||||
|
' - id: foo\n'
|
||||||
|
' # These args are because reasons!\r\n'
|
||||||
|
' args: [foo, bar, baz]\r\n'
|
||||||
|
)
|
||||||
|
cfg = tmpdir.join(C.CONFIG_FILE)
|
||||||
|
cfg.write_binary(
|
||||||
|
fmt.format(out_of_date.path, out_of_date.original_rev).encode(),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert autoupdate(str(cfg), store, freeze=False, tags_only=False) == 0
|
||||||
|
expected = fmt.format(out_of_date.path, out_of_date.head_rev).encode()
|
||||||
|
assert cfg.read_binary() == expected
|
||||||
|
|
||||||
|
|
||||||
def test_loses_formatting_when_not_detectable(out_of_date, store, tmpdir):
|
def test_loses_formatting_when_not_detectable(out_of_date, store, tmpdir):
|
||||||
"""A best-effort attempt is made at updating rev without rewriting
|
"""A best-effort attempt is made at updating rev without rewriting
|
||||||
formatting. When the original formatting cannot be detected, this
|
formatting. When the original formatting cannot be detected, this
|
||||||
|
|
|
@ -89,6 +89,51 @@ def test_run_legacy_recursive(tmpdir):
|
||||||
call()
|
call()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
('hook_type', 'args'),
|
||||||
|
(
|
||||||
|
('pre-commit', []),
|
||||||
|
('pre-merge-commit', []),
|
||||||
|
('pre-push', ['branch_name', 'remote_name']),
|
||||||
|
('commit-msg', ['.git/COMMIT_EDITMSG']),
|
||||||
|
('post-checkout', ['old_head', 'new_head', '1']),
|
||||||
|
# multiple choices for commit-editmsg
|
||||||
|
('prepare-commit-msg', ['.git/COMMIT_EDITMSG']),
|
||||||
|
('prepare-commit-msg', ['.git/COMMIT_EDITMSG', 'message']),
|
||||||
|
('prepare-commit-msg', ['.git/COMMIT_EDITMSG', 'commit', 'deadbeef']),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
def test_check_args_length_ok(hook_type, args):
|
||||||
|
hook_impl._check_args_length(hook_type, args)
|
||||||
|
|
||||||
|
|
||||||
|
def test_check_args_length_error_too_many_plural():
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
hook_impl._check_args_length('pre-commit', ['run', '--all-files'])
|
||||||
|
msg, = excinfo.value.args
|
||||||
|
assert msg == (
|
||||||
|
'hook-impl for pre-commit expected 0 arguments but got 2: '
|
||||||
|
"['run', '--all-files']"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_check_args_length_error_too_many_singluar():
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
hook_impl._check_args_length('commit-msg', [])
|
||||||
|
msg, = excinfo.value.args
|
||||||
|
assert msg == 'hook-impl for commit-msg expected 1 argument but got 0: []'
|
||||||
|
|
||||||
|
|
||||||
|
def test_check_args_length_prepare_commit_msg_error():
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
hook_impl._check_args_length('prepare-commit-msg', [])
|
||||||
|
msg, = excinfo.value.args
|
||||||
|
assert msg == (
|
||||||
|
'hook-impl for prepare-commit-msg expected 1, 2, or 3 arguments '
|
||||||
|
'but got 0: []'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -52,6 +52,18 @@ def test_full_msg():
|
||||||
assert ret == 'start......end\n'
|
assert ret == 'start......end\n'
|
||||||
|
|
||||||
|
|
||||||
|
def test_full_msg_with_cjk():
|
||||||
|
ret = _full_msg(
|
||||||
|
start='啊あ아',
|
||||||
|
end_msg='end',
|
||||||
|
end_color='',
|
||||||
|
use_color=False,
|
||||||
|
cols=15,
|
||||||
|
)
|
||||||
|
# 5 dots: 15 - 6 - 3 - 1
|
||||||
|
assert ret == '啊あ아.....end\n'
|
||||||
|
|
||||||
|
|
||||||
def test_full_msg_with_color():
|
def test_full_msg_with_color():
|
||||||
ret = _full_msg(
|
ret = _full_msg(
|
||||||
start='start',
|
start='start',
|
||||||
|
|
|
@ -20,4 +20,4 @@ def test_docker_fallback_user():
|
||||||
getuid=invalid_attribute,
|
getuid=invalid_attribute,
|
||||||
getgid=invalid_attribute,
|
getgid=invalid_attribute,
|
||||||
):
|
):
|
||||||
assert docker.get_docker_user() == '1000:1000'
|
assert docker.get_docker_user() == ()
|
||||||
|
|
47
tests/languages/node_test.py
Normal file
47
tests/languages/node_test.py
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import sys
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import pre_commit.constants as C
|
||||||
|
from pre_commit import parse_shebang
|
||||||
|
from pre_commit.languages.node import get_default_version
|
||||||
|
|
||||||
|
|
||||||
|
ACTUAL_GET_DEFAULT_VERSION = get_default_version.__wrapped__
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def is_linux():
|
||||||
|
with mock.patch.object(sys, 'platform', 'linux'):
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def is_win32():
|
||||||
|
with mock.patch.object(sys, 'platform', 'win32'):
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def find_exe_mck():
|
||||||
|
with mock.patch.object(parse_shebang, 'find_executable') as mck:
|
||||||
|
yield mck
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('is_linux')
|
||||||
|
def test_sets_system_when_node_and_npm_are_available(find_exe_mck):
|
||||||
|
find_exe_mck.return_value = '/path/to/exe'
|
||||||
|
assert ACTUAL_GET_DEFAULT_VERSION() == 'system'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('is_linux')
|
||||||
|
def test_uses_default_when_node_and_npm_are_not_available(find_exe_mck):
|
||||||
|
find_exe_mck.return_value = None
|
||||||
|
assert ACTUAL_GET_DEFAULT_VERSION() == C.DEFAULT
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures('is_win32')
|
||||||
|
def test_sets_default_on_windows(find_exe_mck):
|
||||||
|
find_exe_mck.return_value = '/path/to/exe'
|
||||||
|
assert ACTUAL_GET_DEFAULT_VERSION() == C.DEFAULT
|
|
@ -131,9 +131,9 @@ def test_python_hook(tempdir_factory, store):
|
||||||
def test_python_hook_default_version(tempdir_factory, store):
|
def test_python_hook_default_version(tempdir_factory, store):
|
||||||
# make sure that this continues to work for platforms where default
|
# make sure that this continues to work for platforms where default
|
||||||
# language detection does not work
|
# language detection does not work
|
||||||
with mock.patch.object(
|
returns_default = mock.Mock(return_value=C.DEFAULT)
|
||||||
python, 'get_default_version', return_value=C.DEFAULT,
|
lang = languages['python']._replace(get_default_version=returns_default)
|
||||||
):
|
with mock.patch.dict(languages, python=lang):
|
||||||
test_python_hook(tempdir_factory, store)
|
test_python_hook(tempdir_factory, store)
|
||||||
|
|
||||||
|
|
||||||
|
@ -243,6 +243,15 @@ def test_run_a_node_hook(tempdir_factory, store):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
returns_default = mock.Mock(return_value=C.DEFAULT)
|
||||||
|
lang = languages['node']._replace(get_default_version=returns_default)
|
||||||
|
with mock.patch.dict(languages, node=lang):
|
||||||
|
test_run_a_node_hook(tempdir_factory, store)
|
||||||
|
|
||||||
|
|
||||||
def test_run_versioned_node_hook(tempdir_factory, store):
|
def test_run_versioned_node_hook(tempdir_factory, store):
|
||||||
_test_hook_repo(
|
_test_hook_repo(
|
||||||
tempdir_factory, store, 'node_versioned_hooks_repo',
|
tempdir_factory, store, 'node_versioned_hooks_repo',
|
||||||
|
|
Loading…
Add table
Reference in a new issue