def test_create_changes_to_git_root(tempdir_factory): path = git_dir(tempdir_factory) with cwd(path): # Change into some directory, create should set to root foo_path = os.path.join(path, 'foo') os.mkdir(foo_path) os.chdir(foo_path) assert os.getcwd() != path runner = Runner.create(C.CONFIG_FILE) assert os.path.normcase(runner.git_root) == os.path.normcase(path) assert os.path.normcase(os.getcwd()) == os.path.normcase(path)
def test_create_changes_to_git_root(tmpdir_factory): path = git_dir(tmpdir_factory) with local.cwd(path): # Change into some directory, create should set to root foo_path = os.path.join(path, 'foo') os.mkdir(foo_path) os.chdir(foo_path) assert os.getcwd() != path runner = Runner.create() assert runner.git_root == path assert os.getcwd() == path
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 expected = ('`.pre-commit-config.yaml` config file not found. ' 'Skipping `pre-commit`.') assert expected in output
def test_commit_msg_integration_passing( commit_msg_repo, tempdir_factory, store, ): runner = Runner(commit_msg_repo, C.CONFIG_FILE) install(runner, store, hook_type='commit-msg') msg = 'Hi\nSigned off by: me, lol' retc, out = _get_commit_output(tempdir_factory, commit_msg=msg) assert retc == 0 first_line = out.splitlines()[0] assert first_line.startswith('Must have "Signed off by:"...') assert first_line.endswith('...Passed')
def test_autoupdate_meta_hooks(tmpdir, capsys): cfg = tmpdir.join(C.CONFIG_FILE) cfg.write( 'repos:\n' '- repo: meta\n' ' hooks:\n' ' - id: check-useless-excludes\n', ) ret = autoupdate(Runner(tmpdir.strpath, C.CONFIG_FILE), tags_only=True) assert ret == 0 assert cfg.read() == ('repos:\n' '- repo: meta\n' ' hooks:\n' ' - id: check-useless-excludes\n')
def test_autoupdate_up_to_date_repo(up_to_date_repo, in_tmpdir, store): # Write out the config config = make_config_from_repo(up_to_date_repo, check=False) write_config('.', config) with open(C.CONFIG_FILE) as f: before = f.read() assert '^$' not in before ret = autoupdate(Runner('.', C.CONFIG_FILE), store, tags_only=False) with open(C.CONFIG_FILE) as f: after = f.read() assert ret == 0 assert before == after
def test_installs_hooks_with_hooks_True( tempdir_factory, mock_out_store_directory, ): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): install(Runner(path, C.CONFIG_FILE), hooks=True) ret, output = _get_commit_output( tempdir_factory, pre_commit_home=mock_out_store_directory, ) assert ret == 0 assert PRE_INSTALLED.match(output)
def test_install_hooks_command(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path, C.CONFIG_FILE) install(runner, store) install_hooks(runner, store) ret, output = _get_commit_output( tempdir_factory, pre_commit_home=store.directory, ) assert ret == 0 assert PRE_INSTALLED.match(output)
def test_install_disallow_mising_config(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path, C.CONFIG_FILE) remove_config_from_repo(path) ret = install( runner, store, overwrite=True, skip_on_missing_conf=False, ) assert ret == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 1
def test_commit_msg_legacy(commit_msg_repo, tempdir_factory, store): runner = Runner(commit_msg_repo, C.CONFIG_FILE) hook_path = runner.get_hook_path('commit-msg') mkdirp(os.path.dirname(hook_path)) with io.open(hook_path, 'w') as hook_file: hook_file.write( '#!/usr/bin/env bash\n' 'set -eu\n' 'test -e "$1"\n' 'echo legacy\n', ) make_executable(hook_path) install(runner, store, hook_type='commit-msg') msg = 'Hi\nSigned off by: asottile' retc, out = _get_commit_output(tempdir_factory, commit_msg=msg) assert retc == 0 first_line, second_line = out.splitlines()[:2] assert first_line == 'legacy' assert second_line.startswith('Must have "Signed off by:"...')
def test_unicode_merge_commit_message(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): assert install(Runner(path, C.CONFIG_FILE), store) == 0 cmd_output('git', 'checkout', 'master', '-b', 'foo') cmd_output('git', 'commit', '--allow-empty', '-n', '-m', 'branch2') cmd_output('git', 'checkout', 'master') cmd_output('git', 'merge', 'foo', '--no-ff', '--no-commit', '-m', '☃') # Used to crash cmd_output_mocked_pre_commit_home( 'git', 'commit', '--no-edit', tempdir_factory=tempdir_factory, )
def test_autoupdate_up_to_date_repo( up_to_date_repo, in_tmpdir, mock_out_store_directory, ): # Write out the config config = make_config_from_repo(up_to_date_repo, check=False) write_config('.', config) before = open(C.CONFIG_FILE).read() assert '^$' not in before ret = autoupdate(Runner('.', C.CONFIG_FILE), tags_only=False) after = open(C.CONFIG_FILE).read() assert ret == 0 assert before == after
def test_install_in_submodule_and_run(tempdir_factory): src_path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') parent_path = git_dir(tempdir_factory) with cwd(parent_path): cmd_output('git', 'submodule', 'add', src_path, 'sub') cmd_output('git', 'commit', '-m', 'foo') sub_pth = os.path.join(parent_path, 'sub') with cwd(sub_pth): assert install(Runner(sub_pth, C.CONFIG_FILE)) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert NORMAL_PRE_COMMIT_RUN.match(output)
def test_install_pre_commit(tmpdir_factory): path = git_dir(tmpdir_factory) runner = Runner(path) ret = install(runner) assert ret == 0 assert os.path.exists(runner.pre_commit_path) pre_commit_contents = io.open(runner.pre_commit_path).read() pre_commit_script = resource_filename('pre-commit-hook') expected_contents = io.open(pre_commit_script).read().format( sys_executable=sys.executable, ) assert pre_commit_contents == expected_contents stat_result = os.stat(runner.pre_commit_path) assert stat_result.st_mode & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
def test_autoupdate_tagged_repo( tagged_repo, in_tmpdir, mock_out_store_directory, ): config = make_config_from_repo( tagged_repo.path, sha=tagged_repo.original_sha, ) write_config('.', config) ret = autoupdate(Runner('.')) assert ret == 0 assert 'v1.2.3' in open(C.CONFIG_FILE).read()
def test_pre_push_integration_failing(tmpdir_factory): upstream = make_consuming_repo(tmpdir_factory, 'failing_hook_repo') path = tmpdir_factory.get() cmd_output('git', 'clone', upstream, path) with cwd(path): install(Runner(path), hook_type='pre-push') # commit succeeds because pre-commit is only installed for pre-push assert _get_commit_output(tmpdir_factory)[0] == 0 retc, output = _get_push_output(tmpdir_factory) assert retc == 1 assert 'Failing hook' in output assert 'Failed' in output assert 'hookid: failing_hook' in output
def test_autoupdate_tags_only( tagged_repo_with_more_commits, in_tmpdir, mock_out_store_directory, ): config = make_config_from_repo( tagged_repo_with_more_commits.path, sha=tagged_repo_with_more_commits.original_sha, ) write_config('.', config) ret = autoupdate(Runner('.', C.CONFIG_FILE), tags_only=True) assert ret == 0 assert 'v1.2.3' in open(C.CONFIG_FILE).read()
def test_already_migrated_configuration_noop(tmpdir, capsys): contents = ('repos:\n' '- repo: local\n' ' hooks:\n' ' - id: foo\n' ' name: foo\n' ' entry: ./bin/foo.sh\n' ' language: script\n') cfg = tmpdir.join(C.CONFIG_FILE) cfg.write(contents) assert not migrate_config(Runner(tmpdir.strpath, C.CONFIG_FILE)) out, _ = capsys.readouterr() assert out == 'Configuration is already migrated.\n' assert cfg.read() == contents
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 env = dict(os.environ, PRE_COMMIT_ALLOW_NO_CONFIG='1') ret, output = _get_commit_output(tempdir_factory, env=env) assert ret == 0 expected = ('`.pre-commit-config.yaml` config file not found. ' 'Skipping `pre-commit`.') assert expected in output
def test_autoupdate_local_hooks_with_out_of_date_repo( out_of_date_repo, in_tmpdir, mock_out_store_directory, ): stale_config = make_config_from_repo( out_of_date_repo.path, sha=out_of_date_repo.original_sha, check=False, ) local_config = config_with_local_hooks() config = {'repos': [local_config, stale_config]} write_config('.', config) runner = Runner('.', C.CONFIG_FILE) assert autoupdate(runner, tags_only=False) == 0 new_config_writen = load_config(runner.config_file_path) assert len(new_config_writen['repos']) == 2 assert new_config_writen['repos'][0] == local_config
def test_autoupdate_latest_no_config(out_of_date_repo, in_tmpdir, store): config = make_config_from_repo( out_of_date_repo.path, rev=out_of_date_repo.original_rev, ) write_config('.', config) cmd_output('git', '-C', out_of_date_repo.path, 'rm', '-r', ':/') cmd_output('git', '-C', out_of_date_repo.path, 'commit', '-m', 'rm') ret = autoupdate(Runner('.', C.CONFIG_FILE), store, tags_only=False) assert ret == 1 with open(C.CONFIG_FILE) as f: assert out_of_date_repo.original_rev in f.read()
def test_autoupdate_hook_disappearing_repo(hook_disappearing_repo, in_tmpdir, mock_out_store_directory): config = make_config_from_repo( hook_disappearing_repo.path, sha=hook_disappearing_repo.original_sha, hooks=[OrderedDict((('id', 'foo'), ))], check=False, ) write_config('.', config) before = open(C.CONFIG_FILE).read() ret = autoupdate(Runner('.', C.CONFIG_FILE), tags_only=False) after = open(C.CONFIG_FILE).read() assert ret == 1 assert before == after
def test_pre_push_new_upstream(tempdir_factory, store): upstream = make_consuming_repo(tempdir_factory, 'script_hooks_repo') upstream2 = git_dir(tempdir_factory) path = tempdir_factory.get() cmd_output('git', 'clone', upstream, path) with cwd(path): install(Runner(path, C.CONFIG_FILE), store, hook_type='pre-push') assert _get_commit_output(tempdir_factory)[0] == 0 cmd_output('git', 'remote', 'rename', 'origin', 'upstream') cmd_output('git', 'remote', 'add', 'origin', upstream2) retc, output = _get_push_output(tempdir_factory) assert retc == 0 assert 'Bash hook' in output assert 'Passed' in output
def test_installed_from_venv(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') with cwd(path): install(Runner(path)) # No environment so pre-commit is not on the path when running! # Should still pick up the python from when we installed ret, output = _get_commit_output( tmpdir_factory, env_base={ 'HOME': os.environ['HOME'], 'TERM': os.environ.get('TERM', ''), }, ) assert ret == 0 assert NORMAL_PRE_COMMIT_RUN.match(output)
def test_uninstall_restores_legacy_hooks(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path, C.CONFIG_FILE) _write_legacy_hook(path) # Now install and uninstall pre-commit assert install(runner, store) == 0 assert uninstall(runner) == 0 # Make sure we installed the "old" hook correctly ret, output = _get_commit_output(tempdir_factory, touch_file='baz') assert ret == 0 assert EXISTING_COMMIT_RUN.match(output)
def test_autoupdate_local_hooks_with_out_of_date_repo( out_of_date_repo, in_tmpdir, mock_out_store_directory): stale_config = make_config_from_repo( out_of_date_repo.path, sha=out_of_date_repo.original_sha, check=False, ) local_config = config_with_local_hooks() config = [local_config, stale_config] write_config('.', config) runner = Runner('.') assert autoupdate(runner) == 0 new_config_writen = load_config(runner.config_file_path) assert len(new_config_writen) == 2 assert new_config_writen[0] == local_config
def test_install_overwrite(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path) # Write out the "old" hook with io.open(runner.pre_commit_path, 'w') as hook_file: hook_file.write('#!/usr/bin/env bash\necho "legacy hook"\n') make_executable(runner.pre_commit_path) assert install(runner, overwrite=True) == 0 ret, output = _get_commit_output(tmpdir_factory) assert ret == 0 assert NORMAL_PRE_COMMIT_RUN.match(output)
def test_commit_am(tempdir_factory): """Regression test for #322.""" path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): # Make an unstaged change open('unstaged', 'w').close() cmd_output('git', 'add', '.') cmd_output('git', 'commit', '-m', 'foo') with io.open('unstaged', 'w') as foo_file: foo_file.write('Oh hai') assert install(Runner(path, C.CONFIG_FILE)) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0
def test_install_existing_hook_no_overwrite_idempotent(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path, C.CONFIG_FILE) _write_legacy_hook(path) # Install twice assert install(runner, store) == 0 assert install(runner, store) == 0 # We should run both the legacy and pre-commit hooks ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert output.startswith('legacy hook\n') assert NORMAL_PRE_COMMIT_RUN.match(output[len('legacy hook\n'):])
def test_failing_existing_hook_returns_1(tmpdir_factory): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path) # Write out a failing "old" hook with io.open(runner.pre_commit_path, 'w') as hook_file: hook_file.write('#!/usr/bin/env bash\necho "fail!"\nexit 1\n') make_executable(runner.pre_commit_path) assert install(runner) == 0 # We should get a failure from the legacy hook ret, output = _get_commit_output(tmpdir_factory) assert ret == 1 assert FAIL_OLD_HOOK.match(output)
def test_pre_push_integration_failing(tempdir_factory, store): upstream = make_consuming_repo(tempdir_factory, 'failing_hook_repo') path = tempdir_factory.get() cmd_output('git', 'clone', upstream, path) with cwd(path): install(Runner(path, C.CONFIG_FILE), store, hook_type='pre-push') # commit succeeds because pre-commit is only installed for pre-push assert _get_commit_output(tempdir_factory)[0] == 0 assert _get_commit_output(tempdir_factory, touch_file='zzz')[0] == 0 retc, output = _get_push_output(tempdir_factory) assert retc == 1 assert 'Failing hook' in output assert 'Failed' in output assert 'foo zzz' in output # both filenames should be printed assert 'hookid: failing_hook' in output
def test_autoupdate_out_of_date_repo_with_wrong_repo_name( out_of_date_repo, in_tmpdir, mock_out_store_directory, ): # Write out the config config = make_config_from_repo( out_of_date_repo.path, rev=out_of_date_repo.original_rev, check=False, ) write_config('.', config) runner = Runner('.', C.CONFIG_FILE) before = open(C.CONFIG_FILE).read() # It will not update it, because the name doesn't match ret = autoupdate(runner, tags_only=False, repos=('wrong_repo_name',)) after = open(C.CONFIG_FILE).read() assert ret == 0 assert before == after
def test_create_sets_correct_directory(tmpdir_factory): path = git_dir(tmpdir_factory) with local.cwd(path): runner = Runner.create() assert runner.git_root == path assert os.getcwd() == path
def test_create_sets_correct_directory(tempdir_factory): path = git_dir(tempdir_factory) with cwd(path): runner = Runner.create(C.CONFIG_FILE) assert os.path.normcase(runner.git_root) == os.path.normcase(path) assert os.path.normcase(os.getcwd()) == os.path.normcase(path)
def main(argv=None): argv = argv if argv is not None else sys.argv[1:] argv = [five.to_text(arg) for arg in argv] parser = argparse.ArgumentParser() # http://stackoverflow.com/a/8521644/812183 parser.add_argument( '-V', '--version', action='version', version='%(prog)s {}'.format( pkg_resources.get_distribution('pre-commit').version ) ) subparsers = parser.add_subparsers(dest='command') install_parser = subparsers.add_parser( 'install', help='Install the pre-commit script.', ) _add_color_option(install_parser) _add_config_option(install_parser) install_parser.add_argument( '-f', '--overwrite', action='store_true', help='Overwrite existing hooks / remove migration mode.', ) install_parser.add_argument( '--install-hooks', action='store_true', help=( 'Whether to install hook environments for all environments ' 'in the config file.' ), ) install_parser.add_argument( '-t', '--hook-type', choices=('pre-commit', 'pre-push'), default='pre-commit', ) install_hooks_parser = subparsers.add_parser( 'install-hooks', help=( 'Install hook environemnts for all environemnts in the config ' 'file. You may find `pre-commit install --install-hooks` more ' 'useful.' ), ) _add_color_option(install_hooks_parser) _add_config_option(install_hooks_parser) uninstall_parser = subparsers.add_parser( 'uninstall', help='Uninstall the pre-commit script.', ) _add_color_option(uninstall_parser) _add_config_option(uninstall_parser) uninstall_parser.add_argument( '-t', '--hook-type', choices=('pre-commit', 'pre-push'), default='pre-commit', ) clean_parser = subparsers.add_parser( 'clean', help='Clean out pre-commit files.', ) _add_color_option(clean_parser) _add_config_option(clean_parser) autoupdate_parser = subparsers.add_parser( 'autoupdate', help="Auto-update pre-commit config to the latest repos' versions.", ) _add_color_option(autoupdate_parser) _add_config_option(autoupdate_parser) run_parser = subparsers.add_parser('run', help='Run hooks.') _add_color_option(run_parser) _add_config_option(run_parser) run_parser.add_argument('hook', nargs='?', help='A single hook-id to run') run_parser.add_argument( '--no-stash', default=False, action='store_true', help='Use this option to prevent auto stashing of unstaged files.', ) run_parser.add_argument( '--verbose', '-v', action='store_true', default=False, ) run_parser.add_argument( '--origin', '-o', help="The origin branch's commit_id when using `git push`.", ) run_parser.add_argument( '--source', '-s', help="The remote branch's commit_id when using `git push`.", ) run_parser.add_argument( '--allow-unstaged-config', default=False, action='store_true', help=( 'Allow an unstaged config to be present. Note that this will ' 'be stashed before parsing unless --no-stash is specified.' ), ) run_parser.add_argument( '--hook-stage', choices=('commit', 'push'), default='commit', help='The stage during which the hook is fired e.g. commit or push.', ) run_mutex_group = run_parser.add_mutually_exclusive_group(required=False) run_mutex_group.add_argument( '--all-files', '-a', action='store_true', default=False, help='Run on all the files in the repo. Implies --no-stash.', ) run_mutex_group.add_argument( '--files', nargs='*', default=[], help='Specific filenames to run hooks on.', ) help = subparsers.add_parser( 'help', help='Show help for a specific command.', ) help.add_argument('help_cmd', nargs='?', help='Command to show help for.') # Argparse doesn't really provide a way to use a `default` subparser if len(argv) == 0: argv = ['run'] args = parser.parse_args(argv) if args.command == 'run': args.files = [ os.path.relpath(os.path.abspath(filename), git.get_root()) for filename in args.files ] if args.command == 'help': if args.help_cmd: parser.parse_args([args.help_cmd, '--help']) else: parser.parse_args(['--help']) with error_handler(): add_logging_handler(args.color) runner = Runner.create(args.config) git.check_for_cygwin_mismatch() if args.command == 'install': return install( runner, overwrite=args.overwrite, hooks=args.install_hooks, hook_type=args.hook_type, ) elif args.command == 'install-hooks': return install_hooks(runner) elif args.command == 'uninstall': return uninstall(runner, hook_type=args.hook_type) elif args.command == 'clean': return clean(runner) elif args.command == 'autoupdate': return autoupdate(runner) elif args.command == 'run': return run(runner, args) else: raise NotImplementedError( 'Command {} not implemented.'.format(args.command) ) raise AssertionError( 'Command {} failed to exit with a returncode'.format(args.command) )
def main(argv=None): argv = argv if argv is not None else sys.argv[1:] parser = argparse.ArgumentParser() # http://stackoverflow.com/a/8521644/812183 parser.add_argument( '-V', '--version', action='version', version='%(prog)s {0}'.format( pkg_resources.get_distribution('pre-commit').version ) ) subparsers = parser.add_subparsers(dest='command') install_parser = subparsers.add_parser( 'install', help='Install the pre-commit script.', ) install_parser.add_argument( '-f', '--overwrite', action='store_true', help='Overwrite existing hooks / remove migration mode.', ) install_parser.add_argument( '--install-hooks', action='store_true', help=( 'Whether to install hook environments for all environments ' 'in the config file.' ), ) subparsers.add_parser('uninstall', help='Uninstall the pre-commit script.') subparsers.add_parser('clean', help='Clean out pre-commit files.') subparsers.add_parser( 'autoupdate', help="Auto-update pre-commit config to the latest repos' versions.", ) run_parser = subparsers.add_parser('run', help='Run hooks.') run_parser.add_argument('hook', nargs='?', help='A single hook-id to run') run_parser.add_argument( '--color', default='auto', type=color.use_color, help='Whether to use color in output. Defaults to `auto`', ) run_parser.add_argument( '--no-stash', default=False, action='store_true', help='Use this option to prevent auto stashing of unstaged files.', ) run_parser.add_argument( '--verbose', '-v', action='store_true', default=False, ) run_mutex_group = run_parser.add_mutually_exclusive_group(required=False) run_mutex_group.add_argument( '--all-files', '-a', action='store_true', default=False, help='Run on all the files in the repo. Implies --no-stash.', ) run_mutex_group.add_argument( '--files', nargs='*', help='Specific filenames to run hooks on.', ) help = subparsers.add_parser( 'help', help='Show help for a specific command.' ) help.add_argument('help_cmd', nargs='?', help='Command to show help for.') # Argparse doesn't really provide a way to use a `default` subparser if len(argv) == 0: argv = ['run'] args = parser.parse_args(argv) if args.command == 'help': if args.help_cmd: parser.parse_args([args.help_cmd, '--help']) else: parser.parse_args(['--help']) with error_handler(): runner = Runner.create() if args.command == 'install': return install( runner, overwrite=args.overwrite, hooks=args.install_hooks, ) elif args.command == 'uninstall': return uninstall(runner) elif args.command == 'clean': return clean(runner) elif args.command == 'autoupdate': return autoupdate(runner) elif args.command == 'run': return run(runner, args) else: raise NotImplementedError( 'Command {0} not implemented.'.format(args.command) ) raise AssertionError( 'Command {0} failed to exit with a returncode'.format(args.command) )
def main(argv=None): argv = argv if argv is not None else sys.argv[1:] argv = [five.to_text(arg) for arg in argv] parser = argparse.ArgumentParser() # http://stackoverflow.com/a/8521644/812183 parser.add_argument( '-V', '--version', action='version', version='%(prog)s {}'.format(C.VERSION), ) subparsers = parser.add_subparsers(dest='command') install_parser = subparsers.add_parser( 'install', help='Install the pre-commit script.', ) _add_color_option(install_parser) _add_config_option(install_parser) install_parser.add_argument( '-f', '--overwrite', action='store_true', help='Overwrite existing hooks / remove migration mode.', ) install_parser.add_argument( '--install-hooks', action='store_true', help=( 'Whether to install hook environments for all environments ' 'in the config file.' ), ) _add_hook_type_option(install_parser) install_parser.add_argument( '--allow-missing-config', action='store_true', default=False, help=( 'Whether to allow a missing `pre-commit` configuration file ' 'or exit with a failure code.' ), ) install_hooks_parser = subparsers.add_parser( 'install-hooks', help=( 'Install hook environments for all environments in the config ' 'file. You may find `pre-commit install --install-hooks` more ' 'useful.' ), ) _add_color_option(install_hooks_parser) _add_config_option(install_hooks_parser) uninstall_parser = subparsers.add_parser( 'uninstall', help='Uninstall the pre-commit script.', ) _add_color_option(uninstall_parser) _add_config_option(uninstall_parser) _add_hook_type_option(uninstall_parser) clean_parser = subparsers.add_parser( 'clean', help='Clean out pre-commit files.', ) _add_color_option(clean_parser) _add_config_option(clean_parser) autoupdate_parser = subparsers.add_parser( 'autoupdate', help="Auto-update pre-commit config to the latest repos' versions.", ) _add_color_option(autoupdate_parser) _add_config_option(autoupdate_parser) autoupdate_parser.add_argument( '--tags-only', action='store_true', help='LEGACY: for compatibility', ) autoupdate_parser.add_argument( '--bleeding-edge', action='store_true', help=( 'Update to the bleeding edge of `master` instead of the latest ' 'tagged version (the default behavior).' ), ) migrate_config_parser = subparsers.add_parser( 'migrate-config', help='Migrate list configuration to new map configuration.', ) _add_color_option(migrate_config_parser) _add_config_option(migrate_config_parser) run_parser = subparsers.add_parser('run', help='Run hooks.') _add_color_option(run_parser) _add_config_option(run_parser) run_parser.add_argument('hook', nargs='?', help='A single hook-id to run') run_parser.add_argument( '--verbose', '-v', action='store_true', default=False, ) run_parser.add_argument( '--origin', '-o', help="The origin branch's commit_id when using `git push`.", ) run_parser.add_argument( '--source', '-s', help="The remote branch's commit_id when using `git push`.", ) run_parser.add_argument( '--commit-msg-filename', help='Filename to check when running during `commit-msg`', ) run_parser.add_argument( '--hook-stage', choices=('commit', 'push', 'commit-msg'), default='commit', help='The stage during which the hook is fired e.g. commit or push.', ) run_parser.add_argument( '--show-diff-on-failure', action='store_true', help='When hooks fail, run `git diff` directly afterward.', ) run_mutex_group = run_parser.add_mutually_exclusive_group(required=False) run_mutex_group.add_argument( '--all-files', '-a', action='store_true', default=False, help='Run on all the files in the repo.', ) run_mutex_group.add_argument( '--files', nargs='*', default=[], help='Specific filenames to run hooks on.', ) sample_config_parser = subparsers.add_parser( 'sample-config', help='Produce a sample {} file'.format(C.CONFIG_FILE), ) _add_color_option(sample_config_parser) _add_config_option(sample_config_parser) help = subparsers.add_parser( 'help', help='Show help for a specific command.', ) help.add_argument('help_cmd', nargs='?', help='Command to show help for.') # Argparse doesn't really provide a way to use a `default` subparser if len(argv) == 0: argv = ['run'] args = parser.parse_args(argv) if args.command == 'run': args.files = [ os.path.relpath(os.path.abspath(filename), git.get_root()) for filename in args.files ] if args.command == 'help': if args.help_cmd: parser.parse_args([args.help_cmd, '--help']) else: parser.parse_args(['--help']) with error_handler(): add_logging_handler(args.color) runner = Runner.create(args.config) git.check_for_cygwin_mismatch() if args.command == 'install': 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) elif args.command == 'uninstall': return uninstall(runner, hook_type=args.hook_type) elif args.command == 'clean': return clean(runner) elif args.command == 'autoupdate': if args.tags_only: logger.warning('--tags-only is the default') return autoupdate(runner, tags_only=not args.bleeding_edge) elif args.command == 'migrate-config': return migrate_config(runner) elif args.command == 'run': return run(runner, args) elif args.command == 'sample-config': return sample_config() else: raise NotImplementedError( 'Command {} not implemented.'.format(args.command), ) raise AssertionError( 'Command {} failed to exit with a returncode'.format(args.command), )