From ebe3e59e35f40af7bd9711df52ff722726b9bb88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Fri, 1 May 2020 10:18:08 +0300 Subject: [PATCH] Allow local config only hooks If a repo does not have a manifest, go with local repo config only. --- pre_commit/clientlib.py | 14 ++++++++++++++ pre_commit/repository.py | 36 +++++++++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/pre_commit/clientlib.py b/pre_commit/clientlib.py index 56ec0dd1..7d88f5b2 100644 --- a/pre_commit/clientlib.py +++ b/pre_commit/clientlib.py @@ -5,8 +5,10 @@ import shlex import sys from typing import Any from typing import Dict +from typing import Mapping from typing import Optional from typing import Sequence +from typing import TypeVar import cfgv from identify.identify import ALL_TAGS @@ -89,6 +91,18 @@ load_manifest = functools.partial( ) +HOOK_CONFIG_T = TypeVar('HOOK_CONFIG_T', bound=Mapping[str, Any]) + + +def validate_manifest(data: HOOK_CONFIG_T) -> HOOK_CONFIG_T: + return cfgv.validate(data, MANIFEST_SCHEMA) + + +def apply_manifest_defaults(data: Sequence[HOOK_CONFIG_T]) \ + -> Sequence[HOOK_CONFIG_T]: + return cfgv.apply_defaults(data, MANIFEST_SCHEMA) + + def validate_manifest_main(argv: Optional[Sequence[str]] = None) -> int: parser = _make_argparser('Manifest filenames.') args = parser.parse_args(argv) diff --git a/pre_commit/repository.py b/pre_commit/repository.py index 77734ee6..75f8f048 100644 --- a/pre_commit/repository.py +++ b/pre_commit/repository.py @@ -10,9 +10,11 @@ from typing import Set from typing import Tuple import pre_commit.constants as C +from pre_commit.clientlib import apply_manifest_defaults from pre_commit.clientlib import load_manifest from pre_commit.clientlib import LOCAL from pre_commit.clientlib import META +from pre_commit.clientlib import validate_manifest from pre_commit.hook import Hook from pre_commit.languages.all import languages from pre_commit.languages.helpers import environment_dir @@ -146,21 +148,37 @@ def _cloned_repository_hooks( ) -> Tuple[Hook, ...]: repo, rev = repo_config['repo'], repo_config['rev'] manifest_path = os.path.join(store.clone(repo, rev), C.MANIFEST_FILE) - by_id = {hook['id']: hook for hook in load_manifest(manifest_path)} + if os.path.isfile(manifest_path): + by_id = {hook['id']: hook for hook in load_manifest(manifest_path)} - for hook in repo_config['hooks']: - if hook['id'] not in by_id: - logger.error( - f'`{hook["id"]}` is not present in repository {repo}. ' - f'Typo? Perhaps it is introduced in a newer version? ' - f'Often `pre-commit autoupdate` fixes this.', - ) - exit(1) + for hook in repo_config['hooks']: + if hook['id'] not in by_id: + logger.error( + f'`{hook["id"]}` is not present in repository {repo}. ' + f'Typo? Perhaps it is introduced in a newer version? ' + f'Often `pre-commit autoupdate` fixes this.', + ) + exit(1) + else: + logger.info( + f'No {C.MANIFEST_FILE} found in repository {repo}. ' + 'Proceeding with local repo config only.', + ) + by_id = { + hook['id']: hook + for hook in apply_manifest_defaults([ + {'id': repo_hook['id']} + for repo_hook in repo_config['hooks'] + ]) + } hook_dcts = [ _hook(by_id[hook['id']], hook, root_config=root_config) for hook in repo_config['hooks'] ] + if not by_id: + for hook_dct in hook_dcts: + validate_manifest(hook_dct) return tuple( Hook.create( repo_config['repo'],