Hello community,
here is the log from the commit of package python-pre-commit for
openSUSE:Factory checked in at 2020-08-31 16:50:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pre-commit (Old)
and /work/SRC/openSUSE:Factory/.python-pre-commit.new.3399 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pre-commit"
Mon Aug 31 16:50:34 2020 rev:5 rq:830498 version:2.7.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pre-commit/python-pre-commit.changes
2020-07-20 21:01:20.801091420 +0200
+++
/work/SRC/openSUSE:Factory/.python-pre-commit.new.3399/python-pre-commit.changes
2020-08-31 16:50:59.324375905 +0200
@@ -1,0 +2,34 @@
+Sat Aug 29 05:38:23 UTC 2020 - Arun Persaud <[email protected]
+
+- update to version 2.7.1:
+ * Fixes
+ + Improve performance of docker hooks by removing slow ps call
+ #1572 PR by @rkm.
+ #1569 issue by @asottile.
+ + Fix un-healthy() invalidation followed by install being reported
+ as un-healthy().
+ #1576 PR by @asottile.
+ #1575 issue by @jab.
+ + Fix rare file race condition on windows with os.replace()
+ #1577 PR by @asottile.
+
+- changes from version 2.7.0:
+ * Features
+ + Produce error message if an environment is immediately unhealthy
+ #1535 PR by @asottile.
+ + Add --no-allow-missing-config option to init-templatedir
+ #1539 PR by @singergr.
+ + Add warning for old list-style configuration
+ #1544 PR by @asottile.
+ + Allow pre-commit to succeed on a readonly store.
+ #1570 PR by @asottile.
+ #1536 issue by @asottile.
+ * Fixes
+ + Fix error messaging when the store directory is readonly
+ #1546 PR by @asottile.
+ #1536 issue by @asottile.
+ + Improve diff performance with many hooks
+ #1566 PR by @jhenkens.
+ #1564 issue by @jhenkens.
+
+-------------------------------------------------------------------
Old:
----
pre_commit-2.6.0.tar.gz
New:
----
pre_commit-2.7.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pre-commit.spec ++++++
--- /var/tmp/diff_new_pack.oyumQz/_old 2020-08-31 16:51:00.316376385 +0200
+++ /var/tmp/diff_new_pack.oyumQz/_new 2020-08-31 16:51:00.320376387 +0200
@@ -19,7 +19,7 @@
%define skip_python2 1
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-pre-commit
-Version: 2.6.0
+Version: 2.7.1
Release: 0
Summary: Multi-language pre-commit hooks
License: MIT
++++++ pre_commit-2.6.0.tar.gz -> pre_commit-2.7.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/.pre-commit-config.yaml
new/pre-commit-2.7.1/.pre-commit-config.yaml
--- old/pre-commit-2.6.0/.pre-commit-config.yaml 2020-07-01
21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/.pre-commit-config.yaml 2020-08-23
19:53:21.000000000 +0200
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v2.5.0
+ rev: v3.1.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@@ -12,20 +12,20 @@
- id: requirements-txt-fixer
- id: double-quote-string-fixer
- repo: https://gitlab.com/pycqa/flake8
- rev: 3.8.0
+ rev: 3.8.3
hooks:
- id: flake8
additional_dependencies: [flake8-typing-imports==1.6.0]
- repo: https://github.com/pre-commit/mirrors-autopep8
- rev: v1.5.2
+ rev: v1.5.3
hooks:
- id: autopep8
- repo: https://github.com/pre-commit/pre-commit
- rev: v2.4.0
+ rev: v2.6.0
hooks:
- id: validate_manifest
- repo: https://github.com/asottile/pyupgrade
- rev: v2.4.1
+ rev: v2.6.2
hooks:
- id: pyupgrade
args: [--py36-plus]
@@ -40,11 +40,11 @@
- id: add-trailing-comma
args: [--py36-plus]
- repo: https://github.com/asottile/setup-cfg-fmt
- rev: v1.9.0
+ rev: v1.10.0
hooks:
- id: setup-cfg-fmt
- repo: https://github.com/pre-commit/mirrors-mypy
- rev: v0.770
+ rev: v0.782
hooks:
- id: mypy
exclude: ^testing/resources/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/CHANGELOG.md
new/pre-commit-2.7.1/CHANGELOG.md
--- old/pre-commit-2.6.0/CHANGELOG.md 2020-07-01 21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/CHANGELOG.md 2020-08-23 19:53:21.000000000 +0200
@@ -1,3 +1,40 @@
+2.7.1 - 2020-08-23
+==================
+
+### Fixes
+- Improve performance of docker hooks by removing slow `ps` call
+ - #1572 PR by @rkm.
+ - #1569 issue by @asottile.
+- Fix un-`healthy()` invalidation followed by install being reported as
+ un-`healthy()`.
+ - #1576 PR by @asottile.
+ - #1575 issue by @jab.
+- Fix rare file race condition on windows with `os.replace()`
+ - #1577 PR by @asottile.
+
+2.7.0 - 2020-08-22
+==================
+
+### Features
+- Produce error message if an environment is immediately unhealthy
+ - #1535 PR by @asottile.
+- Add --no-allow-missing-config option to init-templatedir
+ - #1539 PR by @singergr.
+- Add warning for old list-style configuration
+ - #1544 PR by @asottile.
+- Allow pre-commit to succeed on a readonly store.
+ - #1570 PR by @asottile.
+ - #1536 issue by @asottile.
+
+### Fixes
+- Fix error messaging when the store directory is readonly
+ - #1546 PR by @asottile.
+ - #1536 issue by @asottile.
+- Improve `diff` performance with many hooks
+ - #1566 PR by @jhenkens.
+ - #1564 issue by @jhenkens.
+
+
2.6.0 - 2020-07-01
==================
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/pre_commit/clientlib.py
new/pre-commit-2.7.1/pre_commit/clientlib.py
--- old/pre-commit-2.6.0/pre_commit/clientlib.py 2020-07-01
21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/pre_commit/clientlib.py 2020-08-23
19:53:21.000000000 +0200
@@ -12,8 +12,10 @@
from identify.identify import ALL_TAGS
import pre_commit.constants as C
+from pre_commit.color import add_color_option
from pre_commit.error_handler import FatalError
from pre_commit.languages.all import all_languages
+from pre_commit.logging_handler import logging_handler
from pre_commit.util import parse_version
from pre_commit.util import yaml_load
@@ -43,6 +45,7 @@
parser = argparse.ArgumentParser()
parser.add_argument('filenames', nargs='*', help=filenames_help)
parser.add_argument('-V', '--version', action='version', version=C.VERSION)
+ add_color_option(parser)
return parser
@@ -92,14 +95,16 @@
def validate_manifest_main(argv: Optional[Sequence[str]] = None) -> int:
parser = _make_argparser('Manifest filenames.')
args = parser.parse_args(argv)
- ret = 0
- for filename in args.filenames:
- try:
- load_manifest(filename)
- except InvalidManifestError as e:
- print(e)
- ret = 1
- return ret
+
+ with logging_handler(args.color):
+ ret = 0
+ for filename in args.filenames:
+ try:
+ load_manifest(filename)
+ except InvalidManifestError as e:
+ print(e)
+ ret = 1
+ return ret
LOCAL = 'local'
@@ -290,7 +295,11 @@
def ordered_load_normalize_legacy_config(contents: str) -> Dict[str, Any]:
data = yaml_load(contents)
if isinstance(data, list):
- # TODO: Once happy, issue a deprecation warning and instructions
+ logger.warning(
+ 'normalizing pre-commit configuration to a top-level map. '
+ 'support for top level list will be removed in a future version. '
+ 'run: `pre-commit migrate-config` to automatically fix this.',
+ )
return {'repos': data}
else:
return data
@@ -307,11 +316,13 @@
def validate_config_main(argv: Optional[Sequence[str]] = None) -> int:
parser = _make_argparser('Config filenames.')
args = parser.parse_args(argv)
- ret = 0
- for filename in args.filenames:
- try:
- load_config(filename)
- except InvalidConfigError as e:
- print(e)
- ret = 1
- return ret
+
+ with logging_handler(args.color):
+ ret = 0
+ for filename in args.filenames:
+ try:
+ load_config(filename)
+ except InvalidConfigError as e:
+ print(e)
+ ret = 1
+ return ret
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/pre_commit/color.py
new/pre-commit-2.7.1/pre_commit/color.py
--- old/pre-commit-2.6.0/pre_commit/color.py 2020-07-01 21:39:34.000000000
+0200
+++ new/pre-commit-2.7.1/pre_commit/color.py 2020-08-23 19:53:21.000000000
+0200
@@ -1,3 +1,4 @@
+import argparse
import os
import sys
@@ -95,3 +96,12 @@
os.getenv('TERM') != 'dumb'
)
)
+
+
+def add_color_option(parser: argparse.ArgumentParser) -> None:
+ parser.add_argument(
+ '--color', default=os.environ.get('PRE_COMMIT_COLOR', 'auto'),
+ type=use_color,
+ metavar='{' + ','.join(COLOR_CHOICES) + '}',
+ help='Whether to use color in output. Defaults to `%(default)s`.',
+ )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pre-commit-2.6.0/pre_commit/commands/init_templatedir.py
new/pre-commit-2.7.1/pre_commit/commands/init_templatedir.py
--- old/pre-commit-2.6.0/pre_commit/commands/init_templatedir.py
2020-07-01 21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/pre_commit/commands/init_templatedir.py
2020-08-23 19:53:21.000000000 +0200
@@ -15,10 +15,15 @@
store: Store,
directory: str,
hook_types: Sequence[str],
+ skip_on_missing_config: bool = True,
) -> int:
install(
- config_file, store, hook_types=hook_types,
- overwrite=True, skip_on_missing_config=True, git_dir=directory,
+ config_file,
+ store,
+ hook_types=hook_types,
+ overwrite=True,
+ skip_on_missing_config=skip_on_missing_config,
+ git_dir=directory,
)
try:
_, out, _ = cmd_output('git', 'config', 'init.templateDir')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pre-commit-2.6.0/pre_commit/commands/install_uninstall.py
new/pre-commit-2.7.1/pre_commit/commands/install_uninstall.py
--- old/pre-commit-2.6.0/pre_commit/commands/install_uninstall.py
2020-07-01 21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/pre_commit/commands/install_uninstall.py
2020-08-23 19:53:21.000000000 +0200
@@ -165,7 +165,7 @@
output.write_line(f'{hook_type} uninstalled')
if os.path.exists(legacy_path):
- os.rename(legacy_path, hook_path)
+ os.replace(legacy_path, hook_path)
output.write_line(f'Restored previous hooks to {hook_path}')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/pre_commit/commands/run.py
new/pre-commit-2.7.1/pre_commit/commands/run.py
--- old/pre-commit-2.6.0/pre_commit/commands/run.py 2020-07-01
21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/pre_commit/commands/run.py 2020-08-23
19:53:21.000000000 +0200
@@ -134,9 +134,10 @@
hook: Hook,
skips: Set[str],
cols: int,
+ diff_before: bytes,
verbose: bool,
use_color: bool,
-) -> bool:
+) -> Tuple[bool, bytes]:
filenames = classifier.filenames_for_hook(hook)
if hook.id in skips or hook.alias in skips:
@@ -151,6 +152,7 @@
)
duration = None
retcode = 0
+ diff_after = diff_before
files_modified = False
out = b''
elif not filenames and not hook.always_run:
@@ -166,21 +168,20 @@
)
duration = None
retcode = 0
+ diff_after = diff_before
files_modified = False
out = b''
else:
# print hook and dots first in case the hook takes a while to run
output.write(_start_msg(start=hook.name, end_len=6, cols=cols))
- diff_cmd = ('git', 'diff', '--no-ext-diff')
- diff_before = cmd_output_b(*diff_cmd, retcode=None)
if not hook.pass_filenames:
filenames = ()
time_before = time.time()
language = languages[hook.language]
retcode, out = language.run_hook(hook, filenames, use_color)
duration = round(time.time() - time_before, 2) or 0
- diff_after = cmd_output_b(*diff_cmd, retcode=None)
+ diff_after = _get_diff()
# if the hook makes changes, fail the commit
files_modified = diff_before != diff_after
@@ -212,7 +213,7 @@
output.write_line_b(out.strip(), logfile_name=hook.log_file)
output.write_line()
- return files_modified or bool(retcode)
+ return files_modified or bool(retcode), diff_after
def _compute_cols(hooks: Sequence[Hook]) -> int:
@@ -248,6 +249,11 @@
return git.get_staged_files()
+def _get_diff() -> bytes:
+ _, out, _ = cmd_output_b('git', 'diff', '--no-ext-diff', retcode=None)
+ return out
+
+
def _run_hooks(
config: Dict[str, Any],
hooks: Sequence[Hook],
@@ -261,14 +267,16 @@
_all_filenames(args), config['files'], config['exclude'],
)
retval = 0
+ prior_diff = _get_diff()
for hook in hooks:
- retval |= _run_single_hook(
- classifier, hook, skips, cols,
+ current_retval, prior_diff = _run_single_hook(
+ classifier, hook, skips, cols, prior_diff,
verbose=args.verbose, use_color=args.color,
)
+ retval |= current_retval
if retval and config['fail_fast']:
break
- if retval and args.show_diff_on_failure and git.has_diff():
+ if retval and args.show_diff_on_failure and prior_diff:
if args.all_files:
output.write_line(
'pre-commit hook(s) made changes.\n'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/pre_commit/error_handler.py
new/pre-commit-2.7.1/pre_commit/error_handler.py
--- old/pre-commit-2.6.0/pre_commit/error_handler.py 2020-07-01
21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/pre_commit/error_handler.py 2020-08-23
19:53:21.000000000 +0200
@@ -18,10 +18,17 @@
def _log_and_exit(msg: str, exc: BaseException, formatted: str) -> None:
error_msg = f'{msg}: {type(exc).__name__}: '.encode() + force_bytes(exc)
output.write_line_b(error_msg)
- log_path = os.path.join(Store().directory, 'pre-commit.log')
- output.write_line(f'Check the log at {log_path}')
- with open(log_path, 'wb') as log:
+ storedir = Store().directory
+ log_path = os.path.join(storedir, 'pre-commit.log')
+ with contextlib.ExitStack() as ctx:
+ if os.access(storedir, os.W_OK):
+ output.write_line(f'Check the log at {log_path}')
+ log = ctx.enter_context(open(log_path, 'wb'))
+ else: # pragma: win32 no cover
+ output.write_line(f'Failed to write to log at {log_path}')
+ log = sys.stdout.buffer
+
_log_line = functools.partial(output.write_line, stream=log)
_log_line_b = functools.partial(output.write_line_b, stream=log)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/pre_commit/file_lock.py
new/pre-commit-2.7.1/pre_commit/file_lock.py
--- old/pre-commit-2.6.0/pre_commit/file_lock.py 2020-07-01
21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/pre_commit/file_lock.py 2020-08-23
19:53:21.000000000 +0200
@@ -21,13 +21,13 @@
) -> Generator[None, None, None]:
try:
# TODO: https://github.com/python/typeshed/pull/3607
- msvcrt.locking(fileno, msvcrt.LK_NBLCK, _region) # type: ignore
+ msvcrt.locking(fileno, msvcrt.LK_NBLCK, _region)
except OSError:
blocked_cb()
while True:
try:
# TODO: https://github.com/python/typeshed/pull/3607
- msvcrt.locking(fileno, msvcrt.LK_LOCK, _region) # type:
ignore # noqa: E501
+ msvcrt.locking(fileno, msvcrt.LK_LOCK, _region)
except OSError as e:
# Locking violation. Returned when the _LK_LOCK or _LK_RLCK
# flag is specified and the file cannot be locked after 10
@@ -46,7 +46,7 @@
# "Regions should be locked only briefly and should be unlocked
# before closing a file or exiting the program."
# TODO: https://github.com/python/typeshed/pull/3607
- msvcrt.locking(fileno, msvcrt.LK_UNLCK, _region) # type: ignore
+ msvcrt.locking(fileno, msvcrt.LK_UNLCK, _region)
else: # pragma: win32 no cover
import fcntl
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/pre_commit/languages/docker.py
new/pre-commit-2.7.1/pre_commit/languages/docker.py
--- old/pre-commit-2.6.0/pre_commit/languages/docker.py 2020-07-01
21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/pre_commit/languages/docker.py 2020-08-23
19:53:21.000000000 +0200
@@ -7,9 +7,7 @@
from pre_commit.hook import Hook
from pre_commit.languages import helpers
from pre_commit.prefix import Prefix
-from pre_commit.util import CalledProcessError
from pre_commit.util import clean_path_on_failure
-from pre_commit.util import cmd_output_b
ENVIRONMENT_DIR = 'docker'
PRE_COMMIT_LABEL = 'PRE_COMMIT'
@@ -26,21 +24,6 @@
return f'pre-commit-{md5sum}'
-def docker_is_running() -> bool: # pragma: win32 no cover
- try:
- cmd_output_b('docker', 'ps')
- except CalledProcessError:
- return False
- else:
- return True
-
-
-def assert_docker_available() -> None: # pragma: win32 no cover
- assert docker_is_running(), (
- 'Docker is either not running or not configured in this environment'
- )
-
-
def build_docker_image(
prefix: Prefix,
*,
@@ -63,7 +46,6 @@
) -> None: # pragma: win32 no cover
helpers.assert_version_default('docker', version)
helpers.assert_no_additional_deps('docker', additional_dependencies)
- assert_docker_available()
directory = prefix.path(
helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT),
@@ -101,7 +83,6 @@
file_args: Sequence[str],
color: bool,
) -> Tuple[int, bytes]: # pragma: win32 no cover
- assert_docker_available()
# Rebuild the docker image in case it has gone missing, as many people do
# automated cleanup of docker images.
build_docker_image(hook.prefix, pull=False)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pre-commit-2.6.0/pre_commit/languages/docker_image.py
new/pre-commit-2.7.1/pre_commit/languages/docker_image.py
--- old/pre-commit-2.6.0/pre_commit/languages/docker_image.py 2020-07-01
21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/pre_commit/languages/docker_image.py 2020-08-23
19:53:21.000000000 +0200
@@ -3,7 +3,6 @@
from pre_commit.hook import Hook
from pre_commit.languages import helpers
-from pre_commit.languages.docker import assert_docker_available
from pre_commit.languages.docker import docker_cmd
ENVIRONMENT_DIR = None
@@ -17,6 +16,5 @@
file_args: Sequence[str],
color: bool,
) -> Tuple[int, bytes]: # pragma: win32 no cover
- assert_docker_available()
cmd = docker_cmd() + hook.cmd
return helpers.run_xargs(hook, cmd, file_args, color=color)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/pre_commit/languages/python.py
new/pre-commit-2.7.1/pre_commit/languages/python.py
--- old/pre-commit-2.6.0/pre_commit/languages/python.py 2020-07-01
21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/pre_commit/languages/python.py 2020-08-23
19:53:21.000000000 +0200
@@ -191,7 +191,8 @@
return (
'version_info' in cfg and
- _version_info(py_exe) == cfg['version_info'] and (
+ # always use uncached lookup here in case we replaced an unhealthy env
+ _version_info.__wrapped__(py_exe) == cfg['version_info'] and (
'base-executable' not in cfg or
_version_info(cfg['base-executable']) == cfg['version_info']
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/pre_commit/main.py
new/pre-commit-2.7.1/pre_commit/main.py
--- old/pre-commit-2.6.0/pre_commit/main.py 2020-07-01 21:39:34.000000000
+0200
+++ new/pre-commit-2.7.1/pre_commit/main.py 2020-08-23 19:53:21.000000000
+0200
@@ -8,8 +8,8 @@
from typing import Union
import pre_commit.constants as C
-from pre_commit import color
from pre_commit import git
+from pre_commit.color import add_color_option
from pre_commit.commands.autoupdate import autoupdate
from pre_commit.commands.clean import clean
from pre_commit.commands.gc import gc
@@ -41,15 +41,6 @@
COMMANDS_NO_GIT = {'clean', 'gc', 'init-templatedir', 'sample-config'}
-def _add_color_option(parser: argparse.ArgumentParser) -> None:
- parser.add_argument(
- '--color', default=os.environ.get('PRE_COMMIT_COLOR', 'auto'),
- type=color.use_color,
- metavar='{' + ','.join(color.COLOR_CHOICES) + '}',
- help='Whether to use color in output. Defaults to `%(default)s`.',
- )
-
-
def _add_config_option(parser: argparse.ArgumentParser) -> None:
parser.add_argument(
'-c', '--config', default=C.CONFIG_FILE,
@@ -195,7 +186,7 @@
'autoupdate',
help="Auto-update pre-commit config to the latest repos' versions.",
)
- _add_color_option(autoupdate_parser)
+ add_color_option(autoupdate_parser)
_add_config_option(autoupdate_parser)
autoupdate_parser.add_argument(
'--bleeding-edge', action='store_true',
@@ -216,11 +207,11 @@
clean_parser = subparsers.add_parser(
'clean', help='Clean out pre-commit files.',
)
- _add_color_option(clean_parser)
+ add_color_option(clean_parser)
_add_config_option(clean_parser)
hook_impl_parser = subparsers.add_parser('hook-impl')
- _add_color_option(hook_impl_parser)
+ add_color_option(hook_impl_parser)
_add_config_option(hook_impl_parser)
hook_impl_parser.add_argument('--hook-type')
hook_impl_parser.add_argument('--hook-dir')
@@ -230,7 +221,7 @@
hook_impl_parser.add_argument(dest='rest', nargs=argparse.REMAINDER)
gc_parser = subparsers.add_parser('gc', help='Clean unused cached repos.')
- _add_color_option(gc_parser)
+ add_color_option(gc_parser)
_add_config_option(gc_parser)
init_templatedir_parser = subparsers.add_parser(
@@ -240,17 +231,23 @@
'`git config init.templateDir`.'
),
)
- _add_color_option(init_templatedir_parser)
+ add_color_option(init_templatedir_parser)
_add_config_option(init_templatedir_parser)
init_templatedir_parser.add_argument(
'directory', help='The directory in which to write the hook script.',
)
+ init_templatedir_parser.add_argument(
+ '--no-allow-missing-config',
+ action='store_false',
+ dest='allow_missing_config',
+ help='Assume cloned repos should have a `pre-commit` config.',
+ )
_add_hook_type_option(init_templatedir_parser)
install_parser = subparsers.add_parser(
'install', help='Install the pre-commit script.',
)
- _add_color_option(install_parser)
+ add_color_option(install_parser)
_add_config_option(install_parser)
install_parser.add_argument(
'-f', '--overwrite', action='store_true',
@@ -280,32 +277,32 @@
'useful.'
),
)
- _add_color_option(install_hooks_parser)
+ add_color_option(install_hooks_parser)
_add_config_option(install_hooks_parser)
migrate_config_parser = subparsers.add_parser(
'migrate-config',
help='Migrate list configuration to new map configuration.',
)
- _add_color_option(migrate_config_parser)
+ add_color_option(migrate_config_parser)
_add_config_option(migrate_config_parser)
run_parser = subparsers.add_parser('run', help='Run hooks.')
- _add_color_option(run_parser)
+ add_color_option(run_parser)
_add_config_option(run_parser)
_add_run_options(run_parser)
sample_config_parser = subparsers.add_parser(
'sample-config', help=f'Produce a sample {C.CONFIG_FILE} file',
)
- _add_color_option(sample_config_parser)
+ add_color_option(sample_config_parser)
_add_config_option(sample_config_parser)
try_repo_parser = subparsers.add_parser(
'try-repo',
help='Try the hooks in a repository, useful for developing new hooks.',
)
- _add_color_option(try_repo_parser)
+ add_color_option(try_repo_parser)
_add_config_option(try_repo_parser)
try_repo_parser.add_argument(
'repo', help='Repository to source hooks from.',
@@ -322,7 +319,7 @@
uninstall_parser = subparsers.add_parser(
'uninstall', help='Uninstall the pre-commit script.',
)
- _add_color_option(uninstall_parser)
+ add_color_option(uninstall_parser)
_add_config_option(uninstall_parser)
_add_hook_type_option(uninstall_parser)
@@ -383,6 +380,7 @@
return init_templatedir(
args.config, store, args.directory,
hook_types=args.hook_types,
+ skip_on_missing_config=args.allow_missing_config,
)
elif args.command == 'install-hooks':
return install_hooks(args.config, store)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/pre_commit/repository.py
new/pre-commit-2.7.1/pre_commit/repository.py
--- old/pre-commit-2.6.0/pre_commit/repository.py 2020-07-01
21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/pre_commit/repository.py 2020-08-23
19:53:21.000000000 +0200
@@ -48,7 +48,7 @@
with open(staging, 'w') as state_file:
state_file.write(json.dumps(state))
# Move the file into place atomically to indicate we've installed
- os.rename(staging, state_filename)
+ os.replace(staging, state_filename)
def _hook_installed(hook: Hook) -> bool:
@@ -82,6 +82,12 @@
lang.install_environment(
hook.prefix, hook.language_version, hook.additional_dependencies,
)
+ if not lang.healthy(hook.prefix, hook.language_version):
+ raise AssertionError(
+ f'BUG: expected environment for {hook.language} to be healthy() '
+ f'immediately after install, please open an issue describing '
+ f'your environment',
+ )
# Write our state to indicate we're installed
_write_state(hook.prefix, venv, _state(hook.additional_dependencies))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/pre_commit/store.py
new/pre-commit-2.7.1/pre_commit/store.py
--- old/pre-commit-2.6.0/pre_commit/store.py 2020-07-01 21:39:34.000000000
+0200
+++ new/pre-commit-2.7.1/pre_commit/store.py 2020-08-23 19:53:21.000000000
+0200
@@ -43,6 +43,10 @@
def __init__(self, directory: Optional[str] = None) -> None:
self.directory = directory or Store.get_default_directory()
self.db_path = os.path.join(self.directory, 'db.db')
+ self.readonly = (
+ os.path.exists(self.directory) and
+ not os.access(self.directory, os.W_OK)
+ )
if not os.path.exists(self.directory):
os.makedirs(self.directory, exist_ok=True)
@@ -75,7 +79,7 @@
self._create_config_table(db)
# Atomic file move
- os.rename(tmpfile, self.db_path)
+ os.replace(tmpfile, self.db_path)
@contextlib.contextmanager
def exclusive_lock(self) -> Generator[None, None, None]:
@@ -218,6 +222,8 @@
)
def mark_config_used(self, path: str) -> None:
+ if self.readonly: # pragma: win32 no cover
+ return
path = os.path.realpath(path)
# don't insert config files that do not exist
if not os.path.exists(path):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/setup.cfg
new/pre-commit-2.7.1/setup.cfg
--- old/pre-commit-2.6.0/setup.cfg 2020-07-01 21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/setup.cfg 2020-08-23 19:53:21.000000000 +0200
@@ -1,6 +1,6 @@
[metadata]
name = pre_commit
-version = 2.6.0
+version = 2.7.1
description = A framework for managing and maintaining multi-language
pre-commit hooks.
long_description = file: README.md
long_description_content_type = text/markdown
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/testing/util.py
new/pre-commit-2.7.1/testing/util.py
--- old/pre-commit-2.6.0/testing/util.py 2020-07-01 21:39:34.000000000
+0200
+++ new/pre-commit-2.7.1/testing/util.py 2020-08-23 19:53:21.000000000
+0200
@@ -5,14 +5,24 @@
import pytest
from pre_commit import parse_shebang
-from pre_commit.languages.docker import docker_is_running
+from pre_commit.util import CalledProcessError
from pre_commit.util import cmd_output
+from pre_commit.util import cmd_output_b
from testing.auto_namedtuple import auto_namedtuple
TESTING_DIR = os.path.abspath(os.path.dirname(__file__))
+def docker_is_running() -> bool: # pragma: win32 no cover
+ try:
+ cmd_output_b('docker', 'ps')
+ except CalledProcessError: # pragma: no cover
+ return False
+ else:
+ return True
+
+
def get_resource_path(path):
return os.path.join(TESTING_DIR, 'resources', path)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/tests/clientlib_test.py
new/pre-commit-2.7.1/tests/clientlib_test.py
--- old/pre-commit-2.6.0/tests/clientlib_test.py 2020-07-01
21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/tests/clientlib_test.py 2020-08-23
19:53:21.000000000 +0200
@@ -30,6 +30,10 @@
check_type_tag(value)
+def test_check_type_tag_success():
+ check_type_tag('file')
+
+
@pytest.mark.parametrize(
('config_obj', 'expected'), (
(
@@ -110,15 +114,18 @@
assert not validate_config_main(('.pre-commit-config.yaml',))
-def test_validate_config_old_list_format_ok(tmpdir):
+def test_validate_config_old_list_format_ok(tmpdir, cap_out):
f = tmpdir.join('cfg.yaml')
f.write('- {repo: meta, hooks: [{id: identity}]}')
assert not validate_config_main((f.strpath,))
+ start = '[WARNING] normalizing pre-commit configuration to a top-level map'
+ assert cap_out.get().startswith(start)
def test_validate_warn_on_unknown_keys_at_repo_level(tmpdir, caplog):
f = tmpdir.join('cfg.yaml')
f.write(
+ 'repos:\n'
'- repo: https://gitlab.com/pycqa/flake8\n'
' rev: 3.7.7\n'
' hooks:\n'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pre-commit-2.6.0/tests/commands/init_templatedir_test.py
new/pre-commit-2.7.1/tests/commands/init_templatedir_test.py
--- old/pre-commit-2.6.0/tests/commands/init_templatedir_test.py
2020-07-01 21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/tests/commands/init_templatedir_test.py
2020-08-23 19:53:21.000000000 +0200
@@ -1,6 +1,8 @@
import os.path
from unittest import mock
+import pytest
+
import pre_commit.constants as C
from pre_commit.commands.init_templatedir import init_templatedir
from pre_commit.envcontext import envcontext
@@ -90,3 +92,49 @@
C.CONFIG_FILE, store, target, hook_types=['pre-commit'],
)
assert target.join('hooks/pre-commit').exists()
+
+
[email protected](
+ ('skip', 'commit_retcode', 'commit_output_snippet'),
+ (
+ (True, 0, 'Skipping `pre-commit`.'),
+ (False, 1, f'No {C.CONFIG_FILE} file was found'),
+ ),
+)
+def test_init_templatedir_skip_on_missing_config(
+ tmpdir,
+ tempdir_factory,
+ store,
+ cap_out,
+ skip,
+ commit_retcode,
+ commit_output_snippet,
+):
+ target = str(tmpdir.join('tmpl'))
+ init_git_dir = git_dir(tempdir_factory)
+ with cwd(init_git_dir):
+ cmd_output('git', 'config', 'init.templateDir', target)
+ init_templatedir(
+ C.CONFIG_FILE,
+ store,
+ target,
+ hook_types=['pre-commit'],
+ skip_on_missing_config=skip,
+ )
+
+ lines = cap_out.get().splitlines()
+ assert len(lines) == 1
+ assert lines[0].startswith('pre-commit installed at')
+
+ with envcontext((('GIT_TEMPLATE_DIR', target),)):
+ verify_git_dir = git_dir(tempdir_factory)
+
+ with cwd(verify_git_dir):
+ retcode, output = git_commit(
+ fn=cmd_output_mocked_pre_commit_home,
+ tempdir_factory=tempdir_factory,
+ retcode=None,
+ )
+
+ assert retcode == commit_retcode
+ assert commit_output_snippet in output
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/tests/error_handler_test.py
new/pre-commit-2.7.1/tests/error_handler_test.py
--- old/pre-commit-2.6.0/tests/error_handler_test.py 2020-07-01
21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/tests/error_handler_test.py 2020-08-23
19:53:21.000000000 +0200
@@ -1,13 +1,16 @@
import os.path
import re
+import stat
import sys
from unittest import mock
import pytest
from pre_commit import error_handler
+from pre_commit.store import Store
from pre_commit.util import CalledProcessError
from testing.util import cmd_output_mocked_pre_commit_home
+from testing.util import xfailif_windows
@pytest.fixture
@@ -168,3 +171,29 @@
out_lines = out.splitlines()
assert out_lines[-2] == 'An unexpected error has occurred: ValueError: ☃'
assert out_lines[-1] == f'Check the log at {log_file}'
+
+
+@xfailif_windows # pragma: win32 no cover
+def test_error_handler_read_only_filesystem(mock_store_dir, cap_out, capsys):
+ # a better scenario would be if even the Store crash would be handled
+ # but realistically we're only targetting systems where the Store has
+ # already been set up
+ Store()
+
+ write = (stat.S_IWGRP | stat.S_IWOTH | stat.S_IWUSR)
+ os.chmod(mock_store_dir, os.stat(mock_store_dir).st_mode & ~write)
+
+ with pytest.raises(SystemExit):
+ with error_handler.error_handler():
+ raise ValueError('ohai')
+
+ output = cap_out.get()
+ assert output.startswith(
+ 'An unexpected error has occurred: ValueError: ohai\n'
+ 'Failed to write to log at ',
+ )
+
+ # our cap_out mock is imperfect so the rest of the output goes to capsys
+ out, _ = capsys.readouterr()
+ # the things that normally go to the log file will end up here
+ assert '### version information' in out
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/tests/languages/docker_test.py
new/pre-commit-2.7.1/tests/languages/docker_test.py
--- old/pre-commit-2.6.0/tests/languages/docker_test.py 2020-07-01
21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/tests/languages/docker_test.py 2020-08-23
19:53:21.000000000 +0200
@@ -1,15 +1,6 @@
from unittest import mock
from pre_commit.languages import docker
-from pre_commit.util import CalledProcessError
-
-
-def test_docker_is_running_process_error():
- with mock.patch(
- 'pre_commit.languages.docker.cmd_output_b',
- side_effect=CalledProcessError(1, (), 0, b'', None),
- ):
- assert docker.docker_is_running() is False
def test_docker_fallback_user():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/tests/languages/python_test.py
new/pre-commit-2.7.1/tests/languages/python_test.py
--- old/pre-commit-2.6.0/tests/languages/python_test.py 2020-07-01
21:39:34.000000000 +0200
+++ new/pre-commit-2.7.1/tests/languages/python_test.py 2020-08-23
19:53:21.000000000 +0200
@@ -8,6 +8,7 @@
from pre_commit.envcontext import envcontext
from pre_commit.languages import python
from pre_commit.prefix import Prefix
+from pre_commit.util import make_executable
def test_read_pyvenv_cfg(tmpdir):
@@ -141,3 +142,26 @@
os.remove(prefix.path('py_env-default/pyvenv.cfg'))
assert python.healthy(prefix, C.DEFAULT) is False
+
+
+def test_unhealthy_then_replaced(python_dir):
+ prefix, tmpdir = python_dir
+
+ python.install_environment(prefix, C.DEFAULT, ())
+
+ # simulate an exe which returns an old version
+ exe_name = 'python.exe' if sys.platform == 'win32' else 'python'
+ py_exe = prefix.path(python.bin_dir('py_env-default'), exe_name)
+ os.rename(py_exe, f'{py_exe}.tmp')
+
+ with open(py_exe, 'w') as f:
+ f.write('#!/usr/bin/env bash\necho 1.2.3\n')
+ make_executable(py_exe)
+
+ # should be unhealthy due to version mismatch
+ assert python.healthy(prefix, C.DEFAULT) is False
+
+ # now put the exe back and it should be healthy again
+ os.replace(f'{py_exe}.tmp', py_exe)
+
+ assert python.healthy(prefix, C.DEFAULT) is True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/tests/main_test.py
new/pre-commit-2.7.1/tests/main_test.py
--- old/pre-commit-2.6.0/tests/main_test.py 2020-07-01 21:39:34.000000000
+0200
+++ new/pre-commit-2.7.1/tests/main_test.py 2020-08-23 19:53:21.000000000
+0200
@@ -159,7 +159,28 @@
def test_init_templatedir(mock_store_dir):
with mock.patch.object(main, 'init_templatedir') as patch:
main.main(('init-templatedir', 'tdir'))
+
+ assert patch.call_count == 1
+ assert 'tdir' in patch.call_args[0]
+ assert patch.call_args[1]['hook_types'] == ['pre-commit']
+ assert patch.call_args[1]['skip_on_missing_config'] is True
+
+
+def test_init_templatedir_options(mock_store_dir):
+ args = (
+ 'init-templatedir',
+ 'tdir',
+ '--hook-type',
+ 'commit-msg',
+ '--no-allow-missing-config',
+ )
+ with mock.patch.object(main, 'init_templatedir') as patch:
+ main.main(args)
+
assert patch.call_count == 1
+ assert 'tdir' in patch.call_args[0]
+ assert patch.call_args[1]['hook_types'] == ['commit-msg']
+ assert patch.call_args[1]['skip_on_missing_config'] is False
def test_help_cmd_in_empty_directory(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pre-commit-2.6.0/tests/store_test.py
new/pre-commit-2.7.1/tests/store_test.py
--- old/pre-commit-2.6.0/tests/store_test.py 2020-07-01 21:39:34.000000000
+0200
+++ new/pre-commit-2.7.1/tests/store_test.py 2020-08-23 19:53:21.000000000
+0200
@@ -1,5 +1,6 @@
import os.path
import sqlite3
+import stat
from unittest import mock
import pytest
@@ -12,6 +13,7 @@
from testing.fixtures import git_dir
from testing.util import cwd
from testing.util import git_commit
+from testing.util import xfailif_windows
def test_our_session_fixture_works():
@@ -217,3 +219,27 @@
def test_mark_config_as_used_roll_forward(store, tmpdir):
_simulate_pre_1_14_0(store)
test_mark_config_as_used(store, tmpdir)
+
+
+@xfailif_windows # pragma: win32 no cover
+def test_mark_config_as_used_readonly(tmpdir):
+ cfg = tmpdir.join('f').ensure()
+ store_dir = tmpdir.join('store')
+ # make a store, then we'll convert its directory to be readonly
+ assert not Store(str(store_dir)).readonly # directory didn't exist
+ assert not Store(str(store_dir)).readonly # directory did exist
+
+ def _chmod_minus_w(p):
+ st = os.stat(p)
+ os.chmod(p, st.st_mode & ~(stat.S_IWUSR | stat.S_IWOTH | stat.S_IWGRP))
+
+ _chmod_minus_w(store_dir)
+ for fname in os.listdir(store_dir):
+ assert not os.path.isdir(fname)
+ _chmod_minus_w(os.path.join(store_dir, fname))
+
+ store = Store(str(store_dir))
+ assert store.readonly
+ # should be skipped due to readonly
+ store.mark_config_used(str(cfg))
+ assert store.select_all_configs() == []