Add --allow-missing-config option to install

When no '.pre-commit-config.yaml' file exists while `pre-commit` hooks
are enabled, `pre-commit` returns an error and the action is aborted.
This is a very common scenario when pre-commit is added later on a
project and the user wants to work on a previous branch where the
configuration file does not exist.

This commits allow the user to optionally install the `pre-commit` hooks
with an option to allow a missing configuration and trigger only the
legacy pre-commit hooks (if any) when it is missing.
This commit is contained in:
Filippos Giannakos
2017-02-21 12:40:33 +02:00
parent 41dcaff3fb
commit 2f4199850d
5 changed files with 84 additions and 2 deletions

View File

@@ -37,7 +37,10 @@ def is_previous_pre_commit(filename):
return any(hash in contents for hash in PREVIOUS_IDENTIFYING_HASHES)
def install(runner, overwrite=False, hooks=False, hook_type='pre-commit'):
def install(
runner, overwrite=False, hooks=False, hook_type='pre-commit',
skip_on_missing_conf=False
):
"""Install the pre-commit hooks."""
hook_path = runner.get_hook_path(hook_type)
legacy_path = hook_path + '.legacy'
@@ -70,10 +73,12 @@ def install(runner, overwrite=False, hooks=False, hook_type='pre-commit'):
else:
pre_push_contents = ''
skip_on_missing_conf = 'true' if skip_on_missing_conf else 'false'
contents = io.open(resource_filename('hook-tmpl')).read().format(
sys_executable=sys.executable,
hook_type=hook_type,
pre_push=pre_push_contents,
skip_on_missing_conf=skip_on_missing_conf
)
pre_commit_file_obj.write(contents)
make_executable(hook_path)

View File

@@ -75,6 +75,13 @@ def main(argv=None):
'-t', '--hook-type', choices=('pre-commit', 'pre-push'),
default='pre-commit',
)
install_parser.add_argument(
'--allow-missing-config', action='store_true', default=False,
help=(
'Whether to allow a missing `pre-config` configuration file '
'or exit with a failure code.'
),
)
install_hooks_parser = subparsers.add_parser(
'install-hooks',
@@ -182,6 +189,7 @@ def main(argv=None):
return install(
runner, overwrite=args.overwrite, hooks=args.install_hooks,
hook_type=args.hook_type,
skip_on_missing_conf=args.allow_missing_config
)
elif args.command == 'install-hooks':
return install_hooks(runner)

View File

@@ -10,6 +10,7 @@ retv=0
args=""
ENV_PYTHON='{sys_executable}'
SKIP_ON_MISSING_CONF={skip_on_missing_conf}
which pre-commit >& /dev/null
WHICH_RETV=$?
@@ -37,6 +38,20 @@ if [ -x "$HERE"/{hook_type}.legacy ]; then
fi
fi
CONF_FILE=$(git rev-parse --show-toplevel)"/.pre-commit-config.yaml"
if [ ! -f $CONF_FILE ]; then
if [ $SKIP_ON_MISSING_CONF = true ] || [ ! -z $PRE_COMMIT_ALLOW_NO_CONFIG ]; then
echo '`.pre-commit-config.yaml` config file not found. Skipping `pre-commit`.'
exit $retv
else
echo 'No .pre-commit-config.yaml file was found\n'\
'- To temporarily silence this, run `PRE_COMMIT_ALLOW_NO_CONFIG=1 git ...`\n'\
'- To permanently silence this, install pre-commit with the `--allow-missing-config` option\n'\
'- To uninstall pre-commit run `pre-commit uninstall`'
exit 1
fi
fi
{pre_push}
# Run pre-commit

View File

@@ -123,6 +123,14 @@ def add_config_to_repo(git_path, config, config_file=C.CONFIG_FILE):
return git_path
def remove_config_from_repo(git_path, config_file=C.CONFIG_FILE):
os.unlink(os.path.join(git_path, config_file))
with cwd(git_path):
cmd_output('git', 'add', config_file)
cmd_output('git', 'commit', '-m', 'Remove hooks config')
return git_path
def make_consuming_repo(tempdir_factory, repo_source):
path = make_repo(tempdir_factory, repo_source)
config = make_config_from_repo(path)

View File

@@ -26,6 +26,7 @@ from pre_commit.util import mkdirp
from pre_commit.util import resource_filename
from testing.fixtures import git_dir
from testing.fixtures import make_consuming_repo
from testing.fixtures import remove_config_from_repo
from testing.util import cmd_output_mocked_pre_commit_home
from testing.util import xfailif_no_symlink
@@ -64,7 +65,8 @@ def test_install_pre_commit(tempdir_factory):
expected_contents = io.open(pre_commit_script).read().format(
sys_executable=sys.executable,
hook_type='pre-commit',
pre_push=''
pre_push='',
skip_on_missing_conf='false'
)
assert pre_commit_contents == expected_contents
assert os.access(runner.pre_commit_path, os.X_OK)
@@ -79,6 +81,7 @@ def test_install_pre_commit(tempdir_factory):
sys_executable=sys.executable,
hook_type='pre-push',
pre_push=pre_push_template_contents,
skip_on_missing_conf='false'
)
assert pre_push_contents == expected_contents
@@ -552,3 +555,46 @@ def test_pre_push_integration_empty_push(tempdir_factory):
retc, output = _get_push_output(tempdir_factory)
assert output == 'Everything up-to-date\n'
assert retc == 0
def test_install_disallow_mising_config(tempdir_factory):
path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
with cwd(path):
runner = Runner(path, C.CONFIG_FILE)
remove_config_from_repo(path)
assert install(runner, overwrite=True, skip_on_missing_conf=False) == 0
ret, output = _get_commit_output(tempdir_factory)
assert ret == 1
def test_install_allow_mising_config(tempdir_factory):
path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
with cwd(path):
runner = Runner(path, C.CONFIG_FILE)
remove_config_from_repo(path)
assert install(runner, overwrite=True, skip_on_missing_conf=True) == 0
ret, output = _get_commit_output(tempdir_factory)
assert ret == 0
assert '`.pre-commit-config.yaml` config file not found. '\
'Skipping `pre-commit`.' in output
def test_install_temporarily_allow_mising_config(tempdir_factory):
path = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
with cwd(path):
runner = Runner(path, C.CONFIG_FILE)
remove_config_from_repo(path)
assert install(runner, overwrite=True, skip_on_missing_conf=False) == 0
extra_env = {'PRE_COMMIT_ALLOW_NO_CONFIG': '1'}
env = os.environ.copy()
env.update(extra_env)
ret, output = _get_commit_output(tempdir_factory, env=env)
assert ret == 0
assert '`.pre-commit-config.yaml` config file not found. '\
'Skipping `pre-commit`.' in output