From 0c0427bfbdcda8dd445579bb8a2e160501ea37b5 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 28 Dec 2019 17:58:04 -0800 Subject: [PATCH] Add duration to verbose run --- pre_commit/commands/run.py | 8 ++ .../.pre-commit-hooks.yaml | 9 +-- .../resources/arbitrary_bytes_repo/hook.sh | 7 ++ .../arbitrary_bytes_repo/python3_hook.py | 13 ---- .../resources/arbitrary_bytes_repo/setup.py | 8 -- tests/commands/run_test.py | 77 ++++++++++++------- tests/commands/try_repo_test.py | 7 +- 7 files changed, 74 insertions(+), 55 deletions(-) create mode 100755 testing/resources/arbitrary_bytes_repo/hook.sh delete mode 100644 testing/resources/arbitrary_bytes_repo/python3_hook.py delete mode 100644 testing/resources/arbitrary_bytes_repo/setup.py diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py index 4ea55ffc5..45e603706 100644 --- a/pre_commit/commands/run.py +++ b/pre_commit/commands/run.py @@ -4,6 +4,7 @@ import os import re import subprocess +import time from identify.identify import tags_from_path @@ -99,6 +100,7 @@ def _run_single_hook(classifier, hook, skips, cols, verbose, use_color): cols=cols, ), ) + duration = None retcode = 0 files_modified = False out = b'' @@ -113,6 +115,7 @@ def _run_single_hook(classifier, hook, skips, cols, verbose, use_color): cols=cols, ), ) + duration = None retcode = 0 files_modified = False out = b'' @@ -123,7 +126,9 @@ def _run_single_hook(classifier, hook, skips, cols, verbose, use_color): diff_cmd = ('git', 'diff', '--no-ext-diff') diff_before = cmd_output_b(*diff_cmd, retcode=None) filenames = tuple(filenames) if hook.pass_filenames else () + time_before = time.time() retcode, out = hook.run(filenames, use_color) + duration = round(time.time() - time_before, 2) or 0 diff_after = cmd_output_b(*diff_cmd, retcode=None) # if the hook makes changes, fail the commit @@ -141,6 +146,9 @@ def _run_single_hook(classifier, hook, skips, cols, verbose, use_color): if verbose or hook.verbose or retcode or files_modified: _subtle_line('- hook id: {}'.format(hook.id), use_color) + if (verbose or hook.verbose) and duration is not None: + _subtle_line('- duration: {}s'.format(duration), use_color) + if retcode: _subtle_line('- exit code: {}'.format(retcode), use_color) diff --git a/testing/resources/arbitrary_bytes_repo/.pre-commit-hooks.yaml b/testing/resources/arbitrary_bytes_repo/.pre-commit-hooks.yaml index 2c2370092..c2aec9b9f 100644 --- a/testing/resources/arbitrary_bytes_repo/.pre-commit-hooks.yaml +++ b/testing/resources/arbitrary_bytes_repo/.pre-commit-hooks.yaml @@ -1,6 +1,5 @@ -- id: python3-hook - name: Python 3 Hook - entry: python3-hook - language: python - language_version: python3 +- id: hook + name: hook + entry: ./hook.sh + language: script files: \.py$ diff --git a/testing/resources/arbitrary_bytes_repo/hook.sh b/testing/resources/arbitrary_bytes_repo/hook.sh new file mode 100755 index 000000000..fb7dbae12 --- /dev/null +++ b/testing/resources/arbitrary_bytes_repo/hook.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +# Intentionally write mixed encoding to the output. This should not crash +# pre-commit and should write bytes to the output. +# '☃'.encode('UTF-8') + '²'.encode('latin1') +echo -e '\xe2\x98\x83\xb2' +# exit 1 to trigger printing +exit 1 diff --git a/testing/resources/arbitrary_bytes_repo/python3_hook.py b/testing/resources/arbitrary_bytes_repo/python3_hook.py deleted file mode 100644 index ba698a934..000000000 --- a/testing/resources/arbitrary_bytes_repo/python3_hook.py +++ /dev/null @@ -1,13 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import print_function -from __future__ import unicode_literals - -import sys - - -def main(): - # Intentionally write mixed encoding to the output. This should not crash - # pre-commit and should write bytes to the output. - sys.stdout.buffer.write('☃'.encode('UTF-8') + '²'.encode('latin1') + b'\n') - # Return 1 to trigger printing - return 1 diff --git a/testing/resources/arbitrary_bytes_repo/setup.py b/testing/resources/arbitrary_bytes_repo/setup.py deleted file mode 100644 index c780e427a..000000000 --- a/testing/resources/arbitrary_bytes_repo/setup.py +++ /dev/null @@ -1,8 +0,0 @@ -from setuptools import setup - -setup( - name='python3_hook', - version='0.0.0', - py_modules=['python3_hook'], - entry_points={'console_scripts': ['python3-hook=python3_hook:main']}, -) diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py index e56612e3f..b7412d614 100644 --- a/tests/commands/run_test.py +++ b/tests/commands/run_test.py @@ -5,6 +5,7 @@ import os.path import pipes import sys +import time import mock import pytest @@ -25,6 +26,7 @@ from testing.fixtures import modify_config from testing.fixtures import read_config from testing.fixtures import sample_meta_config +from testing.fixtures import write_config from testing.util import cmd_output_mocked_pre_commit_home from testing.util import cwd from testing.util import git_commit @@ -163,36 +165,55 @@ def test_exclude_types_hook_repository(cap_out, store, tempdir_factory): assert b'exe' not in printed -def test_global_exclude(cap_out, store, tempdir_factory): - git_path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(git_path): - with modify_config() as config: - config['exclude'] = '^foo.py$' - open('foo.py', 'a').close() - open('bar.py', 'a').close() - cmd_output('git', 'add', '.') - opts = run_opts(verbose=True) - ret, printed = _do_run(cap_out, store, git_path, opts) - assert ret == 0 - # Does not contain foo.py since it was excluded - expected = b'- hook id: bash_hook\n\nbar.py\nHello World\n\n' - assert printed.endswith(expected) +def test_global_exclude(cap_out, store, in_git_dir): + config = { + 'exclude': r'^foo\.py$', + 'repos': [{'repo': 'meta', 'hooks': [{'id': 'identity'}]}], + } + write_config('.', config) + open('foo.py', 'a').close() + open('bar.py', 'a').close() + cmd_output('git', 'add', '.') + opts = run_opts(verbose=True) + ret, printed = _do_run(cap_out, store, str(in_git_dir), opts) + assert ret == 0 + # Does not contain foo.py since it was excluded + assert printed.startswith(b'identity' + b'.' * 65 + b'Passed\n') + assert printed.endswith(b'\n\n.pre-commit-config.yaml\nbar.py\n\n') -def test_global_files(cap_out, store, tempdir_factory): - git_path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') - with cwd(git_path): - with modify_config() as config: - config['files'] = '^bar.py$' - open('foo.py', 'a').close() - open('bar.py', 'a').close() - cmd_output('git', 'add', '.') - opts = run_opts(verbose=True) - ret, printed = _do_run(cap_out, store, git_path, opts) - assert ret == 0 - # Does not contain foo.py since it was not included - expected = b'- hook id: bash_hook\n\nbar.py\nHello World\n\n' - assert printed.endswith(expected) +def test_global_files(cap_out, store, in_git_dir): + config = { + 'files': r'^bar\.py$', + 'repos': [{'repo': 'meta', 'hooks': [{'id': 'identity'}]}], + } + write_config('.', config) + open('foo.py', 'a').close() + open('bar.py', 'a').close() + cmd_output('git', 'add', '.') + opts = run_opts(verbose=True) + ret, printed = _do_run(cap_out, store, str(in_git_dir), opts) + assert ret == 0 + # Does not contain foo.py since it was excluded + assert printed.startswith(b'identity' + b'.' * 65 + b'Passed\n') + assert printed.endswith(b'\n\nbar.py\n\n') + + +@pytest.mark.parametrize( + ('t1', 't2', 'expected'), + ( + (1.234, 2., b'\n- duration: 0.77s\n'), + (1., 1., b'\n- duration: 0s\n'), + ), +) +def test_verbose_duration(cap_out, store, in_git_dir, t1, t2, expected): + write_config('.', {'repo': 'meta', 'hooks': [{'id': 'identity'}]}) + cmd_output('git', 'add', '.') + opts = run_opts(verbose=True) + with mock.patch.object(time, 'time', side_effect=(t1, t2)): + ret, printed = _do_run(cap_out, store, str(in_git_dir), opts) + assert ret == 0 + assert expected in printed @pytest.mark.parametrize( diff --git a/tests/commands/try_repo_test.py b/tests/commands/try_repo_test.py index ee010636b..536eb9bc4 100644 --- a/tests/commands/try_repo_test.py +++ b/tests/commands/try_repo_test.py @@ -3,6 +3,9 @@ import os.path import re +import time + +import mock from pre_commit import git from pre_commit.commands.try_repo import try_repo @@ -40,7 +43,8 @@ def _run_try_repo(tempdir_factory, **kwargs): def test_try_repo_repo_only(cap_out, tempdir_factory): - _run_try_repo(tempdir_factory, verbose=True) + with mock.patch.object(time, 'time', return_value=0.0): + _run_try_repo(tempdir_factory, verbose=True) start, config, rest = _get_out(cap_out) assert start == '' assert re.match( @@ -58,6 +62,7 @@ def test_try_repo_repo_only(cap_out, tempdir_factory): - hook id: bash_hook Bash hook................................................................Passed - hook id: bash_hook2 +- duration: 0s test-file