mirror of
https://github.com/pre-commit/pre-commit.git
synced 2026-02-17 08:14:42 +04:00
Merge pull request #1282 from pre-commit/cleanup
More miscellaneous cleanup
This commit is contained in:
commit
5a62501307
33 changed files with 209 additions and 296 deletions
|
|
@ -7,7 +7,6 @@ omit =
|
||||||
setup.py
|
setup.py
|
||||||
# Don't complain if non-runnable code isn't run
|
# Don't complain if non-runnable code isn't run
|
||||||
*/__main__.py
|
*/__main__.py
|
||||||
pre_commit/color_windows.py
|
|
||||||
pre_commit/resources/*
|
pre_commit/resources/*
|
||||||
|
|
||||||
[report]
|
[report]
|
||||||
|
|
|
||||||
|
|
@ -192,19 +192,20 @@ META_HOOK_DICT = cfgv.Map(
|
||||||
cfgv.Required('id', cfgv.check_one_of(tuple(k for k, _ in _meta))),
|
cfgv.Required('id', cfgv.check_one_of(tuple(k for k, _ in _meta))),
|
||||||
# language must be system
|
# language must be system
|
||||||
cfgv.Optional('language', cfgv.check_one_of({'system'}), 'system'),
|
cfgv.Optional('language', cfgv.check_one_of({'system'}), 'system'),
|
||||||
*([
|
*(
|
||||||
# default to the hook definition for the meta hooks
|
# default to the hook definition for the meta hooks
|
||||||
cfgv.ConditionalOptional(key, cfgv.check_any, value, 'id', hook_id)
|
cfgv.ConditionalOptional(key, cfgv.check_any, value, 'id', hook_id)
|
||||||
for hook_id, values in _meta
|
for hook_id, values in _meta
|
||||||
for key, value in values
|
for key, value in values
|
||||||
] + [
|
),
|
||||||
|
*(
|
||||||
# default to the "manifest" parsing
|
# default to the "manifest" parsing
|
||||||
cfgv.OptionalNoDefault(item.key, item.check_fn)
|
cfgv.OptionalNoDefault(item.key, item.check_fn)
|
||||||
# these will always be defaulted above
|
# these will always be defaulted above
|
||||||
if item.key in {'name', 'language', 'entry'} else
|
if item.key in {'name', 'language', 'entry'} else
|
||||||
item
|
item
|
||||||
for item in MANIFEST_HOOK_DICT.items
|
for item in MANIFEST_HOOK_DICT.items
|
||||||
]),
|
),
|
||||||
)
|
)
|
||||||
CONFIG_HOOK_DICT = cfgv.Map(
|
CONFIG_HOOK_DICT = cfgv.Map(
|
||||||
'Hook', 'id',
|
'Hook', 'id',
|
||||||
|
|
@ -215,11 +216,11 @@ CONFIG_HOOK_DICT = cfgv.Map(
|
||||||
# are optional.
|
# are optional.
|
||||||
# No defaults are provided here as the config is merged on top of the
|
# No defaults are provided here as the config is merged on top of the
|
||||||
# manifest.
|
# manifest.
|
||||||
*[
|
*(
|
||||||
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'
|
||||||
],
|
),
|
||||||
)
|
)
|
||||||
CONFIG_REPO_DICT = cfgv.Map(
|
CONFIG_REPO_DICT = cfgv.Map(
|
||||||
'Repository', 'repo',
|
'Repository', 'repo',
|
||||||
|
|
@ -245,7 +246,7 @@ CONFIG_REPO_DICT = cfgv.Map(
|
||||||
DEFAULT_LANGUAGE_VERSION = cfgv.Map(
|
DEFAULT_LANGUAGE_VERSION = cfgv.Map(
|
||||||
'DefaultLanguageVersion', None,
|
'DefaultLanguageVersion', None,
|
||||||
cfgv.NoAdditionalKeys(all_languages),
|
cfgv.NoAdditionalKeys(all_languages),
|
||||||
*[cfgv.Optional(x, cfgv.check_string, C.DEFAULT) for x in all_languages],
|
*(cfgv.Optional(x, cfgv.check_string, C.DEFAULT) for x in all_languages),
|
||||||
)
|
)
|
||||||
CONFIG_SCHEMA = cfgv.Map(
|
CONFIG_SCHEMA = cfgv.Map(
|
||||||
'Config', None,
|
'Config', None,
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,64 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
terminal_supports_color = True
|
|
||||||
if sys.platform == 'win32': # pragma: no cover (windows)
|
if sys.platform == 'win32': # pragma: no cover (windows)
|
||||||
from pre_commit.color_windows import enable_virtual_terminal_processing
|
def _enable() -> None:
|
||||||
|
from ctypes import POINTER
|
||||||
|
from ctypes import windll
|
||||||
|
from ctypes import WinError
|
||||||
|
from ctypes import WINFUNCTYPE
|
||||||
|
from ctypes.wintypes import BOOL
|
||||||
|
from ctypes.wintypes import DWORD
|
||||||
|
from ctypes.wintypes import HANDLE
|
||||||
|
|
||||||
|
STD_OUTPUT_HANDLE = -11
|
||||||
|
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
|
||||||
|
|
||||||
|
def bool_errcheck(result, func, args):
|
||||||
|
if not result:
|
||||||
|
raise WinError()
|
||||||
|
return args
|
||||||
|
|
||||||
|
GetStdHandle = WINFUNCTYPE(HANDLE, DWORD)(
|
||||||
|
('GetStdHandle', windll.kernel32), ((1, 'nStdHandle'),),
|
||||||
|
)
|
||||||
|
|
||||||
|
GetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD))(
|
||||||
|
('GetConsoleMode', windll.kernel32),
|
||||||
|
((1, 'hConsoleHandle'), (2, 'lpMode')),
|
||||||
|
)
|
||||||
|
GetConsoleMode.errcheck = bool_errcheck
|
||||||
|
|
||||||
|
SetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, DWORD)(
|
||||||
|
('SetConsoleMode', windll.kernel32),
|
||||||
|
((1, 'hConsoleHandle'), (1, 'dwMode')),
|
||||||
|
)
|
||||||
|
SetConsoleMode.errcheck = bool_errcheck
|
||||||
|
|
||||||
|
# As of Windows 10, the Windows console supports (some) ANSI escape
|
||||||
|
# sequences, but it needs to be enabled using `SetConsoleMode` first.
|
||||||
|
#
|
||||||
|
# More info on the escape sequences supported:
|
||||||
|
# https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx
|
||||||
|
stdout = GetStdHandle(STD_OUTPUT_HANDLE)
|
||||||
|
flags = GetConsoleMode(stdout)
|
||||||
|
SetConsoleMode(stdout, flags | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
enable_virtual_terminal_processing()
|
_enable()
|
||||||
except OSError:
|
except OSError:
|
||||||
terminal_supports_color = False
|
terminal_supports_color = False
|
||||||
|
else:
|
||||||
|
terminal_supports_color = True
|
||||||
|
else: # pragma: windows no cover
|
||||||
|
terminal_supports_color = True
|
||||||
|
|
||||||
RED = '\033[41m'
|
RED = '\033[41m'
|
||||||
GREEN = '\033[42m'
|
GREEN = '\033[42m'
|
||||||
YELLOW = '\033[43;30m'
|
YELLOW = '\033[43;30m'
|
||||||
TURQUOISE = '\033[46;30m'
|
TURQUOISE = '\033[46;30m'
|
||||||
SUBTLE = '\033[2m'
|
SUBTLE = '\033[2m'
|
||||||
NORMAL = '\033[0m'
|
NORMAL = '\033[m'
|
||||||
|
|
||||||
|
|
||||||
class InvalidColorSetting(ValueError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def format_color(text: str, color: str, use_color_setting: bool) -> str:
|
def format_color(text: str, color: str, use_color_setting: bool) -> str:
|
||||||
|
|
@ -29,10 +69,10 @@ def format_color(text: str, color: str, use_color_setting: bool) -> str:
|
||||||
color - The color start string
|
color - The color start string
|
||||||
use_color_setting - Whether or not to color
|
use_color_setting - Whether or not to color
|
||||||
"""
|
"""
|
||||||
if not use_color_setting:
|
if use_color_setting:
|
||||||
return text
|
|
||||||
else:
|
|
||||||
return f'{color}{text}{NORMAL}'
|
return f'{color}{text}{NORMAL}'
|
||||||
|
else:
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
COLOR_CHOICES = ('auto', 'always', 'never')
|
COLOR_CHOICES = ('auto', 'always', 'never')
|
||||||
|
|
@ -45,7 +85,7 @@ def use_color(setting: str) -> bool:
|
||||||
setting - Either `auto`, `always`, or `never`
|
setting - Either `auto`, `always`, or `never`
|
||||||
"""
|
"""
|
||||||
if setting not in COLOR_CHOICES:
|
if setting not in COLOR_CHOICES:
|
||||||
raise InvalidColorSetting(setting)
|
raise ValueError(setting)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
setting == 'always' or (
|
setting == 'always' or (
|
||||||
|
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
import sys
|
|
||||||
assert sys.platform == 'win32'
|
|
||||||
|
|
||||||
from ctypes import POINTER # noqa: E402
|
|
||||||
from ctypes import windll # noqa: E402
|
|
||||||
from ctypes import WinError # noqa: E402
|
|
||||||
from ctypes import WINFUNCTYPE # noqa: E402
|
|
||||||
from ctypes.wintypes import BOOL # noqa: E402
|
|
||||||
from ctypes.wintypes import DWORD # noqa: E402
|
|
||||||
from ctypes.wintypes import HANDLE # noqa: E402
|
|
||||||
|
|
||||||
|
|
||||||
STD_OUTPUT_HANDLE = -11
|
|
||||||
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
|
|
||||||
|
|
||||||
|
|
||||||
def bool_errcheck(result, func, args):
|
|
||||||
if not result:
|
|
||||||
raise WinError()
|
|
||||||
return args
|
|
||||||
|
|
||||||
|
|
||||||
GetStdHandle = WINFUNCTYPE(HANDLE, DWORD)(
|
|
||||||
('GetStdHandle', windll.kernel32), ((1, 'nStdHandle'),),
|
|
||||||
)
|
|
||||||
|
|
||||||
GetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD))(
|
|
||||||
('GetConsoleMode', windll.kernel32),
|
|
||||||
((1, 'hConsoleHandle'), (2, 'lpMode')),
|
|
||||||
)
|
|
||||||
GetConsoleMode.errcheck = bool_errcheck
|
|
||||||
|
|
||||||
SetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, DWORD)(
|
|
||||||
('SetConsoleMode', windll.kernel32),
|
|
||||||
((1, 'hConsoleHandle'), (1, 'dwMode')),
|
|
||||||
)
|
|
||||||
SetConsoleMode.errcheck = bool_errcheck
|
|
||||||
|
|
||||||
|
|
||||||
def enable_virtual_terminal_processing():
|
|
||||||
"""As of Windows 10, the Windows console supports (some) ANSI escape
|
|
||||||
sequences, but it needs to be enabled using `SetConsoleMode` first.
|
|
||||||
|
|
||||||
More info on the escape sequences supported:
|
|
||||||
https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx
|
|
||||||
"""
|
|
||||||
stdout = GetStdHandle(STD_OUTPUT_HANDLE)
|
|
||||||
flags = GetConsoleMode(stdout)
|
|
||||||
SetConsoleMode(stdout, flags | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
|
||||||
|
|
@ -29,7 +29,5 @@ def init_templatedir(
|
||||||
dest = os.path.realpath(directory)
|
dest = os.path.realpath(directory)
|
||||||
if configured_path != dest:
|
if configured_path != dest:
|
||||||
logger.warning('`init.templateDir` not set to the target directory')
|
logger.warning('`init.templateDir` not set to the target directory')
|
||||||
logger.warning(
|
logger.warning(f'maybe `git config --global init.templateDir {dest}`?')
|
||||||
f'maybe `git config --global init.templateDir {dest}`?',
|
|
||||||
)
|
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
|
|
@ -28,18 +28,17 @@ def _migrate_map(contents: str) -> str:
|
||||||
# If they are using the "default" flow style of yaml, this operation
|
# If they are using the "default" flow style of yaml, this operation
|
||||||
# will yield a valid configuration
|
# will yield a valid configuration
|
||||||
try:
|
try:
|
||||||
trial_contents = header + 'repos:\n' + rest
|
trial_contents = f'{header}repos:\n{rest}'
|
||||||
ordered_load(trial_contents)
|
ordered_load(trial_contents)
|
||||||
contents = trial_contents
|
contents = trial_contents
|
||||||
except yaml.YAMLError:
|
except yaml.YAMLError:
|
||||||
contents = header + 'repos:\n' + _indent(rest)
|
contents = f'{header}repos:\n{_indent(rest)}'
|
||||||
|
|
||||||
return contents
|
return contents
|
||||||
|
|
||||||
|
|
||||||
def _migrate_sha_to_rev(contents: str) -> str:
|
def _migrate_sha_to_rev(contents: str) -> str:
|
||||||
reg = re.compile(r'(\n\s+)sha:')
|
return re.sub(r'(\n\s+)sha:', r'\1rev:', contents)
|
||||||
return reg.sub(r'\1rev:', contents)
|
|
||||||
|
|
||||||
|
|
||||||
def migrate_config(config_file: str, quiet: bool = False) -> int:
|
def migrate_config(config_file: str, quiet: bool = False) -> int:
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ from pre_commit import color
|
||||||
from pre_commit import git
|
from pre_commit import git
|
||||||
from pre_commit import output
|
from pre_commit import output
|
||||||
from pre_commit.clientlib import load_config
|
from pre_commit.clientlib import load_config
|
||||||
from pre_commit.output import get_hook_message
|
|
||||||
from pre_commit.repository import all_hooks
|
from pre_commit.repository import all_hooks
|
||||||
from pre_commit.repository import Hook
|
from pre_commit.repository import Hook
|
||||||
from pre_commit.repository import install_hook_envs
|
from pre_commit.repository import install_hook_envs
|
||||||
|
|
@ -33,6 +32,25 @@ from pre_commit.util import EnvironT
|
||||||
logger = logging.getLogger('pre_commit')
|
logger = logging.getLogger('pre_commit')
|
||||||
|
|
||||||
|
|
||||||
|
def _start_msg(*, start: str, cols: int, end_len: int) -> str:
|
||||||
|
dots = '.' * (cols - len(start) - end_len - 1)
|
||||||
|
return f'{start}{dots}'
|
||||||
|
|
||||||
|
|
||||||
|
def _full_msg(
|
||||||
|
*,
|
||||||
|
start: str,
|
||||||
|
cols: int,
|
||||||
|
end_msg: str,
|
||||||
|
end_color: str,
|
||||||
|
use_color: bool,
|
||||||
|
postfix: str = '',
|
||||||
|
) -> str:
|
||||||
|
dots = '.' * (cols - len(start) - len(postfix) - len(end_msg) - 1)
|
||||||
|
end = color.format_color(end_msg, end_color, use_color)
|
||||||
|
return f'{start}{dots}{postfix}{end}\n'
|
||||||
|
|
||||||
|
|
||||||
def filter_by_include_exclude(
|
def filter_by_include_exclude(
|
||||||
names: Collection[str],
|
names: Collection[str],
|
||||||
include: str,
|
include: str,
|
||||||
|
|
@ -106,8 +124,8 @@ def _run_single_hook(
|
||||||
|
|
||||||
if hook.id in skips or hook.alias in skips:
|
if hook.id in skips or hook.alias in skips:
|
||||||
output.write(
|
output.write(
|
||||||
get_hook_message(
|
_full_msg(
|
||||||
hook.name,
|
start=hook.name,
|
||||||
end_msg=SKIPPED,
|
end_msg=SKIPPED,
|
||||||
end_color=color.YELLOW,
|
end_color=color.YELLOW,
|
||||||
use_color=use_color,
|
use_color=use_color,
|
||||||
|
|
@ -120,8 +138,8 @@ def _run_single_hook(
|
||||||
out = b''
|
out = b''
|
||||||
elif not filenames and not hook.always_run:
|
elif not filenames and not hook.always_run:
|
||||||
output.write(
|
output.write(
|
||||||
get_hook_message(
|
_full_msg(
|
||||||
hook.name,
|
start=hook.name,
|
||||||
postfix=NO_FILES,
|
postfix=NO_FILES,
|
||||||
end_msg=SKIPPED,
|
end_msg=SKIPPED,
|
||||||
end_color=color.TURQUOISE,
|
end_color=color.TURQUOISE,
|
||||||
|
|
@ -135,7 +153,7 @@ def _run_single_hook(
|
||||||
out = b''
|
out = b''
|
||||||
else:
|
else:
|
||||||
# print hook and dots first in case the hook takes a while to run
|
# print hook and dots first in case the hook takes a while to run
|
||||||
output.write(get_hook_message(hook.name, end_len=6, cols=cols))
|
output.write(_start_msg(start=hook.name, end_len=6, cols=cols))
|
||||||
|
|
||||||
diff_cmd = ('git', 'diff', '--no-ext-diff')
|
diff_cmd = ('git', 'diff', '--no-ext-diff')
|
||||||
diff_before = cmd_output_b(*diff_cmd, retcode=None)
|
diff_before = cmd_output_b(*diff_cmd, retcode=None)
|
||||||
|
|
@ -218,9 +236,8 @@ def _run_hooks(
|
||||||
"""Actually run the hooks."""
|
"""Actually run the hooks."""
|
||||||
skips = _get_skips(environ)
|
skips = _get_skips(environ)
|
||||||
cols = _compute_cols(hooks)
|
cols = _compute_cols(hooks)
|
||||||
filenames = _all_filenames(args)
|
|
||||||
filenames = filter_by_include_exclude(
|
filenames = filter_by_include_exclude(
|
||||||
filenames, config['files'], config['exclude'],
|
_all_filenames(args), config['files'], config['exclude'],
|
||||||
)
|
)
|
||||||
classifier = Classifier(filenames)
|
classifier = Classifier(filenames)
|
||||||
retval = 0
|
retval = 0
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
|
from typing import Optional
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
from aspy.yaml import ordered_dump
|
from aspy.yaml import ordered_dump
|
||||||
|
|
@ -18,9 +19,9 @@ from pre_commit.xargs import xargs
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def _repo_ref(tmpdir: str, repo: str, ref: str) -> Tuple[str, str]:
|
def _repo_ref(tmpdir: str, repo: str, ref: Optional[str]) -> Tuple[str, str]:
|
||||||
# if `ref` is explicitly passed, use it
|
# if `ref` is explicitly passed, use it
|
||||||
if ref:
|
if ref is not None:
|
||||||
return repo, ref
|
return repo, ref
|
||||||
|
|
||||||
ref = git.head_rev(repo)
|
ref = git.head_rev(repo)
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,7 @@ else: # pragma: no cover (PY38+)
|
||||||
CONFIG_FILE = '.pre-commit-config.yaml'
|
CONFIG_FILE = '.pre-commit-config.yaml'
|
||||||
MANIFEST_FILE = '.pre-commit-hooks.yaml'
|
MANIFEST_FILE = '.pre-commit-hooks.yaml'
|
||||||
|
|
||||||
YAML_DUMP_KWARGS = {
|
YAML_DUMP_KWARGS = {'default_flow_style': False, 'indent': 4}
|
||||||
'default_flow_style': False,
|
|
||||||
# Use unicode
|
|
||||||
'encoding': None,
|
|
||||||
'indent': 4,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Bump when installation changes in a backwards / forwards incompatible way
|
# Bump when installation changes in a backwards / forwards incompatible way
|
||||||
INSTALLED_STATE_VERSION = '1'
|
INSTALLED_STATE_VERSION = '1'
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import functools
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
from pre_commit import output
|
from pre_commit import output
|
||||||
|
|
@ -15,22 +15,13 @@ class FatalError(RuntimeError):
|
||||||
|
|
||||||
|
|
||||||
def _log_and_exit(msg: str, exc: BaseException, formatted: str) -> None:
|
def _log_and_exit(msg: str, exc: BaseException, formatted: str) -> None:
|
||||||
error_msg = b''.join((
|
error_msg = f'{msg}: {type(exc).__name__}: {exc}'
|
||||||
msg.encode(), b': ',
|
output.write_line(error_msg)
|
||||||
type(exc).__name__.encode(), b': ',
|
log_path = os.path.join(Store().directory, 'pre-commit.log')
|
||||||
str(exc).encode(),
|
|
||||||
))
|
|
||||||
output.write_line_b(error_msg)
|
|
||||||
store = Store()
|
|
||||||
log_path = os.path.join(store.directory, 'pre-commit.log')
|
|
||||||
output.write_line(f'Check the log at {log_path}')
|
output.write_line(f'Check the log at {log_path}')
|
||||||
|
|
||||||
with open(log_path, 'wb') as log:
|
with open(log_path, 'wb') as log:
|
||||||
def _log_line(s: Optional[str] = None) -> None:
|
_log_line = functools.partial(output.write_line, stream=log)
|
||||||
output.write_line(s, stream=log)
|
|
||||||
|
|
||||||
def _log_line_b(s: Optional[bytes] = None) -> None:
|
|
||||||
output.write_line_b(s, stream=log)
|
|
||||||
|
|
||||||
_log_line('### version information')
|
_log_line('### version information')
|
||||||
_log_line()
|
_log_line()
|
||||||
|
|
@ -48,7 +39,7 @@ def _log_and_exit(msg: str, exc: BaseException, formatted: str) -> None:
|
||||||
_log_line('### error information')
|
_log_line('### error information')
|
||||||
_log_line()
|
_log_line()
|
||||||
_log_line('```')
|
_log_line('```')
|
||||||
_log_line_b(error_msg)
|
_log_line(error_msg)
|
||||||
_log_line('```')
|
_log_line('```')
|
||||||
_log_line()
|
_log_line()
|
||||||
_log_line('```')
|
_log_line('```')
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ def head_rev(remote: str) -> str:
|
||||||
|
|
||||||
|
|
||||||
def has_diff(*args: str, repo: str = '.') -> bool:
|
def has_diff(*args: str, repo: str = '.') -> bool:
|
||||||
cmd = ('git', 'diff', '--quiet', '--no-ext-diff') + args
|
cmd = ('git', 'diff', '--quiet', '--no-ext-diff', *args)
|
||||||
return cmd_output_b(*cmd, cwd=repo, retcode=None)[0] == 1
|
return cmd_output_b(*cmd, cwd=repo, retcode=None)[0] == 1
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,9 @@ def get_env_patch(env: str) -> PatchesT:
|
||||||
# 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 os.name == 'nt': # pragma: no cover (platform specific)
|
||||||
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)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
('PYTHONHOME', UNSET),
|
('PYTHONHOME', UNSET),
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,6 @@ def run_hook(
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> Tuple[int, bytes]:
|
||||||
out = hook.entry.encode() + b'\n\n'
|
out = f'{hook.entry}\n\n'.encode()
|
||||||
out += b'\n'.join(f.encode() for f in file_args) + b'\n'
|
out += b'\n'.join(f.encode() for f in file_args) + b'\n'
|
||||||
return 1, out
|
return 1, out
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ def install_environment(
|
||||||
|
|
||||||
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx?f=255&MSPPError=-2147217396#maxpath
|
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx?f=255&MSPPError=-2147217396#maxpath
|
||||||
if sys.platform == 'win32': # pragma: no cover
|
if sys.platform == 'win32': # pragma: no cover
|
||||||
envdir = '\\\\?\\' + os.path.normpath(envdir)
|
envdir = f'\\\\?\\{os.path.normpath(envdir)}'
|
||||||
with clean_path_on_failure(envdir):
|
with clean_path_on_failure(envdir):
|
||||||
cmd = [
|
cmd = [
|
||||||
sys.executable, '-mnodeenv', '--prebuilt', '--clean-src', envdir,
|
sys.executable, '-mnodeenv', '--prebuilt', '--clean-src', envdir,
|
||||||
|
|
@ -83,7 +83,7 @@ def install_environment(
|
||||||
helpers.run_setup_cmd(prefix, ('npm', 'install'))
|
helpers.run_setup_cmd(prefix, ('npm', 'install'))
|
||||||
helpers.run_setup_cmd(
|
helpers.run_setup_cmd(
|
||||||
prefix,
|
prefix,
|
||||||
('npm', 'install', '-g', '.') + additional_dependencies,
|
('npm', 'install', '-g', '.', *additional_dependencies),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,8 @@ def _find_by_py_launcher(
|
||||||
if version.startswith('python'):
|
if version.startswith('python'):
|
||||||
num = version[len('python'):]
|
num = version[len('python'):]
|
||||||
try:
|
try:
|
||||||
return cmd_output(
|
cmd = ('py', f'-{num}', '-c', 'import sys; print(sys.executable)')
|
||||||
'py', f'-{num}', '-c', 'import sys; print(sys.executable)',
|
return cmd_output(*cmd)[1].strip()
|
||||||
)[1].strip()
|
|
||||||
except CalledProcessError:
|
except CalledProcessError:
|
||||||
pass
|
pass
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
|
|
@ -109,12 +109,14 @@ def install_environment(
|
||||||
# Need to call this after installing to set up the shims
|
# Need to call this after installing to set up the shims
|
||||||
helpers.run_setup_cmd(prefix, ('rbenv', 'rehash'))
|
helpers.run_setup_cmd(prefix, ('rbenv', 'rehash'))
|
||||||
helpers.run_setup_cmd(
|
helpers.run_setup_cmd(
|
||||||
prefix, ('gem', 'build') + prefix.star('.gemspec'),
|
prefix, ('gem', 'build', *prefix.star('.gemspec')),
|
||||||
)
|
)
|
||||||
helpers.run_setup_cmd(
|
helpers.run_setup_cmd(
|
||||||
prefix,
|
prefix,
|
||||||
('gem', 'install', '--no-document') +
|
(
|
||||||
prefix.star('.gem') + additional_dependencies,
|
'gem', 'install', '--no-document',
|
||||||
|
*prefix.star('.gem'), *additional_dependencies,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,7 @@ healthy = helpers.basic_healthy
|
||||||
|
|
||||||
def get_env_patch(target_dir: str) -> PatchesT:
|
def get_env_patch(target_dir: str) -> PatchesT:
|
||||||
return (
|
return (
|
||||||
(
|
('PATH', (os.path.join(target_dir, 'bin'), os.pathsep, Var('PATH'))),
|
||||||
'PATH',
|
|
||||||
(os.path.join(target_dir, 'bin'), os.pathsep, Var('PATH')),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,5 @@ def run_hook(
|
||||||
file_args: Sequence[str],
|
file_args: Sequence[str],
|
||||||
color: bool,
|
color: bool,
|
||||||
) -> Tuple[int, bytes]:
|
) -> Tuple[int, bytes]:
|
||||||
cmd = hook.cmd
|
cmd = (hook.prefix.path(hook.cmd[0]), *hook.cmd[1:])
|
||||||
cmd = (hook.prefix.path(cmd[0]),) + cmd[1:]
|
|
||||||
return helpers.run_xargs(hook, cmd, file_args, color=color)
|
return helpers.run_xargs(hook, cmd, file_args, color=color)
|
||||||
|
|
|
||||||
|
|
@ -329,7 +329,8 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
|
||||||
return install(
|
return install(
|
||||||
args.config, store,
|
args.config, store,
|
||||||
hook_types=args.hook_types,
|
hook_types=args.hook_types,
|
||||||
overwrite=args.overwrite, hooks=args.install_hooks,
|
overwrite=args.overwrite,
|
||||||
|
hooks=args.install_hooks,
|
||||||
skip_on_missing_config=args.allow_missing_config,
|
skip_on_missing_config=args.allow_missing_config,
|
||||||
)
|
)
|
||||||
elif args.command == 'init-templatedir':
|
elif args.command == 'init-templatedir':
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ def make_archive(name: str, repo: str, ref: str, destdir: str) -> str:
|
||||||
:param text ref: Tag/SHA/branch to check out.
|
:param text ref: Tag/SHA/branch to check out.
|
||||||
:param text destdir: Directory to place archives in.
|
:param text destdir: Directory to place archives in.
|
||||||
"""
|
"""
|
||||||
output_path = os.path.join(destdir, name + '.tar.gz')
|
output_path = os.path.join(destdir, f'{name}.tar.gz')
|
||||||
with tmpdir() as tempdir:
|
with tmpdir() as tempdir:
|
||||||
# Clone the repository to the temporary directory
|
# Clone the repository to the temporary directory
|
||||||
cmd_output_b('git', 'clone', repo, tempdir)
|
cmd_output_b('git', 'clone', repo, tempdir)
|
||||||
|
|
@ -56,9 +56,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
|
||||||
parser.add_argument('--dest', default='pre_commit/resources')
|
parser.add_argument('--dest', default='pre_commit/resources')
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
for archive_name, repo, ref in REPOS:
|
for archive_name, repo, ref in REPOS:
|
||||||
output.write_line(
|
output.write_line(f'Making {archive_name}.tar.gz for {repo}@{ref}')
|
||||||
f'Making {archive_name}.tar.gz for {repo}@{ref}',
|
|
||||||
)
|
|
||||||
make_archive(archive_name, repo, ref, args.dest)
|
make_archive(archive_name, repo, ref, args.dest)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,59 +4,6 @@ from typing import Any
|
||||||
from typing import IO
|
from typing import IO
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from pre_commit import color
|
|
||||||
|
|
||||||
|
|
||||||
def get_hook_message(
|
|
||||||
start: str,
|
|
||||||
postfix: str = '',
|
|
||||||
end_msg: Optional[str] = None,
|
|
||||||
end_len: int = 0,
|
|
||||||
end_color: Optional[str] = None,
|
|
||||||
use_color: Optional[bool] = None,
|
|
||||||
cols: int = 80,
|
|
||||||
) -> str:
|
|
||||||
"""Prints a message for running a hook.
|
|
||||||
|
|
||||||
This currently supports three approaches:
|
|
||||||
|
|
||||||
# Print `start` followed by dots, leaving 6 characters at the end
|
|
||||||
>>> print_hook_message('start', end_len=6)
|
|
||||||
start...............................................................
|
|
||||||
|
|
||||||
# Print `start` followed by dots with the end message colored if coloring
|
|
||||||
# is specified and a newline afterwards
|
|
||||||
>>> print_hook_message(
|
|
||||||
'start',
|
|
||||||
end_msg='end',
|
|
||||||
end_color=color.RED,
|
|
||||||
use_color=True,
|
|
||||||
)
|
|
||||||
start...................................................................end
|
|
||||||
|
|
||||||
# Print `start` followed by dots, followed by the `postfix` message
|
|
||||||
# uncolored, followed by the `end_msg` colored if specified and a newline
|
|
||||||
# afterwards
|
|
||||||
>>> print_hook_message(
|
|
||||||
'start',
|
|
||||||
postfix='postfix ',
|
|
||||||
end_msg='end',
|
|
||||||
end_color=color.RED,
|
|
||||||
use_color=True,
|
|
||||||
)
|
|
||||||
start...........................................................postfix end
|
|
||||||
"""
|
|
||||||
if end_len:
|
|
||||||
assert end_msg is None, end_msg
|
|
||||||
return start + '.' * (cols - len(start) - end_len - 1)
|
|
||||||
else:
|
|
||||||
assert end_msg is not None
|
|
||||||
assert end_color is not None
|
|
||||||
assert use_color is not None
|
|
||||||
dots = '.' * (cols - len(start) - len(postfix) - len(end_msg) - 1)
|
|
||||||
end = color.format_color(end_msg, end_color, use_color)
|
|
||||||
return f'{start}{dots}{postfix}{end}\n'
|
|
||||||
|
|
||||||
|
|
||||||
def write(s: str, stream: IO[bytes] = sys.stdout.buffer) -> None:
|
def write(s: str, stream: IO[bytes] = sys.stdout.buffer) -> None:
|
||||||
stream.write(s.encode())
|
stream.write(s.encode())
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,7 @@ def parse_filename(filename: str) -> Tuple[str, ...]:
|
||||||
|
|
||||||
|
|
||||||
def find_executable(
|
def find_executable(
|
||||||
exe: str,
|
exe: str, _environ: Optional[Mapping[str, str]] = None,
|
||||||
_environ: Optional[Mapping[str, str]] = None,
|
|
||||||
) -> Optional[str]:
|
) -> Optional[str]:
|
||||||
exe = os.path.normpath(exe)
|
exe = os.path.normpath(exe)
|
||||||
if os.sep in exe:
|
if os.sep in exe:
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ def _state(additional_deps: Sequence[str]) -> object:
|
||||||
|
|
||||||
|
|
||||||
def _state_filename(prefix: Prefix, venv: str) -> str:
|
def _state_filename(prefix: Prefix, venv: str) -> str:
|
||||||
return prefix.path(venv, '.install_state_v' + C.INSTALLED_STATE_VERSION)
|
return prefix.path(venv, f'.install_state_v{C.INSTALLED_STATE_VERSION}')
|
||||||
|
|
||||||
|
|
||||||
def _read_state(prefix: Prefix, venv: str) -> Optional[object]:
|
def _read_state(prefix: Prefix, venv: str) -> Optional[object]:
|
||||||
|
|
@ -46,7 +46,7 @@ def _read_state(prefix: Prefix, venv: str) -> Optional[object]:
|
||||||
|
|
||||||
def _write_state(prefix: Prefix, venv: str, state: object) -> None:
|
def _write_state(prefix: Prefix, venv: str, state: object) -> None:
|
||||||
state_filename = _state_filename(prefix, venv)
|
state_filename = _state_filename(prefix, venv)
|
||||||
staging = state_filename + 'staging'
|
staging = f'{state_filename}staging'
|
||||||
with open(staging, 'w') as state_file:
|
with open(staging, 'w') as state_file:
|
||||||
state_file.write(json.dumps(state))
|
state_file.write(json.dumps(state))
|
||||||
# Move the file into place atomically to indicate we've installed
|
# Move the file into place atomically to indicate we've installed
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,7 @@ def _unstaged_changes_cleared(patch_dir: str) -> Generator[None, None, None]:
|
||||||
patch_filename = f'patch{int(time.time())}'
|
patch_filename = f'patch{int(time.time())}'
|
||||||
patch_filename = os.path.join(patch_dir, patch_filename)
|
patch_filename = os.path.join(patch_dir, patch_filename)
|
||||||
logger.warning('Unstaged files detected.')
|
logger.warning('Unstaged files detected.')
|
||||||
logger.info(
|
logger.info(f'Stashing unstaged files to {patch_filename}.')
|
||||||
f'Stashing unstaged files to {patch_filename}.',
|
|
||||||
)
|
|
||||||
# Save the current unstaged changes as a patch
|
# Save the current unstaged changes as a patch
|
||||||
os.makedirs(patch_dir, exist_ok=True)
|
os.makedirs(patch_dir, exist_ok=True)
|
||||||
with open(patch_filename, 'wb') as patch_file:
|
with open(patch_filename, 'wb') as patch_file:
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,12 @@ import pytest
|
||||||
from pre_commit import envcontext
|
from pre_commit import envcontext
|
||||||
from pre_commit.color import format_color
|
from pre_commit.color import format_color
|
||||||
from pre_commit.color import GREEN
|
from pre_commit.color import GREEN
|
||||||
from pre_commit.color import InvalidColorSetting
|
|
||||||
from pre_commit.color import use_color
|
from pre_commit.color import use_color
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
('in_text', 'in_color', 'in_use_color', 'expected'), (
|
('in_text', 'in_color', 'in_use_color', 'expected'), (
|
||||||
('foo', GREEN, True, f'{GREEN}foo\033[0m'),
|
('foo', GREEN, True, f'{GREEN}foo\033[m'),
|
||||||
('foo', GREEN, False, 'foo'),
|
('foo', GREEN, False, 'foo'),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -56,5 +55,5 @@ def test_use_color_dumb_term():
|
||||||
|
|
||||||
|
|
||||||
def test_use_color_raises_if_given_shenanigans():
|
def test_use_color_raises_if_given_shenanigans():
|
||||||
with pytest.raises(InvalidColorSetting):
|
with pytest.raises(ValueError):
|
||||||
use_color('herpaderp')
|
use_color('herpaderp')
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ def test_is_script():
|
||||||
|
|
||||||
def test_is_previous_pre_commit(tmpdir):
|
def test_is_previous_pre_commit(tmpdir):
|
||||||
f = tmpdir.join('foo')
|
f = tmpdir.join('foo')
|
||||||
f.write(PRIOR_HASHES[0] + '\n')
|
f.write(f'{PRIOR_HASHES[0]}\n')
|
||||||
assert is_our_script(f.strpath)
|
assert is_our_script(f.strpath)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -129,11 +129,11 @@ FILES_CHANGED = (
|
||||||
|
|
||||||
|
|
||||||
NORMAL_PRE_COMMIT_RUN = re.compile(
|
NORMAL_PRE_COMMIT_RUN = re.compile(
|
||||||
r'^\[INFO\] Initializing environment for .+\.\n'
|
fr'^\[INFO\] Initializing environment for .+\.\n'
|
||||||
r'Bash hook\.+Passed\n'
|
fr'Bash hook\.+Passed\n'
|
||||||
r'\[master [a-f0-9]{7}\] commit!\n' +
|
fr'\[master [a-f0-9]{{7}}\] commit!\n'
|
||||||
FILES_CHANGED +
|
fr'{FILES_CHANGED}'
|
||||||
r' create mode 100644 foo\n$',
|
fr' create mode 100644 foo\n$',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -296,10 +296,10 @@ def test_failing_hooks_returns_nonzero(tempdir_factory, store):
|
||||||
|
|
||||||
|
|
||||||
EXISTING_COMMIT_RUN = re.compile(
|
EXISTING_COMMIT_RUN = re.compile(
|
||||||
r'^legacy hook\n'
|
fr'^legacy hook\n'
|
||||||
r'\[master [a-f0-9]{7}\] commit!\n' +
|
fr'\[master [a-f0-9]{{7}}\] commit!\n'
|
||||||
FILES_CHANGED +
|
fr'{FILES_CHANGED}'
|
||||||
r' create mode 100644 baz\n$',
|
fr' create mode 100644 baz\n$',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -453,10 +453,10 @@ def test_uninstall_doesnt_remove_not_our_hooks(in_git_dir):
|
||||||
|
|
||||||
|
|
||||||
PRE_INSTALLED = re.compile(
|
PRE_INSTALLED = re.compile(
|
||||||
r'Bash hook\.+Passed\n'
|
fr'Bash hook\.+Passed\n'
|
||||||
r'\[master [a-f0-9]{7}\] commit!\n' +
|
fr'\[master [a-f0-9]{{7}}\] commit!\n'
|
||||||
FILES_CHANGED +
|
fr'{FILES_CHANGED}'
|
||||||
r' create mode 100644 foo\n$',
|
fr' create mode 100644 foo\n$',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,13 @@ from unittest import mock
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import pre_commit.constants as C
|
import pre_commit.constants as C
|
||||||
|
from pre_commit import color
|
||||||
from pre_commit.commands.install_uninstall import install
|
from pre_commit.commands.install_uninstall import install
|
||||||
from pre_commit.commands.run import _compute_cols
|
from pre_commit.commands.run import _compute_cols
|
||||||
|
from pre_commit.commands.run import _full_msg
|
||||||
from pre_commit.commands.run import _get_skips
|
from pre_commit.commands.run import _get_skips
|
||||||
from pre_commit.commands.run import _has_unmerged_paths
|
from pre_commit.commands.run import _has_unmerged_paths
|
||||||
|
from pre_commit.commands.run import _start_msg
|
||||||
from pre_commit.commands.run import Classifier
|
from pre_commit.commands.run import Classifier
|
||||||
from pre_commit.commands.run import filter_by_include_exclude
|
from pre_commit.commands.run import filter_by_include_exclude
|
||||||
from pre_commit.commands.run import run
|
from pre_commit.commands.run import run
|
||||||
|
|
@ -29,6 +32,62 @@ from testing.util import git_commit
|
||||||
from testing.util import run_opts
|
from testing.util import run_opts
|
||||||
|
|
||||||
|
|
||||||
|
def test_start_msg():
|
||||||
|
ret = _start_msg(start='start', end_len=5, cols=15)
|
||||||
|
# 4 dots: 15 - 5 - 5 - 1
|
||||||
|
assert ret == 'start....'
|
||||||
|
|
||||||
|
|
||||||
|
def test_full_msg():
|
||||||
|
ret = _full_msg(
|
||||||
|
start='start',
|
||||||
|
end_msg='end',
|
||||||
|
end_color='',
|
||||||
|
use_color=False,
|
||||||
|
cols=15,
|
||||||
|
)
|
||||||
|
# 6 dots: 15 - 5 - 3 - 1
|
||||||
|
assert ret == 'start......end\n'
|
||||||
|
|
||||||
|
|
||||||
|
def test_full_msg_with_color():
|
||||||
|
ret = _full_msg(
|
||||||
|
start='start',
|
||||||
|
end_msg='end',
|
||||||
|
end_color=color.RED,
|
||||||
|
use_color=True,
|
||||||
|
cols=15,
|
||||||
|
)
|
||||||
|
# 6 dots: 15 - 5 - 3 - 1
|
||||||
|
assert ret == f'start......{color.RED}end{color.NORMAL}\n'
|
||||||
|
|
||||||
|
|
||||||
|
def test_full_msg_with_postfix():
|
||||||
|
ret = _full_msg(
|
||||||
|
start='start',
|
||||||
|
postfix='post ',
|
||||||
|
end_msg='end',
|
||||||
|
end_color='',
|
||||||
|
use_color=False,
|
||||||
|
cols=20,
|
||||||
|
)
|
||||||
|
# 6 dots: 20 - 5 - 5 - 3 - 1
|
||||||
|
assert ret == 'start......post end\n'
|
||||||
|
|
||||||
|
|
||||||
|
def test_full_msg_postfix_not_colored():
|
||||||
|
ret = _full_msg(
|
||||||
|
start='start',
|
||||||
|
postfix='post ',
|
||||||
|
end_msg='end',
|
||||||
|
end_color=color.RED,
|
||||||
|
use_color=True,
|
||||||
|
cols=20,
|
||||||
|
)
|
||||||
|
# 6 dots: 20 - 5 - 5 - 3 - 1
|
||||||
|
assert ret == f'start......post {color.RED}end{color.NORMAL}\n'
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def repo_with_passing_hook(tempdir_factory):
|
def repo_with_passing_hook(tempdir_factory):
|
||||||
git_path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
|
git_path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
|
||||||
|
|
@ -173,7 +232,7 @@ def test_global_exclude(cap_out, store, in_git_dir):
|
||||||
ret, printed = _do_run(cap_out, store, str(in_git_dir), opts)
|
ret, printed = _do_run(cap_out, store, str(in_git_dir), opts)
|
||||||
assert ret == 0
|
assert ret == 0
|
||||||
# Does not contain foo.py since it was excluded
|
# Does not contain foo.py since it was excluded
|
||||||
assert printed.startswith(b'identity' + b'.' * 65 + b'Passed\n')
|
assert printed.startswith(f'identity{"." * 65}Passed\n'.encode())
|
||||||
assert printed.endswith(b'\n\n.pre-commit-config.yaml\nbar.py\n\n')
|
assert printed.endswith(b'\n\n.pre-commit-config.yaml\nbar.py\n\n')
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -190,7 +249,7 @@ def test_global_files(cap_out, store, in_git_dir):
|
||||||
ret, printed = _do_run(cap_out, store, str(in_git_dir), opts)
|
ret, printed = _do_run(cap_out, store, str(in_git_dir), opts)
|
||||||
assert ret == 0
|
assert ret == 0
|
||||||
# Does not contain foo.py since it was excluded
|
# Does not contain foo.py since it was excluded
|
||||||
assert printed.startswith(b'identity' + b'.' * 65 + b'Passed\n')
|
assert printed.startswith(f'identity{"." * 65}Passed\n'.encode())
|
||||||
assert printed.endswith(b'\n\nbar.py\n\n')
|
assert printed.endswith(b'\n\nbar.py\n\n')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ def try_repo_opts(repo, ref=None, **kwargs):
|
||||||
|
|
||||||
def _get_out(cap_out):
|
def _get_out(cap_out):
|
||||||
out = re.sub(r'\[INFO\].+\n', '', cap_out.get())
|
out = re.sub(r'\[INFO\].+\n', '', cap_out.get())
|
||||||
start, using_config, config, rest = out.split('=' * 79 + '\n')
|
start, using_config, config, rest = out.split(f'{"=" * 79}\n')
|
||||||
assert using_config == 'Using config:\n'
|
assert using_config == 'Using config:\n'
|
||||||
return start, config, rest
|
return start, config, rest
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,6 @@ def test_error_handler_no_tty(tempdir_factory):
|
||||||
ret, out, _ = cmd_output_mocked_pre_commit_home(
|
ret, out, _ = cmd_output_mocked_pre_commit_home(
|
||||||
sys.executable,
|
sys.executable,
|
||||||
'-c',
|
'-c',
|
||||||
'from __future__ import unicode_literals\n'
|
|
||||||
'from pre_commit.error_handler import error_handler\n'
|
'from pre_commit.error_handler import error_handler\n'
|
||||||
'with error_handler():\n'
|
'with error_handler():\n'
|
||||||
' raise ValueError("\\u2603")\n',
|
' raise ValueError("\\u2603")\n',
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ def test_norm_version_expanduser():
|
||||||
expected_path = fr'{home}\python343'
|
expected_path = fr'{home}\python343'
|
||||||
else: # pragma: windows no cover
|
else: # pragma: windows no cover
|
||||||
path = '~/.pyenv/versions/3.4.3/bin/python'
|
path = '~/.pyenv/versions/3.4.3/bin/python'
|
||||||
expected_path = 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)
|
||||||
assert result == expected_path
|
assert result == expected_path
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ def test_logging_handler_color(cap_out):
|
||||||
handler = LoggingHandler(True)
|
handler = LoggingHandler(True)
|
||||||
handler.emit(_log_record('hi', logging.WARNING))
|
handler.emit(_log_record('hi', logging.WARNING))
|
||||||
ret = cap_out.get()
|
ret = cap_out.get()
|
||||||
assert ret == color.YELLOW + '[WARNING]' + color.NORMAL + ' hi\n'
|
assert ret == f'{color.YELLOW}[WARNING]{color.NORMAL} hi\n'
|
||||||
|
|
||||||
|
|
||||||
def test_logging_handler_no_color(cap_out):
|
def test_logging_handler_no_color(cap_out):
|
||||||
|
|
|
||||||
|
|
@ -1,85 +1,9 @@
|
||||||
from unittest import mock
|
import io
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from pre_commit import color
|
|
||||||
from pre_commit import output
|
from pre_commit import output
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
'kwargs',
|
|
||||||
(
|
|
||||||
# both end_msg and end_len
|
|
||||||
{'end_msg': 'end', 'end_len': 1, 'end_color': '', 'use_color': True},
|
|
||||||
# Neither end_msg nor end_len
|
|
||||||
{},
|
|
||||||
# Neither color option for end_msg
|
|
||||||
{'end_msg': 'end'},
|
|
||||||
# No use_color for end_msg
|
|
||||||
{'end_msg': 'end', 'end_color': ''},
|
|
||||||
# No end_color for end_msg
|
|
||||||
{'end_msg': 'end', 'use_color': ''},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
def test_get_hook_message_raises(kwargs):
|
|
||||||
with pytest.raises(AssertionError):
|
|
||||||
output.get_hook_message('start', **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def test_case_with_end_len():
|
|
||||||
ret = output.get_hook_message('start', end_len=5, cols=15)
|
|
||||||
assert ret == 'start' + '.' * 4
|
|
||||||
|
|
||||||
|
|
||||||
def test_case_with_end_msg():
|
|
||||||
ret = output.get_hook_message(
|
|
||||||
'start',
|
|
||||||
end_msg='end',
|
|
||||||
end_color='',
|
|
||||||
use_color=False,
|
|
||||||
cols=15,
|
|
||||||
)
|
|
||||||
assert ret == 'start' + '.' * 6 + 'end' + '\n'
|
|
||||||
|
|
||||||
|
|
||||||
def test_case_with_end_msg_using_color():
|
|
||||||
ret = output.get_hook_message(
|
|
||||||
'start',
|
|
||||||
end_msg='end',
|
|
||||||
end_color=color.RED,
|
|
||||||
use_color=True,
|
|
||||||
cols=15,
|
|
||||||
)
|
|
||||||
assert ret == 'start' + '.' * 6 + color.RED + 'end' + color.NORMAL + '\n'
|
|
||||||
|
|
||||||
|
|
||||||
def test_case_with_postfix_message():
|
|
||||||
ret = output.get_hook_message(
|
|
||||||
'start',
|
|
||||||
postfix='post ',
|
|
||||||
end_msg='end',
|
|
||||||
end_color='',
|
|
||||||
use_color=False,
|
|
||||||
cols=20,
|
|
||||||
)
|
|
||||||
assert ret == 'start' + '.' * 6 + 'post ' + 'end' + '\n'
|
|
||||||
|
|
||||||
|
|
||||||
def test_make_sure_postfix_is_not_colored():
|
|
||||||
ret = output.get_hook_message(
|
|
||||||
'start',
|
|
||||||
postfix='post ',
|
|
||||||
end_msg='end',
|
|
||||||
end_color=color.RED,
|
|
||||||
use_color=True,
|
|
||||||
cols=20,
|
|
||||||
)
|
|
||||||
assert ret == (
|
|
||||||
'start' + '.' * 6 + 'post ' + color.RED + 'end' + color.NORMAL + '\n'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_output_write_writes():
|
def test_output_write_writes():
|
||||||
fake_stream = mock.Mock()
|
stream = io.BytesIO()
|
||||||
output.write('hello world', fake_stream)
|
output.write('hello world', stream)
|
||||||
assert fake_stream.write.call_count == 1
|
assert stream.getvalue() == b'hello world'
|
||||||
|
|
|
||||||
|
|
@ -94,9 +94,9 @@ def test_foo_something_unstaged_diff_color_always(foo_staged, patch_dir):
|
||||||
|
|
||||||
def test_foo_both_modify_non_conflicting(foo_staged, patch_dir):
|
def test_foo_both_modify_non_conflicting(foo_staged, patch_dir):
|
||||||
with open(foo_staged.foo_filename, 'w') as foo_file:
|
with open(foo_staged.foo_filename, 'w') as foo_file:
|
||||||
foo_file.write(FOO_CONTENTS + '9\n')
|
foo_file.write(f'{FOO_CONTENTS}9\n')
|
||||||
|
|
||||||
_test_foo_state(foo_staged, FOO_CONTENTS + '9\n', 'AM')
|
_test_foo_state(foo_staged, f'{FOO_CONTENTS}9\n', 'AM')
|
||||||
|
|
||||||
with staged_files_only(patch_dir):
|
with staged_files_only(patch_dir):
|
||||||
_test_foo_state(foo_staged)
|
_test_foo_state(foo_staged)
|
||||||
|
|
@ -107,7 +107,7 @@ def test_foo_both_modify_non_conflicting(foo_staged, patch_dir):
|
||||||
|
|
||||||
_test_foo_state(foo_staged, FOO_CONTENTS.replace('1', 'a'), 'AM')
|
_test_foo_state(foo_staged, FOO_CONTENTS.replace('1', 'a'), 'AM')
|
||||||
|
|
||||||
_test_foo_state(foo_staged, FOO_CONTENTS.replace('1', 'a') + '9\n', 'AM')
|
_test_foo_state(foo_staged, f'{FOO_CONTENTS.replace("1", "a")}9\n', 'AM')
|
||||||
|
|
||||||
|
|
||||||
def test_foo_both_modify_conflicting(foo_staged, patch_dir):
|
def test_foo_both_modify_conflicting(foo_staged, patch_dir):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue