pre_commit: expose fail-fast argument for run subcommand

This patch exposes the fail-fast feature as a command-line argument for the run
subcommand, allowing to run pre-commit to stop at the first failed hook without
the need of temporarily writing it to the configuration file when temporarily
needed.

Signed-off-by: Luís Ferreira <contact@lsferreira.net>
This commit is contained in:
Luís Ferreira 2021-10-03 00:34:39 +01:00
parent d021bbfabd
commit 61efc539a4
No known key found for this signature in database
GPG key ID: 730750D54B7A9F66
5 changed files with 23 additions and 2 deletions

View file

@ -69,6 +69,7 @@ def _ns(
color: bool, color: bool,
*, *,
all_files: bool = False, all_files: bool = False,
fail_fast: bool = False,
remote_branch: Optional[str] = None, remote_branch: Optional[str] = None,
local_branch: Optional[str] = None, local_branch: Optional[str] = None,
from_ref: Optional[str] = None, from_ref: Optional[str] = None,
@ -91,6 +92,7 @@ def _ns(
remote_url=remote_url, remote_url=remote_url,
commit_msg_filename=commit_msg_filename, commit_msg_filename=commit_msg_filename,
all_files=all_files, all_files=all_files,
fail_fast=fail_fast,
checkout_type=checkout_type, checkout_type=checkout_type,
is_squash_merge=is_squash_merge, is_squash_merge=is_squash_merge,
rewrite_command=rewrite_command, rewrite_command=rewrite_command,

View file

@ -290,7 +290,7 @@ def _run_hooks(
verbose=args.verbose, use_color=args.color, verbose=args.verbose, use_color=args.color,
) )
retval |= current_retval retval |= current_retval
if retval and config['fail_fast']: if retval and (config['fail_fast'] or args.fail_fast):
break break
if retval and args.show_diff_on_failure and prior_diff: if retval and args.show_diff_on_failure and prior_diff:
if args.all_files: if args.all_files:

View file

@ -85,6 +85,10 @@ def _add_run_options(parser: argparse.ArgumentParser) -> None:
'--all-files', '-a', action='store_true', default=False, '--all-files', '-a', action='store_true', default=False,
help='Run on all the files in the repo.', help='Run on all the files in the repo.',
) )
mutex_group.add_argument(
'--fail-fast', action='store_true',
help='Stop running hooks after the first failure',
)
mutex_group.add_argument( mutex_group.add_argument(
'--files', nargs='*', default=[], '--files', nargs='*', default=[],
help='Specific filenames to run hooks on.', help='Specific filenames to run hooks on.',

View file

@ -57,6 +57,7 @@ xfailif_windows = pytest.mark.xfail(os.name == 'nt', reason='windows')
def run_opts( def run_opts(
all_files=False, all_files=False,
fail_fast=False,
files=(), files=(),
color=False, color=False,
verbose=False, verbose=False,
@ -78,6 +79,7 @@ def run_opts(
assert not (all_files and files) assert not (all_files and files)
return auto_namedtuple( return auto_namedtuple(
all_files=all_files, all_files=all_files,
fail_fast=fail_fast,
files=files, files=files,
color=color, color=color,
verbose=verbose, verbose=verbose,

View file

@ -973,7 +973,7 @@ def test_pass_filenames(
assert (b'foo.py' in printed) == pass_filenames assert (b'foo.py' in printed) == pass_filenames
def test_fail_fast(cap_out, store, repo_with_failing_hook): def test_fail_fast_config(cap_out, store, repo_with_failing_hook):
with modify_config() as config: with modify_config() as config:
# More than one hook # More than one hook
config['fail_fast'] = True config['fail_fast'] = True
@ -985,6 +985,19 @@ def test_fail_fast(cap_out, store, repo_with_failing_hook):
assert printed.count(b'Failing hook') == 1 assert printed.count(b'Failing hook') == 1
def test_fail_fast_args(cap_out, store, repo_with_failing_hook):
with modify_config() as config:
# More than one hook
config['repos'][0]['hooks'] *= 2
stage_a_file()
ret, printed = _do_run(
cap_out, store, repo_with_failing_hook, run_opts(fail_fast=True),
)
# it should have only run one hook
assert printed.count(b'Failing hook') == 1
def test_classifier_removes_dne(): def test_classifier_removes_dne():
classifier = Classifier(('this_file_does_not_exist',)) classifier = Classifier(('this_file_does_not_exist',))
assert classifier.filenames == [] assert classifier.filenames == []