Repository: pre-commit/pre-commit
Pull request #515 (2017-03-30 15:46:13)

Add a `pre-commit sample-config` command
CC @elaichi 


Patch:
diff --git a/pre_commit/commands/sample_config.py b/pre_commit/commands/sample_config.py
new file mode 100644
index 0000000..f38d655
--- /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 00b8cfa..8a77316 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)


Test patch:
diff --git a/tests/commands/sample_config_test.py b/tests/commands/sample_config_test.py
new file mode 100644
index 0000000..88a90d9
--- /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 906d6f3..8cc6121 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)