From ade67be453a1a8949c491a35feba6db3272047b1 Mon Sep 17 00:00:00 2001 From: Olli Raula Date: Thu, 28 May 2020 16:55:18 +0300 Subject: [PATCH] Add check_path hook Adds a hook which can be used for preventing commits to paths specified by regex. --- .pre-commit-hooks.yaml | 5 ++++ README.md | 5 ++++ pre_commit_hooks/check_path_edits.py | 40 +++++++++++++++++++++++++ setup.cfg | 1 + tests/check_path_edits_test.py | 45 ++++++++++++++++++++++++++++ 5 files changed, 96 insertions(+) create mode 100644 pre_commit_hooks/check_path_edits.py create mode 100644 tests/check_path_edits_test.py diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 3e4dc9e..9f77e11 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -10,6 +10,11 @@ description: Prevent giant files from being committed entry: check-added-large-files language: python +- id: check-path-edits + name: Check for path edits + description: Prevent edits tp specified path + entry: check-path-edits + language: python - id: check-ast name: Check python ast description: Simply check whether the files parse as valid python. diff --git a/README.md b/README.md index 6c7fba9..b1977e0 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,11 @@ Attempts to load all json files to verify syntax. #### `check-merge-conflict` Check for files that contain merge conflict strings. +#### `check-path-edits` +Prevent files in specific paths from being committed. + - Specify path patterns with regex `args: ["--pattern", "^tmp.*"]`. + - Pattern can be specified many times. + #### `check-symlinks` Checks for symlinks which do not point to anything. diff --git a/pre_commit_hooks/check_path_edits.py b/pre_commit_hooks/check_path_edits.py new file mode 100644 index 0000000..6f82087 --- /dev/null +++ b/pre_commit_hooks/check_path_edits.py @@ -0,0 +1,40 @@ +import argparse +import re +from typing import AbstractSet +from typing import Optional +from typing import Sequence + +from pre_commit_hooks.util import added_files + + +def find_wrong_paths(paths: Sequence[str], patterns: AbstractSet[str]) \ + -> int: + for filename in (added_files() & set(paths)): + if patterns: + for pattern in patterns: + if re.search(pattern, filename): + print(f'Path {filename} prevented by pattern: {pattern}') + return 1 + return 0 + + +def main(argv: Optional[Sequence[str]] = None) -> int: + parser = argparse.ArgumentParser() + parser.add_argument( + 'filenames', nargs='*', + help='Filenames pre-commit believes are changed.', + ) + parser.add_argument( + '-p', '--pattern', action='append', + help=( + 'regex pattern for path to disallow commits to, ' + 'may be specified multiple times' + ), + ) + + args = parser.parse_args(argv) + return find_wrong_paths(args.filenames, args.pattern) + + +if __name__ == '__main__': + exit(main()) diff --git a/setup.cfg b/setup.cfg index 0f7721f..515369a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -36,6 +36,7 @@ console_scripts = check-docstring-first = pre_commit_hooks.check_docstring_first:main check-executables-have-shebangs = pre_commit_hooks.check_executables_have_shebangs:main check-json = pre_commit_hooks.check_json:main + check-path-edits = pre_commit_hooks.check_path_edits:main check-merge-conflict = pre_commit_hooks.check_merge_conflict:main check-symlinks = pre_commit_hooks.check_symlinks:main check-toml = pre_commit_hooks.check_toml:main diff --git a/tests/check_path_edits_test.py b/tests/check_path_edits_test.py new file mode 100644 index 0000000..0088d8d --- /dev/null +++ b/tests/check_path_edits_test.py @@ -0,0 +1,45 @@ +from pre_commit_hooks.check_path_edits import find_wrong_paths +from pre_commit_hooks.check_path_edits import main +from pre_commit_hooks.util import cmd_output + + +def test_nothing_added(temp_git_dir): + with temp_git_dir.as_cwd(): + assert find_wrong_paths(['f.py'], {'asd'}) == 0 + + +def test_adding_something(temp_git_dir): + with temp_git_dir.as_cwd(): + temp_git_dir.join('f.py').write("print('hello world')") + cmd_output('git', 'add', 'f.py') + + assert find_wrong_paths(['f.py'], {'^f.*'}) == 1 + + +def test_some_regex(temp_git_dir): + with temp_git_dir.as_cwd(): + temp_git_dir.join('f.py').write('a' * 10000) + + # Should not fail when not added + assert find_wrong_paths(['f.py'], {'.*'}) == 0 + + cmd_output('git', 'add', 'f.py') + + assert find_wrong_paths(['f.py'], {'.*'}) == 1 + + assert find_wrong_paths(['f.py'], {'dasd', 'py', 'asd'}) == 1 + + assert find_wrong_paths(['f.py'], {'^py'}) == 0 + + +def test_integration(temp_git_dir): + with temp_git_dir.as_cwd(): + assert main(argv=[]) == 0 + + temp_git_dir.join('f.py').write('a') + cmd_output('git', 'add', 'f.py') + + # Should not fail with default + assert main(argv=['f.py']) == 0 + + assert main(argv=['--pattern', 'f.py', 'f.py']) == 1