From 7c883d038de37489966f57576ea4984688439a30 Mon Sep 17 00:00:00 2001 From: allburov Date: Tue, 15 Oct 2019 15:58:47 +0700 Subject: [PATCH] Added config parameter hide_skipped --- pre_commit/clientlib.py | 2 + pre_commit/commands/run.py | 18 ++++-- pre_commit/output.py | 13 +++- .../.pre-commit-hooks.yaml | 15 +++++ .../all_statuses_hooks_repo/bin/hook.sh | 5 ++ tests/clientlib_test.py | 21 ++++++ tests/commands/run_test.py | 64 ++++++++++++++++++- 7 files changed, 130 insertions(+), 8 deletions(-) create mode 100644 testing/resources/all_statuses_hooks_repo/.pre-commit-hooks.yaml create mode 100755 testing/resources/all_statuses_hooks_repo/bin/hook.sh diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index 14a22b99..75de944c 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -262,6 +262,7 @@ CONFIG_SCHEMA = cfgv.Map( ), cfgv.Optional('exclude', cfgv.check_regex, '^$'), cfgv.Optional('fail_fast', cfgv.check_bool, False), + cfgv.Optional('hide_skipped', cfgv.check_bool, False), cfgv.Optional( 'minimum_pre_commit_version', cfgv.check_and(cfgv.check_string, check_min_version), @@ -274,6 +275,7 @@ CONFIG_SCHEMA = cfgv.Map( 'default_stages', 'exclude', 'fail_fast', + 'hide_skipped', 'minimum_pre_commit_version', ), warn_unknown_keys_root, diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index dd30c7e5..d69f2a58 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -19,7 +19,6 @@ from pre_commit.staged_files_only import staged_files_only from pre_commit.util import cmd_output_b from pre_commit.util import noop_context - logger = logging.getLogger('pre_commit') @@ -70,10 +69,16 @@ def _hook_msg_start(hook, verbose): SKIPPED = 'Skipped' +FAILED = 'Failed' +PASSED = 'Passed' NO_FILES = '(no files to check)' -def _run_single_hook(classifier, hook, args, skips, cols, use_color): +def _run_single_hook( + classifier, hook, args, skips, cols, + use_color, + hide_skipped, +): filenames = classifier.filenames_for_hook(hook) if hook.language == 'pcre': @@ -93,6 +98,7 @@ def _run_single_hook(classifier, hook, args, skips, cols, use_color): use_color=args.color, cols=cols, ), + cond=not hide_skipped, ) return 0 elif not filenames and not hook.always_run: @@ -105,6 +111,7 @@ def _run_single_hook(classifier, hook, args, skips, cols, use_color): use_color=args.color, cols=cols, ), + cond=not hide_skipped, ) return 0 @@ -131,11 +138,11 @@ def _run_single_hook(classifier, hook, args, skips, cols, use_color): if retcode: retcode = 1 print_color = color.RED - pass_fail = 'Failed' + pass_fail = FAILED else: retcode = 0 print_color = color.GREEN - pass_fail = 'Passed' + pass_fail = PASSED output.write_line(color.format_color(pass_fail, print_color, args.color)) @@ -202,10 +209,12 @@ def _run_hooks(config, hooks, args, environ): filenames = _all_filenames(args) filenames = filter_by_include_exclude(filenames, '', config['exclude']) classifier = Classifier(filenames) + hide_skipped = False if args.verbose else config['hide_skipped'] retval = 0 for hook in hooks: retval |= _run_single_hook( classifier, hook, args, skips, cols, args.color, + hide_skipped, ) if retval and config['fail_fast']: break @@ -219,6 +228,7 @@ def _run_hooks(config, hooks, args, environ): '`pre-commit install`.', ) output.write_line('All changes made by hooks:') + # args.color is a boolean. # See user_color function in color.py subprocess.call(( diff --git a/pre_commit/output.py b/pre_commit/output.py index 478ad5e6..1a90ebd7 100644 --- a/pre_commit/output.py +++ b/pre_commit/output.py @@ -67,12 +67,21 @@ def get_hook_message( stdout_byte_stream = getattr(sys.stdout, 'buffer', sys.stdout) -def write(s, stream=stdout_byte_stream): +def write(s, stream=stdout_byte_stream, cond=True): + if not cond: + return stream.write(five.to_bytes(s)) stream.flush() -def write_line(s=None, stream=stdout_byte_stream, logfile_name=None): +def write_line( + s=None, + stream=stdout_byte_stream, + logfile_name=None, + cond=True, +): + if not cond: + return output_streams = [stream] if logfile_name: ctx = open(logfile_name, 'ab') diff --git a/testing/resources/all_statuses_hooks_repo/.pre-commit-hooks.yaml b/testing/resources/all_statuses_hooks_repo/.pre-commit-hooks.yaml new file mode 100644 index 00000000..7019446c --- /dev/null +++ b/testing/resources/all_statuses_hooks_repo/.pre-commit-hooks.yaml @@ -0,0 +1,15 @@ +- id: passing_hook + name: Passing hook + entry: bin/hook.sh + args: ['0'] + language: script +- id: failing_hook + name: Failing hook + entry: bin/hook.sh + args: ['1'] + language: script +- id: skipping_hook + name: Skipping hook + entry: bin/hook.sh + language: script + files: 'no-exist-file' diff --git a/testing/resources/all_statuses_hooks_repo/bin/hook.sh b/testing/resources/all_statuses_hooks_repo/bin/hook.sh new file mode 100755 index 00000000..b3f704b6 --- /dev/null +++ b/testing/resources/all_statuses_hooks_repo/bin/hook.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +echo $@ +echo 'Hello World' +exit $1 diff --git a/tests/clientlib_test.py b/tests/clientlib_test.py index 6174889a..d8f5a910 100644 --- a/tests/clientlib_test.py +++ b/tests/clientlib_test.py @@ -315,3 +315,24 @@ def test_warn_additional(schema): x for x in schema.items if isinstance(x, cfgv.WarnAdditionalKeys) ] assert allowed_keys == set(warn_additional.keys) + + +def test_hide_skipped_passing(tmpdir, caplog): + f = tmpdir.join('cfg.yaml') + f.write( + 'hide_skipped: True\n' + 'repos:\n' + '- repo: https://gitlab.com/pycqa/flake8\n' + ' rev: 3.7.7\n' + ' hooks:\n' + ' - id: flake8\n', + ) + ret_val = validate_config_main((f.strpath,)) + assert not ret_val + assert caplog.record_tuples != [ + ( + 'pre_commit', + logging.WARNING, + 'Unexpected key(s) present at root: hide_skipped', + ), + ] diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index f6d5c93f..5659ba69 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -71,9 +71,12 @@ def _do_run(cap_out, store, repo, args, environ={}, config_file=C.CONFIG_FILE): def _test_run( - cap_out, store, repo, opts, expected_outputs, expected_ret, stage, - config_file=C.CONFIG_FILE, + cap_out, store, repo, opts, expected_outputs, expected_ret, stage, + config_file=C.CONFIG_FILE, + unexpected_outputs=None, ): + unexpected_outputs = unexpected_outputs or [] + if stage: stage_a_file() args = run_opts(**opts) @@ -82,6 +85,8 @@ def _test_run( assert ret == expected_ret, (ret, expected_ret, printed) for expected_output_part in expected_outputs: assert expected_output_part in printed + for unexpected_output_part in unexpected_outputs: + assert unexpected_output_part not in printed def test_run_all_hooks_failing(cap_out, store, repo_with_failing_hook): @@ -101,6 +106,61 @@ def test_run_all_hooks_failing(cap_out, store, repo_with_failing_hook): ) +PASSED_MSG = ( + b'Passing hook', + b'Passed', +) +FAILED_MSG = ( + b'Failing hook', + b'Failed', + b'hookid: failing_hook', + b'foo.py', +) +SKIPPED_MSG = ( + b'Skipping hook', + b'(no files to check)', + b'Skipped', +) + + +@pytest.mark.parametrize( + ('expected_outputs', 'unexpected_outputs', 'hide_skipped', 'args'), [ + ([*PASSED_MSG, *FAILED_MSG, *SKIPPED_MSG], [], None, {}), + ([*PASSED_MSG, *FAILED_MSG, *SKIPPED_MSG], [], False, {}), + ([*FAILED_MSG, *PASSED_MSG], [*SKIPPED_MSG], True, {}), + ( + [*PASSED_MSG, *FAILED_MSG, *SKIPPED_MSG], [], True, + {'verbose': True}, + ), + ], +) +def test_hide_skipped( + cap_out, + store, + tempdir_factory, + expected_outputs, + unexpected_outputs, + hide_skipped, + args, +): + git_path = make_consuming_repo(tempdir_factory, 'all_statuses_hooks_repo') + with cwd(git_path): + if hide_skipped is not None: + with modify_config() as config: + config['hide_skipped'] = hide_skipped + + _test_run( + cap_out, + store, + git_path, + args, + expected_outputs, + expected_ret=1, + stage=True, + unexpected_outputs=unexpected_outputs, + ) + + def test_arbitrary_bytes_hook(cap_out, store, tempdir_factory): git_path = make_consuming_repo(tempdir_factory, 'arbitrary_bytes_repo') with cwd(git_path):