From 5ca8f4ffa866870f35f731a7413c16555db49036 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 13 Mar 2014 20:33:42 -0700 Subject: [PATCH] Repository now parses languages and manifests --- Makefile | 4 ++- pre_commit/clientlib/validate_base.py | 2 ++ pre_commit/repository.py | 43 +++++++++++++++++++++-- pre_commit/util.py | 16 +++++++++ tests/clientlib/validate_base_test.py | 7 +++- tests/clientlib/validate_manifest_test.py | 2 +- tests/conftest.py | 25 +++++-------- tests/repository_test.py | 38 ++++++++++++++++++-- 8 files changed, 114 insertions(+), 23 deletions(-) create mode 100644 pre_commit/util.py diff --git a/Makefile b/Makefile index 9aedace0..5d7b8014 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,8 @@ TEST_TARGETS = ITEST_TARGETS = -m integration UTEST_TARGETS = -m "not(integration)" +DEBUG= + all: _tests integration: @@ -19,7 +21,7 @@ itests: itest itest: integration _tests _tests: py_env - bash -c 'source py_env/bin/activate && py.test tests $(TEST_TARGETS)' + bash -c 'source py_env/bin/activate && py.test tests $(TEST_TARGETS) $(DEBUG)' ucoverage: unit coverage icoverage: integration coverage diff --git a/pre_commit/clientlib/validate_base.py b/pre_commit/clientlib/validate_base.py index cef5eaec..d29d6fdf 100644 --- a/pre_commit/clientlib/validate_base.py +++ b/pre_commit/clientlib/validate_base.py @@ -48,4 +48,6 @@ def get_validator( additional_validation_strategy(obj) + return obj + return validate \ No newline at end of file diff --git a/pre_commit/repository.py b/pre_commit/repository.py index 3ec61263..df4de1c1 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -2,24 +2,50 @@ import contextlib from plumbum import local +import pre_commit.constants as C +from pre_commit.clientlib.validate_manifest import validate_manifest from pre_commit.hooks_workspace import in_hooks_workspace +from pre_commit.util import cached_property class Repository(object): def __init__(self, repo_config): self.repo_config = repo_config - @property + @cached_property def repo_url(self): return self.repo_config['repo'] - @property + @cached_property def sha(self): return self.repo_config['sha'] + @cached_property + def languages(self): + return set(filter(None, ( + hook.get('language') for hook in self.hooks.values() + ))) + + @cached_property + def hooks(self): + return dict( + (hook['id'], dict(hook, **self.manifest[hook['id']])) + for hook in self.repo_config['hooks'] + ) + + @cached_property + def manifest(self): + with self.in_checkout(): + return dict( + (hook['id'], hook) + for hook in validate_manifest(C.MANIFEST_FILE) + ) + @contextlib.contextmanager def in_checkout(self): with in_hooks_workspace(): + # SMELL: + self.create() with local.cwd(self.sha): yield @@ -33,6 +59,19 @@ class Repository(object): with self.in_checkout(): local['git']['checkout', self.sha]() + # TODO: make this shit polymorphic + + def _install_python(self): + assert local.path('setup.py').exists() + local['virtualenv']['py_env']() + local['bash']['-c', 'source py_env/bin/activate && pip install .']() + + def _install_ruby(self): + raise NotImplementedError + + def _install_node(self): + raise NotImplementedError + def install(self): # Create if we have not already self.create() diff --git a/pre_commit/util.py b/pre_commit/util.py new file mode 100644 index 00000000..924e8bf0 --- /dev/null +++ b/pre_commit/util.py @@ -0,0 +1,16 @@ + +class cached_property(object): + """Like @property, but caches the value.""" + + def __init__(self, func): + self.__name__ = func.__name__ + self.__module__ = func.__module__ + self.__doc__ = func.__doc__ + self._func = func + + def __get__(self, obj, cls): + if obj is None: + return self + value = self._func(obj) + obj.__dict__[self.__name__] = value + return value diff --git a/tests/clientlib/validate_base_test.py b/tests/clientlib/validate_base_test.py index 5da0b110..22c59296 100644 --- a/tests/clientlib/validate_base_test.py +++ b/tests/clientlib/validate_base_test.py @@ -64,4 +64,9 @@ def test_passes_array_schema(array_validator): def test_raises_when_additional_validation_fails(additional_validator): with pytest.raises(AdditionalValidatorError): - additional_validator() \ No newline at end of file + additional_validator() + + +def test_returns_object_after_validating(noop_validator): + ret = noop_validator('tests/data/array_yaml_file.yaml') + assert ret == ['foo', 'bar'] \ No newline at end of file diff --git a/tests/clientlib/validate_manifest_test.py b/tests/clientlib/validate_manifest_test.py index 1f15945b..e2b2c6a4 100644 --- a/tests/clientlib/validate_manifest_test.py +++ b/tests/clientlib/validate_manifest_test.py @@ -29,7 +29,7 @@ def test_additional_manifest_check_raises_for_bad_language(): @pytest.mark.parametrize(('obj'), ( [{}], [{'language': 'python'}], - [{'language': 'python>2.6'}], + [{'language': 'ruby'}], )) def test_additional_manifest_check_is_ok_with_missing_language(obj): additional_manifest_check(obj) diff --git a/tests/conftest.py b/tests/conftest.py index aa92ff11..d8817f1c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -31,22 +31,17 @@ def dummy_git_repo(empty_git_dir): @pytest.yield_fixture -def dummy_pre_commit_hooks_git_repo(dummy_git_repo): +def python_pre_commit_git_repo(dummy_git_repo): local.path(C.MANIFEST_FILE).write(""" -hooks: - - - id: foo - name: Foo - entry: foo - language: python>2.6 +- + id: foo + name: Foo + entry: foo + language: python """) add_and_commit() - yield dummy_git_repo - -@pytest.yield_fixture -def python_pre_commit_git_repo(dummy_pre_commit_hooks_git_repo): local.path('setup.py').write(""" from setuptools import find_packages from setuptools import setup @@ -61,8 +56,7 @@ setup( ], } ) -""" - ) + """) foo_module = local.path('foo') @@ -73,12 +67,11 @@ setup( local.path('main.py').write(""" def func(): return 0 -""" - ) + """) add_and_commit() - yield dummy_pre_commit_hooks_git_repo + yield dummy_git_repo @pytest.fixture diff --git a/tests/repository_test.py b/tests/repository_test.py index 78e86181..824d7b09 100644 --- a/tests/repository_test.py +++ b/tests/repository_test.py @@ -1,9 +1,10 @@ import os - +import jsonschema import pytest -from pre_commit import git import pre_commit.constants as C +from pre_commit import git +from pre_commit.clientlib.validate_config import CONFIG_JSON_SCHEMA from pre_commit.repository import Repository @@ -40,3 +41,36 @@ def test_install_python_repo_in_env(python_pre_commit_git_repo, config_for_pytho 'py_env', ), ) + + +@pytest.fixture +def mock_repo_config(): + config = { + 'repo': 'git@github.com:pre-commit/pre-commit-hooks', + 'sha': '5e713f8878b7d100c0e059f8cc34be4fc2e8f897', + 'hooks': [{ + 'id': 'pyflakes', + 'files': '*.py', + }], + } + + jsonschema.validate([config], CONFIG_JSON_SCHEMA) + + return config + + +def test_repo_url(mock_repo_config): + repo = Repository(mock_repo_config) + assert repo.repo_url == 'git@github.com:pre-commit/pre-commit-hooks' + + +def test_sha(mock_repo_config): + repo = Repository(mock_repo_config) + assert repo.sha == '5e713f8878b7d100c0e059f8cc34be4fc2e8f897' + + +@pytest.mark.integration +def test_languages(config_for_python_pre_commit_git_repo): + repo = Repository(config_for_python_pre_commit_git_repo) + assert repo.languages == set(['python']) +