diff --git a/pre_commit/commands/sample_config.py b/pre_commit/commands/sample_config.py new file mode 100644 index 00000000..f38d655f --- /dev/null +++ b/pre_commit/commands/sample_config.py @@ -0,0 +1,25 @@ +from __future__ import absolute_import +from __future__ import print_function +from __future__ import unicode_literals + + +# TODO: maybe `git ls-remote git://github.com/pre-commit/pre-commit-hooks` to +# determine the latest revision? This adds ~200ms from my tests (and is +# significantly faster than https:// or http://). For now, periodically +# manually updating the revision is fine. +SAMPLE_CONFIG = '''\ +# See http://pre-commit.com for more information +# See http://pre-commit.com/hooks.html for more hooks +- repo: https://github.com/pre-commit/pre-commit-hooks + sha: v0.7.1 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files +''' + + +def sample_config(): + print(SAMPLE_CONFIG, end='') + return 0 diff --git a/pre_commit/main.py b/pre_commit/main.py index 00b8cfad..8a773161 100644 --- a/pre_commit/main.py +++ b/pre_commit/main.py @@ -14,6 +14,7 @@ from pre_commit.commands.install_uninstall import install from pre_commit.commands.install_uninstall import install_hooks from pre_commit.commands.install_uninstall import uninstall from pre_commit.commands.run import run +from pre_commit.commands.sample_config import sample_config from pre_commit.error_handler import error_handler from pre_commit.logging_handler import add_logging_handler from pre_commit.runner import Runner @@ -163,6 +164,12 @@ def main(argv=None): help='Specific filenames to run hooks on.', ) + sample_config_parser = subparsers.add_parser( + 'sample-config', help='Produce a sample {} file'.format(C.CONFIG_FILE), + ) + _add_color_option(sample_config_parser) + _add_config_option(sample_config_parser) + help = subparsers.add_parser( 'help', help='Show help for a specific command.', ) @@ -205,6 +212,8 @@ def main(argv=None): return autoupdate(runner, args.tags_only) elif args.command == 'run': return run(runner, args) + elif args.command == 'sample-config': + return sample_config() else: raise NotImplementedError( 'Command {} not implemented.'.format(args.command) diff --git a/tests/commands/sample_config_test.py b/tests/commands/sample_config_test.py new file mode 100644 index 00000000..88a90d91 --- /dev/null +++ b/tests/commands/sample_config_test.py @@ -0,0 +1,21 @@ +from __future__ import absolute_import +from __future__ import unicode_literals + +from pre_commit.commands.sample_config import sample_config + + +def test_sample_config(capsys): + ret = sample_config() + assert ret == 0 + out, _ = capsys.readouterr() + assert out == '''\ +# See http://pre-commit.com for more information +# See http://pre-commit.com/hooks.html for more hooks +- repo: https://github.com/pre-commit/pre-commit-hooks + sha: v0.7.1 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files +''' diff --git a/tests/main_test.py b/tests/main_test.py index 906d6f32..8cc61218 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -12,22 +12,20 @@ from pre_commit.util import cwd from testing.auto_namedtuple import auto_namedtuple +FNS = ( + 'autoupdate', 'clean', 'install', 'install_hooks', 'run', 'sample_config', + 'uninstall', +) +CMDS = tuple(fn.replace('_', '-') for fn in FNS) + + @pytest.yield_fixture def mock_commands(): - with mock.patch.object(main, 'autoupdate') as autoupdate_mock: - with mock.patch.object(main, 'install_hooks') as install_hooks_mock: - with mock.patch.object(main, 'install') as install_mock: - with mock.patch.object(main, 'uninstall') as uninstall_mock: - with mock.patch.object(main, 'run') as run_mock: - with mock.patch.object(main, 'clean') as clean_mock: - yield auto_namedtuple( - autoupdate_mock=autoupdate_mock, - clean_mock=clean_mock, - install_mock=install_mock, - install_hooks_mock=install_hooks_mock, - uninstall_mock=uninstall_mock, - run_mock=run_mock, - ) + mcks = {fn: mock.patch.object(main, fn).start() for fn in FNS} + ret = auto_namedtuple(**mcks) + yield ret + for mck in ret: + mck.stop() class CalledExit(Exception): @@ -93,45 +91,10 @@ def test_help_other_command( ]) -def test_install_command(mock_commands): - main.main(['install']) - assert mock_commands.install_mock.call_count == 1 - assert_only_one_mock_called(mock_commands) - - -def test_uninstall_command(mock_commands): - main.main(['uninstall']) - assert mock_commands.uninstall_mock.call_count == 1 - assert_only_one_mock_called(mock_commands) - - -def test_clean_command(mock_commands): - main.main(['clean']) - assert mock_commands.clean_mock.call_count == 1 - assert_only_one_mock_called(mock_commands) - - -def test_autoupdate_command(mock_commands): - main.main(['autoupdate']) - assert mock_commands.autoupdate_mock.call_count == 1 - assert_only_one_mock_called(mock_commands) - - -def test_run_command(mock_commands): - main.main(['run']) - assert mock_commands.run_mock.call_count == 1 - assert_only_one_mock_called(mock_commands) - - -def test_install_hooks_command(mock_commands): - main.main(('install-hooks',)) - assert mock_commands.install_hooks_mock.call_count == 1 - assert_only_one_mock_called(mock_commands) - - -def test_no_commands_run_command(mock_commands): - main.main([]) - assert mock_commands.run_mock.call_count == 1 +@pytest.mark.parametrize('command', CMDS) +def test_install_command(command, mock_commands): + main.main((command,)) + assert getattr(mock_commands, command.replace('-', '_')).call_count == 1 assert_only_one_mock_called(mock_commands)