mirror of
https://github.com/pre-commit/pre-commit.git
synced 2026-04-15 10:01:46 +04:00
Attempt to add a mechanism for tagging hooks
This commit is contained in:
parent
1f59f4cba8
commit
189490a938
8 changed files with 67 additions and 8 deletions
|
|
@ -80,6 +80,7 @@ MANIFEST_HOOK_DICT = cfgv.Map(
|
||||||
cfgv.Optional('minimum_pre_commit_version', cfgv.check_string, '0'),
|
cfgv.Optional('minimum_pre_commit_version', cfgv.check_string, '0'),
|
||||||
cfgv.Optional('require_serial', cfgv.check_bool, False),
|
cfgv.Optional('require_serial', cfgv.check_bool, False),
|
||||||
cfgv.Optional('stages', cfgv.check_array(cfgv.check_one_of(C.STAGES)), []),
|
cfgv.Optional('stages', cfgv.check_array(cfgv.check_one_of(C.STAGES)), []),
|
||||||
|
cfgv.Optional('tags', cfgv.check_array(cfgv.check_string), []),
|
||||||
cfgv.Optional('verbose', cfgv.check_bool, False),
|
cfgv.Optional('verbose', cfgv.check_bool, False),
|
||||||
)
|
)
|
||||||
MANIFEST_SCHEMA = cfgv.Array(MANIFEST_HOOK_DICT)
|
MANIFEST_SCHEMA = cfgv.Array(MANIFEST_HOOK_DICT)
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ def _run_single_hook(
|
||||||
) -> tuple[bool, bytes]:
|
) -> tuple[bool, bytes]:
|
||||||
filenames = classifier.filenames_for_hook(hook)
|
filenames = classifier.filenames_for_hook(hook)
|
||||||
|
|
||||||
if hook.id in skips or hook.alias in skips:
|
if _hook_is_skipped(skips, hook):
|
||||||
output.write(
|
output.write(
|
||||||
_full_msg(
|
_full_msg(
|
||||||
start=hook.name,
|
start=hook.name,
|
||||||
|
|
@ -323,6 +323,25 @@ def _has_unstaged_config(config_file: str) -> bool:
|
||||||
# be explicit, other git errors don't mean it has an unstaged config.
|
# be explicit, other git errors don't mean it has an unstaged config.
|
||||||
return retcode == 1
|
return retcode == 1
|
||||||
|
|
||||||
|
def _hook_should_run(args: argparse.Namespace, hook: Hook) -> bool:
|
||||||
|
if args.hook_stage not in hook.stages:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if args.tags:
|
||||||
|
return len(set(hook.tags) & set(args.tags)) > 0
|
||||||
|
|
||||||
|
return (
|
||||||
|
not args.hook
|
||||||
|
or hook.id == args.hook
|
||||||
|
or hook.alias == args.hook
|
||||||
|
)
|
||||||
|
|
||||||
|
def _hook_is_skipped(skips: Sequence[str], hook: Hook) -> bool:
|
||||||
|
return (
|
||||||
|
hook.id in skips
|
||||||
|
or hook.alias in skips
|
||||||
|
or len(set(hook.tags) & set(skips)) > 0
|
||||||
|
)
|
||||||
|
|
||||||
def run(
|
def run(
|
||||||
config_file: str,
|
config_file: str,
|
||||||
|
|
@ -409,8 +428,7 @@ def run(
|
||||||
hooks = [
|
hooks = [
|
||||||
hook
|
hook
|
||||||
for hook in all_hooks(config, store)
|
for hook in all_hooks(config, store)
|
||||||
if not args.hook or hook.id == args.hook or hook.alias == args.hook
|
if _hook_should_run(args, hook)
|
||||||
if args.hook_stage in hook.stages
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if args.hook and not hooks:
|
if args.hook and not hooks:
|
||||||
|
|
@ -418,12 +436,17 @@ def run(
|
||||||
f'No hook with id `{args.hook}` in stage `{args.hook_stage}`',
|
f'No hook with id `{args.hook}` in stage `{args.hook_stage}`',
|
||||||
)
|
)
|
||||||
return 1
|
return 1
|
||||||
|
if args.tags and not hooks:
|
||||||
|
output.write_line(
|
||||||
|
f'No hooks with tags matching `{args.tags}` in stage `{args.hook_stage}`'
|
||||||
|
)
|
||||||
|
return 1
|
||||||
|
|
||||||
skips = _get_skips(environ)
|
skips = _get_skips(environ)
|
||||||
to_install = [
|
to_install = [
|
||||||
hook
|
hook
|
||||||
for hook in hooks
|
for hook in hooks
|
||||||
if hook.id not in skips and hook.alias not in skips
|
if not _hook_is_skipped(skips, hook)
|
||||||
]
|
]
|
||||||
install_hook_envs(to_install, store)
|
install_hook_envs(to_install, store)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ class Hook(NamedTuple):
|
||||||
minimum_pre_commit_version: str
|
minimum_pre_commit_version: str
|
||||||
require_serial: bool
|
require_serial: bool
|
||||||
stages: Sequence[str]
|
stages: Sequence[str]
|
||||||
|
tags: Sequence[str]
|
||||||
verbose: bool
|
verbose: bool
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,9 @@ def _add_hook_type_option(parser: argparse.ArgumentParser) -> None:
|
||||||
|
|
||||||
|
|
||||||
def _add_run_options(parser: argparse.ArgumentParser) -> None:
|
def _add_run_options(parser: argparse.ArgumentParser) -> None:
|
||||||
parser.add_argument('hook', nargs='?', help='A single hook-id to run')
|
hooks_mutex_group = parser.add_mutually_exclusive_group(required=False)
|
||||||
|
hooks_mutex_group.add_argument('hook', nargs='?', help='A single hook-id to run')
|
||||||
|
hooks_mutex_group.add_argument('--tags', nargs='+', default=[], help='Tag groups to run')
|
||||||
parser.add_argument('--verbose', '-v', action='store_true', default=False)
|
parser.add_argument('--verbose', '-v', action='store_true', default=False)
|
||||||
mutex_group = parser.add_mutually_exclusive_group(required=False)
|
mutex_group = parser.add_mutually_exclusive_group(required=False)
|
||||||
mutex_group.add_argument(
|
mutex_group.add_argument(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[metadata]
|
[metadata]
|
||||||
name = pre_commit
|
name = pre_commit
|
||||||
version = 2.20.0
|
version = 2.21.0
|
||||||
description = A framework for managing and maintaining multi-language pre-commit hooks.
|
description = A framework for managing and maintaining multi-language pre-commit hooks.
|
||||||
long_description = file: README.md
|
long_description = file: README.md
|
||||||
long_description_content_type = text/markdown
|
long_description_content_type = text/markdown
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,5 @@
|
||||||
entry: bin/hook.sh
|
entry: bin/hook.sh
|
||||||
language: script
|
language: script
|
||||||
files: ''
|
files: ''
|
||||||
|
tags:
|
||||||
|
- foo
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,7 @@ def run_opts(
|
||||||
color=False,
|
color=False,
|
||||||
verbose=False,
|
verbose=False,
|
||||||
hook=None,
|
hook=None,
|
||||||
|
tags=(),
|
||||||
remote_branch='',
|
remote_branch='',
|
||||||
local_branch='',
|
local_branch='',
|
||||||
from_ref='',
|
from_ref='',
|
||||||
|
|
@ -84,12 +85,14 @@ def run_opts(
|
||||||
):
|
):
|
||||||
# These are mutually exclusive
|
# These are mutually exclusive
|
||||||
assert not (all_files and files)
|
assert not (all_files and files)
|
||||||
|
assert not (hook and tags)
|
||||||
return auto_namedtuple(
|
return auto_namedtuple(
|
||||||
all_files=all_files,
|
all_files=all_files,
|
||||||
files=files,
|
files=files,
|
||||||
color=color,
|
color=color,
|
||||||
verbose=verbose,
|
verbose=verbose,
|
||||||
hook=hook,
|
hook=hook,
|
||||||
|
tags=tags,
|
||||||
remote_branch=remote_branch,
|
remote_branch=remote_branch,
|
||||||
local_branch=local_branch,
|
local_branch=local_branch,
|
||||||
from_ref=from_ref,
|
from_ref=from_ref,
|
||||||
|
|
|
||||||
|
|
@ -144,12 +144,14 @@ def _do_run(cap_out, store, repo, args, environ={}, config_file=C.CONFIG_FILE):
|
||||||
|
|
||||||
def _test_run(
|
def _test_run(
|
||||||
cap_out, store, repo, opts, expected_outputs, expected_ret, stage,
|
cap_out, store, repo, opts, expected_outputs, expected_ret, stage,
|
||||||
config_file=C.CONFIG_FILE,
|
config_file=C.CONFIG_FILE, environ_override=None
|
||||||
):
|
):
|
||||||
if stage:
|
if stage:
|
||||||
stage_a_file()
|
stage_a_file()
|
||||||
|
if environ_override is None:
|
||||||
|
environ_override = {}
|
||||||
args = run_opts(**opts)
|
args = run_opts(**opts)
|
||||||
ret, printed = _do_run(cap_out, store, repo, args, config_file=config_file)
|
ret, printed = _do_run(cap_out, store, repo, args, config_file=config_file, environ=environ_override)
|
||||||
|
|
||||||
assert ret == expected_ret, (ret, expected_ret, printed)
|
assert ret == expected_ret, (ret, expected_ret, printed)
|
||||||
for expected_output_part in expected_outputs:
|
for expected_output_part in expected_outputs:
|
||||||
|
|
@ -352,6 +354,7 @@ def test_show_diff_on_failure(
|
||||||
({}, (b'Bash hook', b'Passed'), 0, True),
|
({}, (b'Bash hook', b'Passed'), 0, True),
|
||||||
({'verbose': True}, (b'foo.py\nHello World',), 0, True),
|
({'verbose': True}, (b'foo.py\nHello World',), 0, True),
|
||||||
({'hook': 'bash_hook'}, (b'Bash hook', b'Passed'), 0, True),
|
({'hook': 'bash_hook'}, (b'Bash hook', b'Passed'), 0, True),
|
||||||
|
({'tags': ['foo']}, (b'Bash hook', b'Passed'), 0, True),
|
||||||
(
|
(
|
||||||
{'hook': 'nope'},
|
{'hook': 'nope'},
|
||||||
(b'No hook with id `nope` in stage `commit`',),
|
(b'No hook with id `nope` in stage `commit`',),
|
||||||
|
|
@ -364,6 +367,18 @@ def test_show_diff_on_failure(
|
||||||
1,
|
1,
|
||||||
True,
|
True,
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
{'tags': ['bar', 'baz']},
|
||||||
|
(b'No hooks with tags matching `[\'bar\', \'baz\']` in stage `commit`',),
|
||||||
|
1,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{'tags': ['bar', 'baz'], 'hook_stage': 'push'},
|
||||||
|
(b'No hooks with tags matching `[\'bar\', \'baz\']` in stage `push`',),
|
||||||
|
1,
|
||||||
|
True,
|
||||||
|
),
|
||||||
(
|
(
|
||||||
{'all_files': True, 'verbose': True},
|
{'all_files': True, 'verbose': True},
|
||||||
(b'foo.py',),
|
(b'foo.py',),
|
||||||
|
|
@ -618,6 +633,18 @@ def test_skip_aliased_hook(cap_out, store, aliased_repo):
|
||||||
for msg in (b'Bash hook', b'Skipped'):
|
for msg in (b'Bash hook', b'Skipped'):
|
||||||
assert printed.count(msg) == 1
|
assert printed.count(msg) == 1
|
||||||
|
|
||||||
|
def test_skip_tag(cap_out, store, repo_with_passing_hook):
|
||||||
|
_test_run(
|
||||||
|
cap_out,
|
||||||
|
store,
|
||||||
|
repo_with_passing_hook,
|
||||||
|
{},
|
||||||
|
(b'Bash hook', b'Skipped'),
|
||||||
|
0,
|
||||||
|
True,
|
||||||
|
environ_override={'SKIP': 'foo'}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_skip_bypasses_installation(cap_out, store, repo_with_passing_hook):
|
def test_skip_bypasses_installation(cap_out, store, repo_with_passing_hook):
|
||||||
config = {
|
config = {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue