Merge pull request #52 from pre-commit/no_deps_hook_types

Implement no-dependency system and script hook types.  Closes #39.
This commit is contained in:
Anthony Sottile 2014-03-30 15:23:51 -07:00
commit 88dd5e46d5
14 changed files with 86 additions and 52 deletions

View file

@ -23,4 +23,5 @@
name: My Bash Based Hook name: My Bash Based Hook
description: This is a hook that uses grep to validate some stuff description: This is a hook that uses grep to validate some stuff
entry: ./my_grep_based_hook.sh entry: ./my_grep_based_hook.sh
language: script
expected_return_value: 1 expected_return_value: 1

View file

@ -6,6 +6,7 @@ import sys
import pre_commit.constants as C import pre_commit.constants as C
from pre_commit.clientlib.validate_base import get_validator from pre_commit.clientlib.validate_base import get_validator
from pre_commit.languages.all import all_languages
from pre_commit.util import entry from pre_commit.util import entry
@ -25,7 +26,7 @@ MANIFEST_JSON_SCHEMA = {
'language': {'type': 'string'}, 'language': {'type': 'string'},
'expected_return_value': {'type': 'number'}, 'expected_return_value': {'type': 'number'},
}, },
'required': ['id', 'name', 'entry'], 'required': ['id', 'name', 'entry', 'language'],
}, },
} }
@ -35,13 +36,13 @@ def additional_manifest_check(obj):
language = hook_config.get('language') language = hook_config.get('language')
if language is not None and not any( if language is not None and not any(
language.startswith(lang) for lang in C.SUPPORTED_LANGUAGES language.startswith(lang) for lang in all_languages
): ):
raise InvalidManifestError( raise InvalidManifestError(
'Expected language {0} for {1} to start with one of {2!r}'.format( 'Expected language {0} for {1} to start with one of {2!r}'.format(
hook_config['id'], hook_config['id'],
hook_config['language'], hook_config['language'],
C.SUPPORTED_LANGUAGES, all_languages,
) )
) )

View file

@ -5,13 +5,6 @@ HOOKS_WORKSPACE = '.pre-commit-files'
MANIFEST_FILE = 'hooks.yaml' MANIFEST_FILE = 'hooks.yaml'
SUPPORTED_LANGUAGES = set([
'python',
'ruby',
'node',
])
YAML_DUMP_KWARGS = { YAML_DUMP_KWARGS = {
'default_flow_style': False, 'default_flow_style': False,
'indent': 4, 'indent': 4,

View file

@ -2,6 +2,8 @@
from pre_commit.languages import node from pre_commit.languages import node
from pre_commit.languages import python from pre_commit.languages import python
from pre_commit.languages import ruby from pre_commit.languages import ruby
from pre_commit.languages import script
from pre_commit.languages import system
# A language implements the following two functions in its module: # A language implements the following two functions in its module:
# #
@ -29,4 +31,9 @@ languages = {
'node': node, 'node': node,
'python': python, 'python': python,
'ruby': ruby, 'ruby': ruby,
'script': script,
'system': system,
} }
all_languages = languages.keys()

View file

@ -0,0 +1,13 @@
def install_environment(repo_cmd_runner):
"""Installation for script type is a noop."""
pass
def run_hook(repo_cmd_runner, hook, file_args):
return repo_cmd_runner.run(
['xargs', '{{prefix}}{0}'.format(hook['entry'])] + hook.get('args', []),
# TODO: this is duplicated in pre_commit/languages/helpers.py
stdin='\n'.join(list(file_args) + ['']),
retcode=None,
)

View file

@ -0,0 +1,13 @@
def install_environment(repo_cmd_runner):
"""Installation for system type is a noop."""
pass
def run_hook(repo_cmd_runner, hook, file_args):
return repo_cmd_runner.run(
['xargs', hook['entry']] + hook.get('args', []),
# TODO: this is duplicated in pre_commit/languages/helpers.py
stdin='\n'.join(list(file_args) + ['']),
retcode=None,
)

View file

@ -82,8 +82,7 @@ class Repository(object):
""" """
self.require_created() self.require_created()
repo_cmd_runner = self.get_cmd_runner(cmd_runner) repo_cmd_runner = self.get_cmd_runner(cmd_runner)
for language in C.SUPPORTED_LANGUAGES: for language in self.languages:
if language in self.languages:
languages[language].install_environment(repo_cmd_runner) languages[language].install_environment(repo_cmd_runner)
@contextlib.contextmanager @contextlib.contextmanager

View file

@ -1,4 +1,4 @@
- id: prints_cwd - id: prints_cwd
name: Prints Cwd name: Prints Cwd
entry: prints_cwd entry: pwd
language: python language: system

View file

@ -0,0 +1,4 @@
#!/usr/bin/env bash
echo $@
echo 'Hello World'

View file

@ -0,0 +1,4 @@
- id: bash_hook
name: Bash hook
entry: bin/hook.sh
language: script

View file

@ -45,7 +45,7 @@ def is_valid_according_to_schema(obj, schema):
@pytest.mark.parametrize(('manifest_obj', 'expected'), ( @pytest.mark.parametrize(('manifest_obj', 'expected'), (
([], False), ([], False),
([{'id': 'a', 'name': 'b', 'entry': 'c'}], True), ([{'id': 'a', 'name': 'b', 'entry': 'c', 'language': 'python'}], True),
( (
[{ [{
'id': 'a', 'id': 'a',

View file

@ -59,45 +59,36 @@ def prints_cwd_repo(dummy_git_repo):
@pytest.yield_fixture @pytest.yield_fixture
def config_for_node_hooks_repo(node_hooks_repo): def script_hooks_repo(dummy_git_repo):
yield _make_repo(dummy_git_repo, 'script_hooks_repo')
def _make_config(path, hook_id, file_regex):
config = { config = {
'repo': node_hooks_repo, 'repo': path,
'sha': git.get_head_sha(node_hooks_repo), 'sha': git.get_head_sha(path),
'hooks': [{ 'hooks': [{'id': hook_id, 'files': file_regex}],
'id': 'foo',
'files': '\.js$',
}],
} }
jsonschema.validate([config], CONFIG_JSON_SCHEMA) jsonschema.validate([config], CONFIG_JSON_SCHEMA)
validate_config_extra([config]) validate_config_extra([config])
yield config return config
@pytest.yield_fixture
def config_for_node_hooks_repo(node_hooks_repo):
yield _make_config(node_hooks_repo, 'foo', '\.js$')
@pytest.yield_fixture @pytest.yield_fixture
def config_for_python_hooks_repo(python_hooks_repo): def config_for_python_hooks_repo(python_hooks_repo):
config = { yield _make_config(python_hooks_repo, 'foo', '\.py$')
'repo': python_hooks_repo,
'sha': git.get_head_sha(python_hooks_repo),
'hooks': [{
'id': 'foo',
'files': '\.py$',
}],
}
jsonschema.validate([config], CONFIG_JSON_SCHEMA)
validate_config_extra([config])
yield config
@pytest.yield_fixture @pytest.yield_fixture
def config_for_prints_cwd_repo(prints_cwd_repo): def config_for_prints_cwd_repo(prints_cwd_repo):
config = { yield _make_config(prints_cwd_repo, 'prints_cwd', '^$')
'repo': prints_cwd_repo,
'sha': git.get_head_sha(prints_cwd_repo),
'hooks': [{ @pytest.yield_fixture
'id': 'prints_cwd', def config_for_script_hooks_repo(script_hooks_repo):
'files': '\.py$', yield _make_config(script_hooks_repo, 'bash_hook', '^$')
}],
}
jsonschema.validate([config], CONFIG_JSON_SCHEMA)
validate_config_extra([config])
yield config

View file

@ -1,15 +1,11 @@
import pytest import pytest
import pre_commit.constants as C from pre_commit.languages.all import all_languages
from pre_commit.languages.all import languages from pre_commit.languages.all import languages
def test_all_languages_have_repo_setups(): @pytest.mark.parametrize('language', all_languages)
assert set(languages.keys()) == C.SUPPORTED_LANGUAGES
@pytest.mark.parametrize('language', C.SUPPORTED_LANGUAGES)
def test_all_languages_support_interface(language): def test_all_languages_support_interface(language):
assert hasattr(languages[language], 'install_environment') assert hasattr(languages[language], 'install_environment')
assert hasattr(languages[language], 'run_hook') assert hasattr(languages[language], 'run_hook')

View file

@ -67,6 +67,7 @@ def test_run_a_hook_lots_of_files(config_for_python_hooks_repo):
@pytest.mark.integration @pytest.mark.integration
def test_cwd_of_hook(config_for_prints_cwd_repo): def test_cwd_of_hook(config_for_prints_cwd_repo):
# Note: this doubles as a test for `system` hooks
repo = Repository(config_for_prints_cwd_repo) repo = Repository(config_for_prints_cwd_repo)
ret = repo.run_hook( ret = repo.run_hook(
PrefixedCommandRunner(C.HOOKS_WORKSPACE), 'prints_cwd', [], PrefixedCommandRunner(C.HOOKS_WORKSPACE), 'prints_cwd', [],
@ -89,6 +90,17 @@ def test_run_a_node_hook(config_for_node_hooks_repo):
assert ret[1] == 'Hello World\n' assert ret[1] == 'Hello World\n'
@pytest.mark.integration
def test_run_a_script_hook(config_for_script_hooks_repo):
repo = Repository(config_for_script_hooks_repo)
ret = repo.run_hook(
PrefixedCommandRunner(C.HOOKS_WORKSPACE), 'bash_hook', ['bar'],
)
assert ret[0] == 0
assert ret[1] == 'bar\nHello World\n'
@pytest.fixture @pytest.fixture
def mock_repo_config(): def mock_repo_config():
config = { config = {