1
0
Fork 0

Merging upstream version 2.20.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-09 21:34:34 +01:00
parent 65a743ec23
commit eea7a7b6f9
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
18 changed files with 165 additions and 87 deletions

View file

@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.2.0
rev: v4.3.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@ -14,7 +14,7 @@ repos:
hooks:
- id: setup-cfg-fmt
- repo: https://github.com/asottile/reorder_python_imports
rev: v3.1.0
rev: v3.3.0
hooks:
- id: reorder-python-imports
exclude: ^(pre_commit/resources/|testing/resources/python3_hooks_repo/)
@ -25,7 +25,7 @@ repos:
- id: add-trailing-comma
args: [--py36-plus]
- repo: https://github.com/asottile/pyupgrade
rev: v2.32.0
rev: v2.34.0
hooks:
- id: pyupgrade
args: [--py37-plus]
@ -38,7 +38,7 @@ repos:
hooks:
- id: flake8
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.950
rev: v0.961
hooks:
- id: mypy
additional_dependencies: [types-all]

View file

@ -1,3 +1,23 @@
2.20.0 - 2022-07-10
===================
### Features
- Expose `source` and `object-name` (positional args) of `prepare-commit-msg`
hook as `PRE_COMMIT_COMIT_MSG_SOURCE` and `PRE_COMMIT_COMMIT_OBJECT_NAME`.
- #2407 PR by @M-Whitaker.
- #2406 issue by @M-Whitaker.
### Fixes
- Fix `language: ruby` installs when `--user-install` is set in gemrc.
- #2394 PR by @narpfel.
- #2393 issue by @narpfel.
- Adjust pty setup for solaris.
- #2390 PR by @gaige.
- #2389 issue by @gaige.
- Remove unused `--config` option from `gc`, `sample-config`,
`validate-config`, `validate-manifest` sub-commands.
- #2429 PR by @asottile.
2.19.0 - 2022-05-05
===================

View file

@ -72,7 +72,7 @@ to implement. The current implemented languages are at varying levels:
- 3rd class - pre-commit requires the user to install both the tool and the
language globally (current examples: script, system)
"third class" is usually the easiest to implement first and is perfectly
"second class" is usually the easiest to implement first and is perfectly
acceptable.
Ideally the language works on the supported platforms for pre-commit (linux,

View file

@ -76,6 +76,8 @@ def _ns(
remote_name: str | None = None,
remote_url: str | None = None,
commit_msg_filename: str | None = None,
prepare_commit_message_source: str | None = None,
commit_object_name: str | None = None,
checkout_type: str | None = None,
is_squash_merge: str | None = None,
rewrite_command: str | None = None,
@ -90,6 +92,8 @@ def _ns(
remote_name=remote_name,
remote_url=remote_url,
commit_msg_filename=commit_msg_filename,
prepare_commit_message_source=prepare_commit_message_source,
commit_object_name=commit_object_name,
all_files=all_files,
checkout_type=checkout_type,
is_squash_merge=is_squash_merge,
@ -202,8 +206,20 @@ def _run_ns(
_check_args_length(hook_type, args)
if hook_type == 'pre-push':
return _pre_push_ns(color, args, stdin)
elif hook_type in {'commit-msg', 'prepare-commit-msg'}:
elif hook_type in 'commit-msg':
return _ns(hook_type, color, commit_msg_filename=args[0])
elif hook_type == 'prepare-commit-msg' and len(args) == 1:
return _ns(hook_type, color, commit_msg_filename=args[0])
elif hook_type == 'prepare-commit-msg' and len(args) == 2:
return _ns(
hook_type, color, commit_msg_filename=args[0],
prepare_commit_message_source=args[1],
)
elif hook_type == 'prepare-commit-msg' and len(args) == 3:
return _ns(
hook_type, color, commit_msg_filename=args[0],
prepare_commit_message_source=args[1], commit_object_name=args[2],
)
elif hook_type in {'post-commit', 'pre-merge-commit', 'pre-commit'}:
return _ns(hook_type, color)
elif hook_type == 'post-checkout':

View file

@ -361,6 +361,16 @@ def run(
):
return 0
# Expose prepare_commit_message_source / commit_object_name
# as environment variables for the hooks
if args.prepare_commit_message_source:
environ['PRE_COMMIT_COMMIT_MSG_SOURCE'] = (
args.prepare_commit_message_source
)
if args.commit_object_name:
environ['PRE_COMMIT_COMMIT_OBJECT_NAME'] = args.commit_object_name
# Expose from-ref / to-ref as environment variables for hooks to consume
if args.from_ref and args.to_ref:
# legacy names

View file

@ -5,9 +5,9 @@ import os
import random
import re
from typing import Any
from typing import NoReturn
from typing import overload
from typing import Sequence
from typing import TYPE_CHECKING
import pre_commit.constants as C
from pre_commit import parse_shebang
@ -16,9 +16,6 @@ from pre_commit.prefix import Prefix
from pre_commit.util import cmd_output_b
from pre_commit.xargs import xargs
if TYPE_CHECKING:
from typing import NoReturn
FIXED_RANDOM_SEED = 1542676187
SHIMS_RE = re.compile(r'[/\\]shims[/\\]')

View file

@ -138,6 +138,7 @@ def install_environment(
(
'gem', 'install',
'--no-document', '--no-format-executable',
'--no-user-install',
*prefix.star('.gem'), *additional_dependencies,
),
)

View file

@ -107,6 +107,20 @@ def _add_run_options(parser: argparse.ArgumentParser) -> None:
'--commit-msg-filename',
help='Filename to check when running during `commit-msg`',
)
parser.add_argument(
'--prepare-commit-message-source',
help=(
'Source of the commit message '
'(typically the second argument to .git/hooks/prepare-commit-msg)'
),
)
parser.add_argument(
'--commit-object-name',
help=(
'Commit object name '
'(typically the third argument to .git/hooks/prepare-commit-msg)'
),
)
parser.add_argument(
'--remote-name', help='Remote name used by `git push`.',
)
@ -167,11 +181,15 @@ def main(argv: Sequence[str] | None = None) -> int:
subparsers = parser.add_subparsers(dest='command')
autoupdate_parser = subparsers.add_parser(
def _add_cmd(name: str, *, help: str) -> argparse.ArgumentParser:
parser = subparsers.add_parser(name, help=help)
add_color_option(parser)
return parser
autoupdate_parser = _add_cmd(
'autoupdate',
help="Auto-update pre-commit config to the latest repos' versions.",
)
add_color_option(autoupdate_parser)
_add_config_option(autoupdate_parser)
autoupdate_parser.add_argument(
'--bleeding-edge', action='store_true',
@ -189,34 +207,17 @@ def main(argv: Sequence[str] | None = None) -> int:
help='Only update this repository -- may be specified multiple times.',
)
clean_parser = subparsers.add_parser(
'clean', help='Clean out pre-commit files.',
)
add_color_option(clean_parser)
_add_config_option(clean_parser)
_add_cmd('clean', help='Clean out pre-commit files.')
hook_impl_parser = subparsers.add_parser('hook-impl')
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')
hook_impl_parser.add_argument(
'--skip-on-missing-config', action='store_true',
)
hook_impl_parser.add_argument(dest='rest', nargs=argparse.REMAINDER)
_add_cmd('gc', help='Clean unused cached repos.')
gc_parser = subparsers.add_parser('gc', help='Clean unused cached repos.')
add_color_option(gc_parser)
_add_config_option(gc_parser)
init_templatedir_parser = subparsers.add_parser(
init_templatedir_parser = _add_cmd(
'init-templatedir',
help=(
'Install hook script in a directory intended for use with '
'`git config init.templateDir`.'
),
)
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.',
@ -229,10 +230,7 @@ def main(argv: Sequence[str] | None = None) -> int:
)
_add_hook_type_option(init_templatedir_parser)
install_parser = subparsers.add_parser(
'install', help='Install the pre-commit script.',
)
add_color_option(install_parser)
install_parser = _add_cmd('install', help='Install the pre-commit script.')
_add_config_option(install_parser)
install_parser.add_argument(
'-f', '--overwrite', action='store_true',
@ -254,7 +252,7 @@ def main(argv: Sequence[str] | None = None) -> int:
),
)
install_hooks_parser = subparsers.add_parser(
install_hooks_parser = _add_cmd(
'install-hooks',
help=(
'Install hook environments for all environments in the config '
@ -262,32 +260,24 @@ def main(argv: Sequence[str] | None = None) -> int:
'useful.'
),
)
add_color_option(install_hooks_parser)
_add_config_option(install_hooks_parser)
migrate_config_parser = subparsers.add_parser(
migrate_config_parser = _add_cmd(
'migrate-config',
help='Migrate list configuration to new map configuration.',
)
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)
run_parser = _add_cmd('run', help='Run hooks.')
_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_config_option(sample_config_parser)
_add_cmd('sample-config', help=f'Produce a sample {C.CONFIG_FILE} file')
try_repo_parser = subparsers.add_parser(
try_repo_parser = _add_cmd(
'try-repo',
help='Try the hooks in a repository, useful for developing new hooks.',
)
add_color_option(try_repo_parser)
_add_config_option(try_repo_parser)
try_repo_parser.add_argument(
'repo', help='Repository to source hooks from.',
@ -301,32 +291,39 @@ def main(argv: Sequence[str] | None = None) -> int:
)
_add_run_options(try_repo_parser)
uninstall_parser = subparsers.add_parser(
uninstall_parser = _add_cmd(
'uninstall', help='Uninstall the pre-commit script.',
)
add_color_option(uninstall_parser)
_add_config_option(uninstall_parser)
_add_hook_type_option(uninstall_parser)
validate_config_parser = subparsers.add_parser(
validate_config_parser = _add_cmd(
'validate-config', help='Validate .pre-commit-config.yaml files',
)
add_color_option(validate_config_parser)
_add_config_option(validate_config_parser)
validate_config_parser.add_argument('filenames', nargs='*')
validate_manifest_parser = subparsers.add_parser(
validate_manifest_parser = _add_cmd(
'validate-manifest', help='Validate .pre-commit-hooks.yaml files',
)
add_color_option(validate_manifest_parser)
_add_config_option(validate_manifest_parser)
validate_manifest_parser.add_argument('filenames', nargs='*')
# does not use `_add_cmd` because it doesn't use `--color`
help = subparsers.add_parser(
'help', help='Show help for a specific command.',
)
help.add_argument('help_cmd', nargs='?', help='Command to show help for.')
# not intended for users to call this directly
hook_impl_parser = subparsers.add_parser('hook-impl')
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')
hook_impl_parser.add_argument(
'--skip-on-missing-config', action='store_true',
)
hook_impl_parser.add_argument(dest='rest', nargs=argparse.REMAINDER)
# argparse doesn't really provide a way to use a `default` subparser
if len(argv) == 0:
argv = ['run']
@ -340,11 +337,11 @@ def main(argv: Sequence[str] | None = None) -> int:
with error_handler(), logging_handler(args.color):
git.check_for_cygwin_mismatch()
store = Store()
if args.command not in COMMANDS_NO_GIT:
_adjust_args_and_chdir(args)
store = Store()
store.mark_config_used(args.config)
store.mark_config_used(args.config)
if args.command == 'autoupdate':
return autoupdate(

View file

@ -2,13 +2,10 @@ from __future__ import annotations
import os.path
from typing import Mapping
from typing import TYPE_CHECKING
from typing import NoReturn
from identify.identify import parse_shebang_from_file
if TYPE_CHECKING:
from typing import NoReturn
class ExecutableNotFoundError(OSError):
def to_output(self) -> tuple[int, bytes, None]:

View file

@ -168,10 +168,10 @@ if os.name != 'nt': # pragma: win32 no cover
self.r, self.w = openpty()
# tty flags normally change \n to \r\n
attrs = termios.tcgetattr(self.r)
attrs = termios.tcgetattr(self.w)
assert isinstance(attrs[1], int)
attrs[1] &= ~(termios.ONLCR | termios.OPOST)
termios.tcsetattr(self.r, termios.TCSANOW, attrs)
termios.tcsetattr(self.w, termios.TCSANOW, attrs)
return self

View file

@ -1,6 +1,6 @@
[metadata]
name = pre_commit
version = 2.19.0
version = 2.20.0
description = A framework for managing and maintaining multi-language pre-commit hooks.
long_description = file: README.md
long_description_content_type = text/markdown

View file

@ -38,7 +38,7 @@ def copy_tree_to_path(src_dir, dest_dir):
def git_dir(tempdir_factory):
path = tempdir_factory.get()
cmd_output('git', 'init', path)
cmd_output('git', '-c', 'init.defaultBranch=master', 'init', path)
return path

View file

@ -76,6 +76,8 @@ def run_opts(
hook_stage='commit',
show_diff_on_failure=False,
commit_msg_filename='',
prepare_commit_message_source='',
commit_object_name='',
checkout_type='',
is_squash_merge='',
rewrite_command='',
@ -97,6 +99,8 @@ def run_opts(
hook_stage=hook_stage,
show_diff_on_failure=show_diff_on_failure,
commit_msg_filename=commit_msg_filename,
prepare_commit_message_source=prepare_commit_message_source,
commit_object_name=commit_object_name,
checkout_type=checkout_type,
is_squash_merge=is_squash_merge,
rewrite_command=rewrite_command,

View file

@ -154,6 +154,42 @@ def test_run_ns_commit_msg():
assert ns.commit_msg_filename == '.git/COMMIT_MSG'
def test_run_ns_prepare_commit_msg_one_arg():
ns = hook_impl._run_ns(
'prepare-commit-msg', False,
('.git/COMMIT_MSG',), b'',
)
assert ns is not None
assert ns.hook_stage == 'prepare-commit-msg'
assert ns.color is False
assert ns.commit_msg_filename == '.git/COMMIT_MSG'
def test_run_ns_prepare_commit_msg_two_arg():
ns = hook_impl._run_ns(
'prepare-commit-msg', False,
('.git/COMMIT_MSG', 'message'), b'',
)
assert ns is not None
assert ns.hook_stage == 'prepare-commit-msg'
assert ns.color is False
assert ns.commit_msg_filename == '.git/COMMIT_MSG'
assert ns.prepare_commit_message_source == 'message'
def test_run_ns_prepare_commit_msg_three_arg():
ns = hook_impl._run_ns(
'prepare-commit-msg', False,
('.git/COMMIT_MSG', 'message', 'HEAD'), b'',
)
assert ns is not None
assert ns.hook_stage == 'prepare-commit-msg'
assert ns.color is False
assert ns.commit_msg_filename == '.git/COMMIT_MSG'
assert ns.prepare_commit_message_source == 'message'
assert ns.commit_object_name == 'HEAD'
def test_run_ns_post_commit():
ns = hook_impl._run_ns('post-commit', True, (), b'')
assert ns is not None

View file

@ -810,7 +810,12 @@ def test_prepare_commit_msg_hook(cap_out, store, prepare_commit_msg_repo):
cap_out,
store,
prepare_commit_msg_repo,
{'hook_stage': 'prepare-commit-msg', 'commit_msg_filename': filename},
{
'hook_stage': 'prepare-commit-msg',
'commit_msg_filename': filename,
'prepare_commit_message_source': 'commit',
'commit_object_name': 'HEAD',
},
expected_outputs=[b'Add "Signed off by:"', b'Passed'],
expected_ret=0,
stage=False,

View file

@ -21,24 +21,6 @@ from testing.util import cwd
from testing.util import git_commit
@pytest.fixture(autouse=True)
def no_warnings(recwarn):
yield
warnings = []
for warning in recwarn: # pragma: no cover
message = str(warning.message)
# ImportWarning: Not importing directory '...' missing __init__(.py)
if not (
isinstance(warning.message, ImportWarning) and
message.startswith('Not importing directory ') and
' missing __init__' in message
):
warnings.append(
f'{warning.filename}:{warning.lineno} {message}',
)
assert not warnings
@pytest.fixture
def tempdir_factory(tmpdir):
class TmpdirFactory:

View file

@ -45,9 +45,11 @@ def test_error_handler_fatal_error(mocked_log_and_exit):
r'Traceback \(most recent call last\):\n'
r' File ".+pre_commit.error_handler.py", line \d+, in error_handler\n'
r' yield\n'
r'( \^\^\^\^\^\n)?'
r' File ".+tests.error_handler_test.py", line \d+, '
r'in test_error_handler_fatal_error\n'
r' raise exc\n'
r'( \^\^\^\^\^\^\^\^\^\n)?'
r'(pre_commit\.errors\.)?FatalError: just a test\n',
)
pattern.assert_matches(mocked_log_and_exit.call_args[0][3])
@ -69,9 +71,11 @@ def test_error_handler_uncaught_error(mocked_log_and_exit):
r'Traceback \(most recent call last\):\n'
r' File ".+pre_commit.error_handler.py", line \d+, in error_handler\n'
r' yield\n'
r'( \^\^\^\^\^\n)?'
r' File ".+tests.error_handler_test.py", line \d+, '
r'in test_error_handler_uncaught_error\n'
r' raise exc\n'
r'( \^\^\^\^\^\^\^\^\^\n)?'
r'ValueError: another test\n',
)
pattern.assert_matches(mocked_log_and_exit.call_args[0][3])
@ -93,9 +97,11 @@ def test_error_handler_keyboardinterrupt(mocked_log_and_exit):
r'Traceback \(most recent call last\):\n'
r' File ".+pre_commit.error_handler.py", line \d+, in error_handler\n'
r' yield\n'
r'( \^\^\^\^\^\n)?'
r' File ".+tests.error_handler_test.py", line \d+, '
r'in test_error_handler_keyboardinterrupt\n'
r' raise exc\n'
r'( \^\^\^\^\^\^\^\^\^\n)?'
r'KeyboardInterrupt\n',
)
pattern.assert_matches(mocked_log_and_exit.call_args[0][3])

View file

@ -332,6 +332,13 @@ def test_run_a_ruby_hook(tempdir_factory, store):
)
def test_run_a_ruby_hook_with_user_install_set(tempdir_factory, store, tmpdir):
gemrc = tmpdir.join('gemrc')
gemrc.write('gem: --user-install\n')
with envcontext((('GEMRC', str(gemrc)),)):
test_run_a_ruby_hook(tempdir_factory, store)
@xfailif_windows # pragma: win32 no cover
def test_run_versioned_ruby_hook(tempdir_factory, store):
_test_hook_repo(