Merge pull request #908 from asottile/default_language_version

Implement default_language_version
This commit is contained in:
Anthony Sottile 2019-01-05 13:47:18 -08:00 committed by GitHub
commit 9c6a1d80d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 150 additions and 103 deletions

View file

@ -27,7 +27,7 @@ repos:
rev: v1.3.0 rev: v1.3.0
hooks: hooks:
- id: reorder-python-imports - id: reorder-python-imports
language_version: python2.7 language_version: python3
- repo: https://github.com/asottile/add-trailing-comma - repo: https://github.com/asottile/add-trailing-comma
rev: v0.7.1 rev: v0.7.1
hooks: hooks:

View file

@ -55,7 +55,7 @@ MANIFEST_HOOK_DICT = cfgv.Map(
cfgv.Optional('always_run', cfgv.check_bool, False), cfgv.Optional('always_run', cfgv.check_bool, False),
cfgv.Optional('pass_filenames', cfgv.check_bool, True), cfgv.Optional('pass_filenames', cfgv.check_bool, True),
cfgv.Optional('description', cfgv.check_string, ''), cfgv.Optional('description', cfgv.check_string, ''),
cfgv.Optional('language_version', cfgv.check_string, 'default'), cfgv.Optional('language_version', cfgv.check_string, C.DEFAULT),
cfgv.Optional('log_file', cfgv.check_string, ''), cfgv.Optional('log_file', cfgv.check_string, ''),
cfgv.Optional('minimum_pre_commit_version', cfgv.check_string, '0'), cfgv.Optional('minimum_pre_commit_version', cfgv.check_string, '0'),
cfgv.Optional('require_serial', cfgv.check_bool, False), cfgv.Optional('require_serial', cfgv.check_bool, False),
@ -90,8 +90,8 @@ def validate_manifest_main(argv=None):
return ret return ret
_LOCAL = 'local' LOCAL = 'local'
_META = 'meta' META = 'meta'
class MigrateShaToRev(object): class MigrateShaToRev(object):
@ -100,12 +100,12 @@ class MigrateShaToRev(object):
return cfgv.Conditional( return cfgv.Conditional(
key, cfgv.check_string, key, cfgv.check_string,
condition_key='repo', condition_key='repo',
condition_value=cfgv.NotIn(_LOCAL, _META), condition_value=cfgv.NotIn(LOCAL, META),
ensure_absent=True, ensure_absent=True,
) )
def check(self, dct): def check(self, dct):
if dct.get('repo') in {_LOCAL, _META}: if dct.get('repo') in {LOCAL, META}:
self._cond('rev').check(dct) self._cond('rev').check(dct)
self._cond('sha').check(dct) self._cond('sha').check(dct)
elif 'sha' in dct and 'rev' in dct: elif 'sha' in dct and 'rev' in dct:
@ -159,12 +159,11 @@ _meta = (
META_HOOK_DICT = cfgv.Map( META_HOOK_DICT = cfgv.Map(
'Hook', 'id', 'Hook', 'id',
*([
cfgv.Required('id', cfgv.check_string), cfgv.Required('id', cfgv.check_string),
cfgv.Required('id', cfgv.check_one_of(tuple(k for k, _ in _meta))), cfgv.Required('id', cfgv.check_one_of(tuple(k for k, _ in _meta))),
# language must be system # language must be system
cfgv.Optional('language', cfgv.check_one_of({'system'}), 'system'), cfgv.Optional('language', cfgv.check_one_of({'system'}), 'system'),
] + [ *([
# default to the hook definition for the meta hooks # default to the hook definition for the meta hooks
cfgv.ConditionalOptional(key, cfgv.check_any, value, 'id', hook_id) cfgv.ConditionalOptional(key, cfgv.check_any, value, 'id', hook_id)
for hook_id, values in _meta for hook_id, values in _meta
@ -200,36 +199,36 @@ CONFIG_REPO_DICT = cfgv.Map(
cfgv.ConditionalRecurse( cfgv.ConditionalRecurse(
'hooks', cfgv.Array(CONFIG_HOOK_DICT), 'hooks', cfgv.Array(CONFIG_HOOK_DICT),
'repo', cfgv.NotIn(_LOCAL, _META), 'repo', cfgv.NotIn(LOCAL, META),
), ),
cfgv.ConditionalRecurse( cfgv.ConditionalRecurse(
'hooks', cfgv.Array(MANIFEST_HOOK_DICT), 'hooks', cfgv.Array(MANIFEST_HOOK_DICT),
'repo', _LOCAL, 'repo', LOCAL,
), ),
cfgv.ConditionalRecurse( cfgv.ConditionalRecurse(
'hooks', cfgv.Array(META_HOOK_DICT), 'hooks', cfgv.Array(META_HOOK_DICT),
'repo', _META, 'repo', META,
), ),
MigrateShaToRev(), MigrateShaToRev(),
) )
DEFAULT_LANGUAGE_VERSION = cfgv.Map(
'DefaultLanguageVersion', None,
cfgv.NoAdditionalKeys(all_languages),
*[cfgv.Optional(x, cfgv.check_string, C.DEFAULT) for x in all_languages]
)
CONFIG_SCHEMA = cfgv.Map( CONFIG_SCHEMA = cfgv.Map(
'Config', None, 'Config', None,
cfgv.RequiredRecurse('repos', cfgv.Array(CONFIG_REPO_DICT)), cfgv.RequiredRecurse('repos', cfgv.Array(CONFIG_REPO_DICT)),
cfgv.OptionalRecurse(
'default_language_version', DEFAULT_LANGUAGE_VERSION, {},
),
cfgv.Optional('exclude', cfgv.check_regex, '^$'), cfgv.Optional('exclude', cfgv.check_regex, '^$'),
cfgv.Optional('fail_fast', cfgv.check_bool, False), cfgv.Optional('fail_fast', cfgv.check_bool, False),
) )
def is_local_repo(repo_entry):
return repo_entry['repo'] == _LOCAL
def is_meta_repo(repo_entry):
return repo_entry['repo'] == _META
class InvalidConfigError(FatalError): class InvalidConfigError(FatalError):
pass pass

View file

@ -13,10 +13,10 @@ import pre_commit.constants as C
from pre_commit import output from pre_commit import output
from pre_commit.clientlib import CONFIG_SCHEMA from pre_commit.clientlib import CONFIG_SCHEMA
from pre_commit.clientlib import InvalidManifestError from pre_commit.clientlib import InvalidManifestError
from pre_commit.clientlib import is_local_repo
from pre_commit.clientlib import is_meta_repo
from pre_commit.clientlib import load_config from pre_commit.clientlib import load_config
from pre_commit.clientlib import load_manifest from pre_commit.clientlib import load_manifest
from pre_commit.clientlib import LOCAL
from pre_commit.clientlib import META
from pre_commit.commands.migrate_config import migrate_config from pre_commit.commands.migrate_config import migrate_config
from pre_commit.util import CalledProcessError from pre_commit.util import CalledProcessError
from pre_commit.util import cmd_output from pre_commit.util import cmd_output
@ -123,8 +123,7 @@ def autoupdate(config_file, store, tags_only, repos=()):
for repo_config in input_config['repos']: for repo_config in input_config['repos']:
if ( if (
is_local_repo(repo_config) or repo_config['repo'] in {LOCAL, META} or
is_meta_repo(repo_config) or
# Skip updating any repo_configs that aren't for the specified repo # Skip updating any repo_configs that aren't for the specified repo
repos and repo_config['repo'] not in repos repos and repo_config['repo'] not in repos
): ):

View file

@ -7,16 +7,16 @@ import pre_commit.constants as C
from pre_commit import output from pre_commit import output
from pre_commit.clientlib import InvalidConfigError from pre_commit.clientlib import InvalidConfigError
from pre_commit.clientlib import InvalidManifestError from pre_commit.clientlib import InvalidManifestError
from pre_commit.clientlib import is_local_repo
from pre_commit.clientlib import is_meta_repo
from pre_commit.clientlib import load_config from pre_commit.clientlib import load_config
from pre_commit.clientlib import load_manifest from pre_commit.clientlib import load_manifest
from pre_commit.clientlib import LOCAL
from pre_commit.clientlib import META
def _mark_used_repos(store, all_repos, unused_repos, repo): def _mark_used_repos(store, all_repos, unused_repos, repo):
if is_meta_repo(repo): if repo['repo'] == META:
return return
elif is_local_repo(repo): elif repo['repo'] == LOCAL:
for hook in repo['hooks']: for hook in repo['hooks']:
deps = hook.get('additional_dependencies') deps = hook.get('additional_dependencies')
unused_repos.discard(( unused_repos.discard((

View file

@ -6,6 +6,7 @@ import logging
import os.path import os.path
import sys import sys
import pre_commit.constants as C
from pre_commit import git from pre_commit import git
from pre_commit import output from pre_commit import output
from pre_commit.clientlib import load_config from pre_commit.clientlib import load_config
@ -51,7 +52,7 @@ def shebang():
py = 'python' py = 'python'
else: else:
py = python.get_default_version() py = python.get_default_version()
if py == 'default': if py == C.DEFAULT:
py = 'python' py = 'python'
return '#!/usr/bin/env {}'.format(py) return '#!/usr/bin/env {}'.format(py)

View file

@ -22,3 +22,5 @@ VERSION = importlib_metadata.version('pre_commit')
# `manual` is not invoked by any installed git hook. See #719 # `manual` is not invoked by any installed git hook. See #719
STAGES = ('commit', 'commit-msg', 'manual', 'push') STAGES = ('commit', 'commit-msg', 'manual', 'push')
DEFAULT = 'default'

View file

@ -35,8 +35,7 @@ from pre_commit.languages import system
# #
# Args: # Args:
# prefix - `Prefix` bound to the repository. # prefix - `Prefix` bound to the repository.
# version - A version specified in the hook configuration or # version - A version specified in the hook configuration or 'default'.
# 'default'.
# """ # """
# #
# def run_hook(hook, file_args): # def run_hook(hook, file_args):

View file

@ -4,6 +4,7 @@ from __future__ import unicode_literals
import hashlib import hashlib
import os import os
import pre_commit.constants as C
from pre_commit import five from pre_commit import five
from pre_commit.languages import helpers from pre_commit.languages import helpers
from pre_commit.util import CalledProcessError from pre_commit.util import CalledProcessError
@ -62,7 +63,7 @@ def install_environment(
assert_docker_available() assert_docker_available()
directory = prefix.path( directory = prefix.path(
helpers.environment_dir(ENVIRONMENT_DIR, 'default'), helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT),
) )
# Docker doesn't really have relevant disk environment, but pre-commit # Docker doesn't really have relevant disk environment, but pre-commit

View file

@ -4,6 +4,7 @@ import contextlib
import os.path import os.path
import sys import sys
import pre_commit.constants as C
from pre_commit import git from pre_commit import git
from pre_commit.envcontext import envcontext from pre_commit.envcontext import envcontext
from pre_commit.envcontext import Var from pre_commit.envcontext import Var
@ -27,7 +28,7 @@ def get_env_patch(venv):
@contextlib.contextmanager @contextlib.contextmanager
def in_env(prefix): def in_env(prefix):
envdir = prefix.path( envdir = prefix.path(
helpers.environment_dir(ENVIRONMENT_DIR, 'default'), helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT),
) )
with envcontext(get_env_patch(envdir)): with envcontext(get_env_patch(envdir)):
yield yield
@ -52,7 +53,7 @@ def guess_go_dir(remote_url):
def install_environment(prefix, version, additional_dependencies): def install_environment(prefix, version, additional_dependencies):
helpers.assert_version_default('golang', version) helpers.assert_version_default('golang', version)
directory = prefix.path( directory = prefix.path(
helpers.environment_dir(ENVIRONMENT_DIR, 'default'), helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT),
) )
with clean_path_on_failure(directory): with clean_path_on_failure(directory):

View file

@ -7,10 +7,10 @@ import shlex
import six import six
import pre_commit.constants as C
from pre_commit.util import cmd_output from pre_commit.util import cmd_output
from pre_commit.xargs import xargs from pre_commit.xargs import xargs
FIXED_RANDOM_SEED = 1542676186 FIXED_RANDOM_SEED = 1542676186
@ -30,7 +30,7 @@ def to_cmd(hook):
def assert_version_default(binary, version): def assert_version_default(binary, version):
if version != 'default': if version != C.DEFAULT:
raise AssertionError( raise AssertionError(
'For now, pre-commit requires system-installed {}'.format(binary), 'For now, pre-commit requires system-installed {}'.format(binary),
) )
@ -45,7 +45,7 @@ def assert_no_additional_deps(lang, additional_deps):
def basic_get_default_version(): def basic_get_default_version():
return 'default' return C.DEFAULT
def basic_healthy(prefix, language_version): def basic_healthy(prefix, language_version):

View file

@ -4,6 +4,7 @@ import contextlib
import os import os
import sys import sys
import pre_commit.constants as C
from pre_commit.envcontext import envcontext from pre_commit.envcontext import envcontext
from pre_commit.envcontext import Var from pre_commit.envcontext import Var
from pre_commit.languages import helpers from pre_commit.languages import helpers
@ -57,7 +58,7 @@ def install_environment(prefix, version, additional_dependencies):
cmd = [ cmd = [
sys.executable, '-mnodeenv', '--prebuilt', '--clean-src', envdir, sys.executable, '-mnodeenv', '--prebuilt', '--clean-src', envdir,
] ]
if version != 'default': if version != C.DEFAULT:
cmd.extend(['-n', version]) cmd.extend(['-n', version])
cmd_output(*cmd) cmd_output(*cmd)

View file

@ -4,6 +4,7 @@ import contextlib
import os import os
import sys import sys
import pre_commit.constants as C
from pre_commit.envcontext import envcontext from pre_commit.envcontext import envcontext
from pre_commit.envcontext import UNSET from pre_commit.envcontext import UNSET
from pre_commit.envcontext import Var from pre_commit.envcontext import Var
@ -76,7 +77,7 @@ def _get_default_version(): # pragma: no cover (platform dependent)
return exe return exe
# We tried! # We tried!
return 'default' return C.DEFAULT
def get_default_version(): def get_default_version():
@ -134,7 +135,7 @@ def py_interface(_dir, _make_venv):
env_dir = prefix.path(directory) env_dir = prefix.path(directory)
with clean_path_on_failure(env_dir): with clean_path_on_failure(env_dir):
if version != 'default': if version != C.DEFAULT:
python = norm_version(version) python = norm_version(version)
else: else:
python = os.path.realpath(sys.executable) python = os.path.realpath(sys.executable)

View file

@ -6,6 +6,7 @@ import os.path
import shutil import shutil
import tarfile import tarfile
import pre_commit.constants as C
from pre_commit.envcontext import envcontext from pre_commit.envcontext import envcontext
from pre_commit.envcontext import Var from pre_commit.envcontext import Var
from pre_commit.languages import helpers from pre_commit.languages import helpers
@ -32,7 +33,7 @@ def get_env_patch(venv, language_version): # pragma: windows no cover
), ),
), ),
) )
if language_version != 'default': if language_version != C.DEFAULT:
patches += (('RBENV_VERSION', language_version),) patches += (('RBENV_VERSION', language_version),)
return patches return patches
@ -52,14 +53,14 @@ def _extract_resource(filename, dest):
tf.extractall(dest) tf.extractall(dest)
def _install_rbenv(prefix, version='default'): # pragma: windows no cover def _install_rbenv(prefix, version=C.DEFAULT): # pragma: windows no cover
directory = helpers.environment_dir(ENVIRONMENT_DIR, version) directory = helpers.environment_dir(ENVIRONMENT_DIR, version)
_extract_resource('rbenv.tar.gz', prefix.path('.')) _extract_resource('rbenv.tar.gz', prefix.path('.'))
shutil.move(prefix.path('rbenv'), prefix.path(directory)) shutil.move(prefix.path('rbenv'), prefix.path(directory))
# Only install ruby-build if the version is specified # Only install ruby-build if the version is specified
if version != 'default': if version != C.DEFAULT:
plugins_dir = prefix.path(directory, 'plugins') plugins_dir = prefix.path(directory, 'plugins')
_extract_resource('ruby-download.tar.gz', plugins_dir) _extract_resource('ruby-download.tar.gz', plugins_dir)
_extract_resource('ruby-build.tar.gz', plugins_dir) _extract_resource('ruby-build.tar.gz', plugins_dir)
@ -84,7 +85,7 @@ def _install_rbenv(prefix, version='default'): # pragma: windows no cover
) )
# If we aren't using the system ruby, add a version here # If we aren't using the system ruby, add a version here
if version != 'default': if version != C.DEFAULT:
activate_file.write('export RBENV_VERSION="{}"\n'.format(version)) activate_file.write('export RBENV_VERSION="{}"\n'.format(version))
@ -109,7 +110,7 @@ def install_environment(
# Need to call this before installing so rbenv's directories are # Need to call this before installing so rbenv's directories are
# set up # set up
helpers.run_setup_cmd(prefix, ('rbenv', 'init', '-')) helpers.run_setup_cmd(prefix, ('rbenv', 'init', '-'))
if version != 'default': if version != C.DEFAULT:
_install_ruby(prefix, version) _install_ruby(prefix, version)
# Need to call this after installing to set up the shims # Need to call this after installing to set up the shims
helpers.run_setup_cmd(prefix, ('rbenv', 'rehash')) helpers.run_setup_cmd(prefix, ('rbenv', 'rehash'))

View file

@ -5,6 +5,7 @@ import os.path
import toml import toml
import pre_commit.constants as C
from pre_commit.envcontext import envcontext from pre_commit.envcontext import envcontext
from pre_commit.envcontext import Var from pre_commit.envcontext import Var
from pre_commit.languages import helpers from pre_commit.languages import helpers
@ -29,7 +30,7 @@ def get_env_patch(target_dir):
@contextlib.contextmanager @contextlib.contextmanager
def in_env(prefix): def in_env(prefix):
target_dir = prefix.path( target_dir = prefix.path(
helpers.environment_dir(ENVIRONMENT_DIR, 'default'), helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT),
) )
with envcontext(get_env_patch(target_dir)): with envcontext(get_env_patch(target_dir)):
yield yield
@ -50,7 +51,7 @@ def _add_dependencies(cargo_toml_path, additional_dependencies):
def install_environment(prefix, version, additional_dependencies): def install_environment(prefix, version, additional_dependencies):
helpers.assert_version_default('rust', version) helpers.assert_version_default('rust', version)
directory = prefix.path( directory = prefix.path(
helpers.environment_dir(ENVIRONMENT_DIR, 'default'), helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT),
) )
# There are two cases where we might want to specify more dependencies: # There are two cases where we might want to specify more dependencies:

View file

@ -3,6 +3,7 @@ from __future__ import unicode_literals
import contextlib import contextlib
import os import os
import pre_commit.constants as C
from pre_commit.envcontext import envcontext from pre_commit.envcontext import envcontext
from pre_commit.envcontext import Var from pre_commit.envcontext import Var
from pre_commit.languages import helpers from pre_commit.languages import helpers
@ -24,7 +25,7 @@ def get_env_patch(venv): # pragma: windows no cover
@contextlib.contextmanager @contextlib.contextmanager
def in_env(prefix): # pragma: windows no cover def in_env(prefix): # pragma: windows no cover
envdir = prefix.path( envdir = prefix.path(
helpers.environment_dir(ENVIRONMENT_DIR, 'default'), helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT),
) )
with envcontext(get_env_patch(envdir)): with envcontext(get_env_patch(envdir)):
yield yield
@ -36,7 +37,7 @@ def install_environment(
helpers.assert_version_default('swift', version) helpers.assert_version_default('swift', version)
helpers.assert_no_additional_deps('swift', additional_dependencies) helpers.assert_no_additional_deps('swift', additional_dependencies)
directory = prefix.path( directory = prefix.path(
helpers.environment_dir(ENVIRONMENT_DIR, 'default'), helpers.environment_dir(ENVIRONMENT_DIR, C.DEFAULT),
) )
# Build the swift package # Build the swift package

View file

@ -8,10 +8,10 @@ import os
import pre_commit.constants as C import pre_commit.constants as C
from pre_commit import five from pre_commit import five
from pre_commit.clientlib import is_local_repo
from pre_commit.clientlib import is_meta_repo
from pre_commit.clientlib import load_manifest from pre_commit.clientlib import load_manifest
from pre_commit.clientlib import LOCAL
from pre_commit.clientlib import MANIFEST_HOOK_DICT from pre_commit.clientlib import MANIFEST_HOOK_DICT
from pre_commit.clientlib import META
from pre_commit.languages.all import languages from pre_commit.languages.all import languages
from pre_commit.languages.helpers import environment_dir from pre_commit.languages.helpers import environment_dir
from pre_commit.prefix import Prefix from pre_commit.prefix import Prefix
@ -111,7 +111,9 @@ class Hook(collections.namedtuple('Hook', ('src', 'prefix') + _KEYS)):
return cls(src=src, prefix=prefix, **{k: dct[k] for k in _KEYS}) return cls(src=src, prefix=prefix, **{k: dct[k] for k in _KEYS})
def _hook(*hook_dicts): def _hook(*hook_dicts, **kwargs):
root_config = kwargs.pop('root_config')
assert not kwargs, kwargs
ret, rest = dict(hook_dicts[0]), hook_dicts[1:] ret, rest = dict(hook_dicts[0]), hook_dicts[1:]
for dct in rest: for dct in rest:
ret.update(dct) ret.update(dct)
@ -127,14 +129,16 @@ def _hook(*hook_dicts):
) )
exit(1) exit(1)
if ret['language_version'] == 'default': lang = ret['language']
language = languages[ret['language']] if ret['language_version'] == C.DEFAULT:
ret['language_version'] = language.get_default_version() ret['language_version'] = root_config['default_language_version'][lang]
if ret['language_version'] == C.DEFAULT:
ret['language_version'] = languages[lang].get_default_version()
return ret return ret
def _non_cloned_repository_hooks(repo_config, store): def _non_cloned_repository_hooks(repo_config, store, root_config):
def _prefix(language_name, deps): def _prefix(language_name, deps):
language = languages[language_name] language = languages[language_name]
# pcre / pygrep / script / system / docker_image do not have # pcre / pygrep / script / system / docker_image do not have
@ -148,13 +152,13 @@ def _non_cloned_repository_hooks(repo_config, store):
Hook.create( Hook.create(
repo_config['repo'], repo_config['repo'],
_prefix(hook['language'], hook['additional_dependencies']), _prefix(hook['language'], hook['additional_dependencies']),
_hook(hook), _hook(hook, root_config=root_config),
) )
for hook in repo_config['hooks'] for hook in repo_config['hooks']
) )
def _cloned_repository_hooks(repo_config, store): def _cloned_repository_hooks(repo_config, store, root_config):
repo, rev = repo_config['repo'], repo_config['rev'] repo, rev = repo_config['repo'], repo_config['rev']
manifest_path = os.path.join(store.clone(repo, rev), C.MANIFEST_FILE) manifest_path = os.path.join(store.clone(repo, rev), C.MANIFEST_FILE)
by_id = {hook['id']: hook for hook in load_manifest(manifest_path)} by_id = {hook['id']: hook for hook in load_manifest(manifest_path)}
@ -169,7 +173,10 @@ def _cloned_repository_hooks(repo_config, store):
) )
exit(1) exit(1)
hook_dcts = [_hook(by_id[h['id']], h) for h in repo_config['hooks']] hook_dcts = [
_hook(by_id[hook['id']], hook, root_config=root_config)
for hook in repo_config['hooks']
]
return tuple( return tuple(
Hook.create( Hook.create(
repo_config['repo'], repo_config['repo'],
@ -180,11 +187,11 @@ def _cloned_repository_hooks(repo_config, store):
) )
def repository_hooks(repo_config, store): def _repository_hooks(repo_config, store, root_config):
if is_local_repo(repo_config) or is_meta_repo(repo_config): if repo_config['repo'] in {LOCAL, META}:
return _non_cloned_repository_hooks(repo_config, store) return _non_cloned_repository_hooks(repo_config, store, root_config)
else: else:
return _cloned_repository_hooks(repo_config, store) return _cloned_repository_hooks(repo_config, store, root_config)
def install_hook_envs(hooks, store): def install_hook_envs(hooks, store):
@ -201,17 +208,13 @@ def install_hook_envs(hooks, store):
return return
with store.exclusive_lock(): with store.exclusive_lock():
# Another process may have already completed this work # Another process may have already completed this work
need_installed = _need_installed() for hook in _need_installed():
if not need_installed: # pragma: no cover (race)
return
for hook in need_installed:
hook.install() hook.install()
def all_hooks(config, store): def all_hooks(root_config, store):
return tuple( return tuple(
hook hook
for repo in config['repos'] for repo in root_config['repos']
for hook in repository_hooks(repo, store) for hook in _repository_hooks(repo, store, root_config)
) )

View file

@ -2,11 +2,11 @@ from __future__ import absolute_import
from __future__ import division from __future__ import division
from __future__ import unicode_literals from __future__ import unicode_literals
import concurrent.futures
import contextlib import contextlib
import math import math
import sys import sys
import concurrent.futures
import six import six
from pre_commit import parse_shebang from pre_commit import parse_shebang

View file

@ -7,7 +7,7 @@ from pre_commit.clientlib import check_type_tag
from pre_commit.clientlib import CONFIG_HOOK_DICT from pre_commit.clientlib import CONFIG_HOOK_DICT
from pre_commit.clientlib import CONFIG_REPO_DICT from pre_commit.clientlib import CONFIG_REPO_DICT
from pre_commit.clientlib import CONFIG_SCHEMA from pre_commit.clientlib import CONFIG_SCHEMA
from pre_commit.clientlib import is_local_repo from pre_commit.clientlib import DEFAULT_LANGUAGE_VERSION
from pre_commit.clientlib import MANIFEST_SCHEMA from pre_commit.clientlib import MANIFEST_SCHEMA
from pre_commit.clientlib import MigrateShaToRev from pre_commit.clientlib import MigrateShaToRev
from pre_commit.clientlib import validate_config_main from pre_commit.clientlib import validate_config_main
@ -30,10 +30,6 @@ def test_check_type_tag_failures(value):
check_type_tag(value) check_type_tag(value)
def test_is_local_repo():
assert is_local_repo({'repo': 'local'})
@pytest.mark.parametrize( @pytest.mark.parametrize(
('args', 'expected_output'), ('args', 'expected_output'),
( (
@ -250,6 +246,20 @@ def test_migrate_to_sha_ok():
{'repo': 'meta', 'hooks': [{'id': 'identity', 'name': False}]}, {'repo': 'meta', 'hooks': [{'id': 'identity', 'name': False}]},
), ),
) )
def test_meta_hook_invalid_id(config_repo): def test_meta_hook_invalid(config_repo):
with pytest.raises(cfgv.ValidationError): with pytest.raises(cfgv.ValidationError):
cfgv.validate(config_repo, CONFIG_REPO_DICT) cfgv.validate(config_repo, CONFIG_REPO_DICT)
@pytest.mark.parametrize(
'mapping',
(
# invalid language key
{'pony': '1.0'},
# not a string for version
{'python': 3},
),
)
def test_default_language_version_invalid(mapping):
with pytest.raises(cfgv.ValidationError):
cfgv.validate(mapping, DEFAULT_LANGUAGE_VERSION)

View file

@ -110,10 +110,10 @@ def test_gc_config_with_missing_hook(
path = make_repo(tempdir_factory, 'script_hooks_repo') path = make_repo(tempdir_factory, 'script_hooks_repo')
write_config('.', make_config_from_repo(path)) write_config('.', make_config_from_repo(path))
store.mark_config_used(C.CONFIG_FILE) store.mark_config_used(C.CONFIG_FILE)
# to trigger a clone
all_hooks(load_config(C.CONFIG_FILE), store)
with modify_config() as config: with modify_config() as config:
# just to trigger a clone
all_hooks(config, store)
# add a hook which does not exist, make sure we don't crash # add a hook which does not exist, make sure we don't crash
config['repos'][0]['hooks'].append({'id': 'does-not-exist'}) config['repos'][0]['hooks'].append({'id': 'does-not-exist'})

View file

@ -53,13 +53,13 @@ def test_shebang_windows():
def test_shebang_otherwise(): def test_shebang_otherwise():
with mock.patch.object(sys, 'platform', 'posix'): with mock.patch.object(sys, 'platform', 'posix'):
assert 'default' not in shebang() assert C.DEFAULT not in shebang()
def test_shebang_returns_default(): def test_shebang_returns_default():
with mock.patch.object(sys, 'platform', 'posix'): with mock.patch.object(sys, 'platform', 'posix'):
with mock.patch.object( with mock.patch.object(
python, 'get_default_version', return_value='default', python, 'get_default_version', return_value=C.DEFAULT,
): ):
assert shebang() == '#!/usr/bin/env python' assert shebang() == '#!/usr/bin/env python'

View file

@ -8,6 +8,7 @@ import sys
import mock import mock
import pytest import pytest
import pre_commit.constants as C
from pre_commit.languages import helpers from pre_commit.languages import helpers
from pre_commit.prefix import Prefix from pre_commit.prefix import Prefix
from pre_commit.util import CalledProcessError from pre_commit.util import CalledProcessError
@ -15,7 +16,7 @@ from testing.auto_namedtuple import auto_namedtuple
def test_basic_get_default_version(): def test_basic_get_default_version():
assert helpers.basic_get_default_version() == 'default' assert helpers.basic_get_default_version() == C.DEFAULT
def test_basic_healthy(): def test_basic_healthy():

View file

@ -12,7 +12,7 @@ import pytest
import pre_commit.constants as C import pre_commit.constants as C
from pre_commit import five from pre_commit import five
from pre_commit import parse_shebang from pre_commit import parse_shebang
from pre_commit.clientlib import CONFIG_REPO_DICT from pre_commit.clientlib import CONFIG_SCHEMA
from pre_commit.clientlib import load_manifest from pre_commit.clientlib import load_manifest
from pre_commit.languages import golang from pre_commit.languages import golang
from pre_commit.languages import helpers from pre_commit.languages import helpers
@ -22,9 +22,9 @@ from pre_commit.languages import python
from pre_commit.languages import ruby from pre_commit.languages import ruby
from pre_commit.languages import rust from pre_commit.languages import rust
from pre_commit.prefix import Prefix from pre_commit.prefix import Prefix
from pre_commit.repository import all_hooks
from pre_commit.repository import Hook from pre_commit.repository import Hook
from pre_commit.repository import install_hook_envs from pre_commit.repository import install_hook_envs
from pre_commit.repository import repository_hooks
from pre_commit.util import cmd_output from pre_commit.util import cmd_output
from testing.fixtures import make_config_from_repo from testing.fixtures import make_config_from_repo
from testing.fixtures import make_repo from testing.fixtures import make_repo
@ -43,15 +43,21 @@ def _norm_out(b):
return b.replace(b'\r\n', b'\n') return b.replace(b'\r\n', b'\n')
def _get_hook(config, store, hook_id): def _get_hook_no_install(repo_config, store, hook_id):
config = cfgv.validate(config, CONFIG_REPO_DICT) config = {'repos': [repo_config]}
config = cfgv.apply_defaults(config, CONFIG_REPO_DICT) config = cfgv.validate(config, CONFIG_SCHEMA)
hooks = repository_hooks(config, store) config = cfgv.apply_defaults(config, CONFIG_SCHEMA)
install_hook_envs(hooks, store) hooks = all_hooks(config, store)
hook, = [hook for hook in hooks if hook.id == hook_id] hook, = [hook for hook in hooks if hook.id == hook_id]
return hook return hook
def _get_hook(repo_config, store, hook_id):
hook = _get_hook_no_install(repo_config, store, hook_id)
install_hook_envs([hook], store)
return hook
def _test_hook_repo( def _test_hook_repo(
tempdir_factory, tempdir_factory,
store, store,
@ -81,7 +87,7 @@ def test_python_hook_default_version(tempdir_factory, store):
# make sure that this continues to work for platforms where default # make sure that this continues to work for platforms where default
# language detection does not work # language detection does not work
with mock.patch.object( with mock.patch.object(
python, 'get_default_version', return_value='default', python, 'get_default_version', return_value=C.DEFAULT,
): ):
test_python_hook(tempdir_factory, store) test_python_hook(tempdir_factory, store)
@ -278,7 +284,7 @@ def test_additional_rust_cli_dependencies_installed(
config['hooks'][0]['additional_dependencies'] = [dep] config['hooks'][0]['additional_dependencies'] = [dep]
hook = _get_hook(config, store, 'rust-hook') hook = _get_hook(config, store, 'rust-hook')
binaries = os.listdir(hook.prefix.path( binaries = os.listdir(hook.prefix.path(
helpers.environment_dir(rust.ENVIRONMENT_DIR, 'default'), 'bin', helpers.environment_dir(rust.ENVIRONMENT_DIR, C.DEFAULT), 'bin',
)) ))
# normalize for windows # normalize for windows
binaries = [os.path.splitext(binary)[0] for binary in binaries] binaries = [os.path.splitext(binary)[0] for binary in binaries]
@ -295,7 +301,7 @@ def test_additional_rust_lib_dependencies_installed(
config['hooks'][0]['additional_dependencies'] = deps config['hooks'][0]['additional_dependencies'] = deps
hook = _get_hook(config, store, 'rust-hook') hook = _get_hook(config, store, 'rust-hook')
binaries = os.listdir(hook.prefix.path( binaries = os.listdir(hook.prefix.path(
helpers.environment_dir(rust.ENVIRONMENT_DIR, 'default'), 'bin', helpers.environment_dir(rust.ENVIRONMENT_DIR, C.DEFAULT), 'bin',
)) ))
# normalize for windows # normalize for windows
binaries = [os.path.splitext(binary)[0] for binary in binaries] binaries = [os.path.splitext(binary)[0] for binary in binaries]
@ -494,7 +500,7 @@ def test_additional_golang_dependencies_installed(
config['hooks'][0]['additional_dependencies'] = deps config['hooks'][0]['additional_dependencies'] = deps
hook = _get_hook(config, store, 'golang-hook') hook = _get_hook(config, store, 'golang-hook')
binaries = os.listdir(hook.prefix.path( binaries = os.listdir(hook.prefix.path(
helpers.environment_dir(golang.ENVIRONMENT_DIR, 'default'), 'bin', helpers.environment_dir(golang.ENVIRONMENT_DIR, C.DEFAULT), 'bin',
)) ))
# normalize for windows # normalize for windows
binaries = [os.path.splitext(binary)[0] for binary in binaries] binaries = [os.path.splitext(binary)[0] for binary in binaries]
@ -588,7 +594,7 @@ def test_control_c_control_c_on_install(tempdir_factory, store):
"""Regression test for #186.""" """Regression test for #186."""
path = make_repo(tempdir_factory, 'python_hooks_repo') path = make_repo(tempdir_factory, 'python_hooks_repo')
config = make_config_from_repo(path) config = make_config_from_repo(path)
hooks = repository_hooks(config, store) hooks = [_get_hook_no_install(config, store, 'foo')]
class MyKeyboardInterrupt(KeyboardInterrupt): class MyKeyboardInterrupt(KeyboardInterrupt):
pass pass
@ -686,22 +692,42 @@ def test_tags_on_repositories(in_tmpdir, tempdir_factory, store):
assert ret2[1] == b'bar\nHello World\n' assert ret2[1] == b'bar\nHello World\n'
def test_local_python_repo(store): @pytest.fixture
def local_python_config():
# Make a "local" hooks repo that just installs our other hooks repo # Make a "local" hooks repo that just installs our other hooks repo
repo_path = get_resource_path('python_hooks_repo') repo_path = get_resource_path('python_hooks_repo')
manifest = load_manifest(os.path.join(repo_path, C.MANIFEST_FILE)) manifest = load_manifest(os.path.join(repo_path, C.MANIFEST_FILE))
hooks = [ hooks = [
dict(hook, additional_dependencies=[repo_path]) for hook in manifest dict(hook, additional_dependencies=[repo_path]) for hook in manifest
] ]
config = {'repo': 'local', 'hooks': hooks} return {'repo': 'local', 'hooks': hooks}
hook = _get_hook(config, store, 'foo')
def test_local_python_repo(store, local_python_config):
hook = _get_hook(local_python_config, store, 'foo')
# language_version should have been adjusted to the interpreter version # language_version should have been adjusted to the interpreter version
assert hook.language_version != 'default' assert hook.language_version != C.DEFAULT
ret = hook.run(('filename',)) ret = hook.run(('filename',))
assert ret[0] == 0 assert ret[0] == 0
assert _norm_out(ret[1]) == b"['filename']\nHello World\n" assert _norm_out(ret[1]) == b"['filename']\nHello World\n"
def test_default_language_version(store, local_python_config):
config = {
'default_language_version': {'python': 'fake'},
'repos': [local_python_config],
}
# `language_version` was not set, should default
hook, = all_hooks(config, store)
assert hook.language_version == 'fake'
# `language_version` is set, should not default
config['repos'][0]['hooks'][0]['language_version'] = 'fake2'
hook, = all_hooks(config, store)
assert hook.language_version == 'fake2'
def test_hook_id_not_present(tempdir_factory, store, fake_log_handler): def test_hook_id_not_present(tempdir_factory, store, fake_log_handler):
path = make_repo(tempdir_factory, 'script_hooks_repo') path = make_repo(tempdir_factory, 'script_hooks_repo')
config = make_config_from_repo(path) config = make_config_from_repo(path)
@ -760,7 +786,7 @@ def test_manifest_hooks(tempdir_factory, store):
files='', files='',
id='bash_hook', id='bash_hook',
language='script', language='script',
language_version='default', language_version=C.DEFAULT,
log_file='', log_file='',
minimum_pre_commit_version='0', minimum_pre_commit_version='0',
name='Bash hook', name='Bash hook',

View file

@ -2,10 +2,10 @@
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import unicode_literals from __future__ import unicode_literals
import concurrent.futures
import sys import sys
import time import time
import concurrent.futures
import mock import mock
import pytest import pytest
import six import six