def test_error_handler_non_stringable_exception(mock_store_dir):
    class C(Exception):
        def __str__(self):
            raise RuntimeError('not today!')

    with pytest.raises(SystemExit):
        with error_handler.error_handler():
            raise C()
def main(
    argv: Argv = None,
    *,
    pre_commit_config_yaml: Path = None,
    hook_entry_func: Callable[[Hook], str] = None,
    tmp_path_func: Callable[[Path], None] = None,
) -> int:
    if argv is None:
        argv = sys.argv[1:]

    if not argv:
        return usage()

    with hook_context(argv) as ctx:
        hook_name, extra_args, tmp_path = ctx
        if hook_name.startswith("-"):
            return usage()

        pre_commit_args = get_pre_commit_args(hook_name,
                                              config=pre_commit_config_yaml)

        with error_handler(), logging_handler(pre_commit_args.color):
            git.check_for_cygwin_mismatch()

            store = Store()
            with store.exclusive_lock():
                store.mark_config_used(pre_commit_args.config)

            hook = find_hook(pre_commit_args, store)
            retcode, out = run_hook(
                patch_hook(
                    hook,
                    extra_args=extra_args,
                    entry=hook_entry_func(hook) if hook_entry_func else None,
                ),
                pre_commit_args.color,
            )

            if tmp_path and tmp_path_func:
                tmp_path_func(tmp_path)

            sys.stdout.buffer.write(out)
            sys.stdout.buffer.flush()

            return retcode
Exemple #3
0
def test_error_handler_uncaught_error(mocked_log_and_exit):
    exc = ValueError('another test')
    with error_handler.error_handler():
        raise exc

    mocked_log_and_exit.assert_called_once_with(
        'An unexpected error has occurred',
        exc,
        # Tested below
        mock.ANY,
    )
    pattern = re_assert.Matches(
        r'Traceback \(most recent call last\):\n'
        r'  File ".+pre_commit.error_handler.py", line \d+, in error_handler\n'
        r'    yield\n'
        r'  File ".+tests.error_handler_test.py", line \d+, '
        r'in test_error_handler_uncaught_error\n'
        r'    raise exc\n'
        r'ValueError: another test\n', )
    pattern.assert_matches(mocked_log_and_exit.call_args[0][2])
Exemple #4
0
def test_error_handler_keyboardinterrupt(mocked_log_and_exit):
    exc = KeyboardInterrupt()
    with error_handler.error_handler():
        raise exc

    mocked_log_and_exit.assert_called_once_with(
        'Interrupted (^C)',
        exc,
        # Tested below
        mock.ANY,
    )
    pattern = re_assert.Matches(
        r'Traceback \(most recent call last\):\n'
        r'  File ".+pre_commit.error_handler.py", line \d+, in error_handler\n'
        r'    yield\n'
        r'  File ".+tests.error_handler_test.py", line \d+, '
        r'in test_error_handler_keyboardinterrupt\n'
        r'    raise exc\n'
        r'KeyboardInterrupt\n', )
    pattern.assert_matches(mocked_log_and_exit.call_args[0][2])
Exemple #5
0
def test_error_handler_uncaught_error(mocked_log_and_exit):
    exc = ValueError('another test')
    with error_handler.error_handler():
        raise exc

    mocked_log_and_exit.assert_called_once_with(
        'An unexpected error has occurred',
        exc,
        # Tested below
        mock.ANY,
    )
    assert re.match(
        'Traceback \(most recent call last\):\n'
        '  File ".+/pre_commit/error_handler.py", line \d+, in error_handler\n'
        '    yield\n'
        '  File ".+/tests/error_handler_test.py", line \d+, '
        'in test_error_handler_uncaught_error\n'
        '    raise exc\n'
        'ValueError: another test\n',
        mocked_log_and_exit.call_args[0][2],
    )
def test_error_handler_keyboardinterrupt(mocked_log_and_exit):
    exc = KeyboardInterrupt()
    with error_handler.error_handler():
        raise exc

    mocked_log_and_exit.assert_called_once_with(
        'Interrupted (^C)',
        exc,
        # Tested below
        mock.ANY,
    )
    assert re.match(
        r'Traceback \(most recent call last\):\n'
        r'  File ".+pre_commit.error_handler.py", line \d+, in error_handler\n'
        r'    yield\n'
        r'  File ".+tests.error_handler_test.py", line \d+, '
        r'in test_error_handler_keyboardinterrupt\n'
        r'    raise exc\n'
        r'KeyboardInterrupt\n',
        mocked_log_and_exit.call_args[0][2],
    )
def test_error_handler_uncaught_error(mocked_log_and_exit):
    exc = ValueError('another test')
    with error_handler.error_handler():
        raise exc

    mocked_log_and_exit.assert_called_once_with(
        'An unexpected error has occurred',
        exc,
        # Tested below
        mock.ANY,
    )
    assert re.match(
        r'Traceback \(most recent call last\):\n'
        r'  File ".+pre_commit.error_handler.py", line \d+, in error_handler\n'
        r'    yield\n'
        r'  File ".+tests.error_handler_test.py", line \d+, '
        r'in test_error_handler_uncaught_error\n'
        r'    raise exc\n'
        r'ValueError: another test\n',
        mocked_log_and_exit.call_args[0][2],
    )
Exemple #8
0
def test_error_handler_fatal_error(mocked_log_and_exit):
    exc = FatalError('just a test')
    with error_handler.error_handler():
        raise exc

    mocked_log_and_exit.assert_called_once_with(
        'An error has occurred',
        exc,
        # Tested below
        mock.ANY,
    )

    pattern = re_assert.Matches(
        r'Traceback \(most recent call last\):\n'
        r'  File ".+pre_commit.error_handler.py", line \d+, in error_handler\n'
        r'    yield\n'
        r'  File ".+tests.error_handler_test.py", line \d+, '
        r'in test_error_handler_fatal_error\n'
        r'    raise exc\n'
        r'(pre_commit\.errors\.)?FatalError: just a test\n', )
    pattern.assert_matches(mocked_log_and_exit.call_args[0][2])
def test_error_handler_fatal_error(mocked_log_and_exit):
    exc = FatalError('just a test')
    with error_handler.error_handler():
        raise exc

    mocked_log_and_exit.assert_called_once_with(
        'An error has occurred',
        exc,
        # Tested below
        mock.ANY,
    )

    assert re.match(
        r'Traceback \(most recent call last\):\n'
        r'  File ".+pre_commit.error_handler.py", line \d+, in error_handler\n'
        r'    yield\n'
        r'  File ".+tests.error_handler_test.py", line \d+, '
        r'in test_error_handler_fatal_error\n'
        r'    raise exc\n'
        r'(pre_commit\.errors\.)?FatalError: just a test\n',
        mocked_log_and_exit.call_args[0][2],
    )
Exemple #10
0
def test_error_handler_fatal_error(mocked_log_and_exit):
    exc = FatalError('just a test')
    with error_handler.error_handler():
        raise exc

    mocked_log_and_exit.assert_called_once_with(
        'An error has occurred',
        exc,
        # Tested below
        mock.ANY,
    )

    assert re.match(
        'Traceback \(most recent call last\):\n'
        '  File ".+/pre_commit/error_handler.py", line \d+, in error_handler\n'
        '    yield\n'
        '  File ".+/tests/error_handler_test.py", line \d+, '
        'in test_error_handler_fatal_error\n'
        '    raise exc\n'
        '(pre_commit\.errors\.)?FatalError: just a test\n',
        mocked_log_and_exit.call_args[0][2],
    )
Exemple #11
0
def test_error_handler_read_only_filesystem(mock_store_dir, cap_out, capsys):
    # a better scenario would be if even the Store crash would be handled
    # but realistically we're only targetting systems where the Store has
    # already been set up
    Store()

    write = (stat.S_IWGRP | stat.S_IWOTH | stat.S_IWUSR)
    os.chmod(mock_store_dir, os.stat(mock_store_dir).st_mode & ~write)

    with pytest.raises(SystemExit):
        with error_handler.error_handler():
            raise ValueError('ohai')

    output = cap_out.get()
    assert output.startswith(
        'An unexpected error has occurred: ValueError: ohai\n'
        'Failed to write to log at ', )

    # our cap_out mock is imperfect so the rest of the output goes to capsys
    out, _ = capsys.readouterr()
    # the things that normally go to the log file will end up here
    assert '### version information' in out
Exemple #12
0
def test_error_handler_no_exception(mocked_log_and_exit):
    with error_handler.error_handler():
        pass
    assert mocked_log_and_exit.call_count == 0
Exemple #13
0
def test_error_handler_non_ascii_exception(mock_store_dir):
    with pytest.raises(SystemExit):
        with error_handler.error_handler():
            raise ValueError('☃')
Exemple #14
0
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)
        )
Exemple #15
0
def test_error_handler_non_ascii_exception(mock_out_store_directory):
    with pytest.raises(error_handler.PreCommitSystemExit):
        with error_handler.error_handler():
            raise ValueError('☃')
Exemple #16
0
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.',
    )
    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',
    )

    uninstall_parser = subparsers.add_parser(
        'uninstall', help='Uninstall the pre-commit script.',
    )
    uninstall_parser.add_argument(
        '-t', '--hook-type', choices=('pre-commit', 'pre-push'),
        default='pre-commit',
    )

    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,
        metavar='{' + ','.join(color.COLOR_CHOICES) + '}',
        help='Whether to use color in output.  Defaults to `%(default)s`.',
    )
    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():
        runner = Runner.create()

        if args.command == 'install':
            return install(
                runner, overwrite=args.overwrite, hooks=args.install_hooks,
                hook_type=args.hook_type,
            )
        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)
        )
Exemple #17
0
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),
        )
Exemple #18
0
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.'),
    )
    install_parser.add_argument(
        '-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',
        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)
    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)
    autoupdate_parser.add_argument(
        '--tags-only',
        action='store_true',
        help='Update to tags only.',
    )

    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_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.  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,
                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':
            return autoupdate(runner, args.tags_only)
        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 test_error_handler_non_utf8_exception(mock_store_dir):
    with pytest.raises(SystemExit):
        with error_handler.error_handler():
            raise CalledProcessError(1, ('exe',), 0, b'error: \xa0\xe1', b'')
Exemple #20
0
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 test_error_handler_non_ascii_exception(mock_out_store_directory):
    with pytest.raises(error_handler.PreCommitSystemExit):
        with error_handler.error_handler():
            raise ValueError('☃')
Exemple #22
0
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()

    # https://stackoverflow.com/a/8521644/812183
    parser.add_argument(
        '-V',
        '--version',
        action='version',
        version='%(prog)s {}'.format(C.VERSION),
    )

    subparsers = parser.add_subparsers(dest='command')

    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).'),
    )
    autoupdate_parser.add_argument(
        '--repo',
        dest='repos',
        action='append',
        metavar='REPO',
        help='Only update this repository -- may be specified multiple times.',
    )

    clean_parser = subparsers.add_parser(
        'clean',
        help='Clean out pre-commit files.',
    )
    _add_color_option(clean_parser)
    _add_config_option(clean_parser)

    gc_parser = subparsers.add_parser('gc', help='Clean unused cached repos.')
    _add_color_option(gc_parser)
    _add_config_option(gc_parser)

    init_templatedir_parser = subparsers.add_parser(
        'init-templatedir',
        help=('Install hook script in a directory intended for use with '
              '`git config init.templateDir`.'),
    )
    _add_color_option(init_templatedir_parser)
    _add_config_option(init_templatedir_parser)
    init_templatedir_parser.add_argument(
        'directory',
        help='The directory in which to write the hook script.',
    )
    _add_hook_type_option(init_templatedir_parser)

    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)

    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)
    _add_run_options(run_parser)

    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)

    try_repo_parser = subparsers.add_parser(
        'try-repo',
        help='Try the hooks in a repository, useful for developing new hooks.',
    )
    _add_color_option(try_repo_parser)
    _add_config_option(try_repo_parser)
    try_repo_parser.add_argument(
        'repo',
        help='Repository to source hooks from.',
    )
    try_repo_parser.add_argument(
        '--ref',
        '--rev',
        help=('Manually select a rev to run against, otherwise the `HEAD` '
              'revision will be used.'),
    )
    _add_run_options(try_repo_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)

    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' and args.help_cmd:
        parser.parse_args([args.help_cmd, '--help'])
    elif args.command == 'help':
        parser.parse_args(['--help'])

    with error_handler(), logging_handler(args.color):
        if args.command not in COMMANDS_NO_GIT:
            _adjust_args_and_chdir(args)

        git.check_for_cygwin_mismatch()

        store = Store()
        store.mark_config_used(args.config)

        if args.command == 'autoupdate':
            if args.tags_only:
                logger.warning('--tags-only is the default')
            return autoupdate(
                args.config,
                store,
                tags_only=not args.bleeding_edge,
                repos=args.repos,
            )
        elif args.command == 'clean':
            return clean(store)
        elif args.command == 'gc':
            return gc(store)
        elif args.command == 'install':
            return install(
                args.config,
                store,
                hook_types=args.hook_types,
                overwrite=args.overwrite,
                hooks=args.install_hooks,
                skip_on_missing_config=args.allow_missing_config,
            )
        elif args.command == 'init-templatedir':
            return init_templatedir(
                args.config,
                store,
                args.directory,
                hook_types=args.hook_types,
            )
        elif args.command == 'install-hooks':
            return install_hooks(args.config, store)
        elif args.command == 'migrate-config':
            return migrate_config(args.config)
        elif args.command == 'run':
            return run(args.config, store, args)
        elif args.command == 'sample-config':
            return sample_config()
        elif args.command == 'try-repo':
            return try_repo(args)
        elif args.command == 'uninstall':
            return uninstall(hook_types=args.hook_types)
        else:
            raise NotImplementedError(
                'Command {} not implemented.'.format(args.command), )

        raise AssertionError(
            'Command {} failed to exit with a returncode'.format(
                args.command), )
def test_error_handler_non_ascii_exception(mock_store_dir):
    with pytest.raises(SystemExit):
        with error_handler.error_handler():
            raise ValueError('☃')
Exemple #24
0
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)
    _add_run_options(run_parser)

    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)

    try_repo_parser = subparsers.add_parser(
        'try-repo',
        help='Try the hooks in a repository, useful for developing new hooks.',
    )
    _add_color_option(try_repo_parser)
    _add_config_option(try_repo_parser)
    try_repo_parser.add_argument(
        'repo',
        help='Repository to source hooks from.',
    )
    try_repo_parser.add_argument(
        '--ref',
        help=('Manually select a ref to run against, otherwise the `HEAD` '
              'revision will be used.'),
    )
    _add_run_options(try_repo_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()
        elif args.command == 'try-repo':
            return try_repo(args)
        else:
            raise NotImplementedError(
                'Command {} not implemented.'.format(args.command), )

        raise AssertionError(
            'Command {} failed to exit with a returncode'.format(
                args.command), )
Exemple #25
0
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 test_error_handler_no_exception(mocked_log_and_exit):
    with error_handler.error_handler():
        pass
    assert mocked_log_and_exit.call_count == 0
Exemple #27
0
def main(argv: Sequence[str] | None = None) -> int:
    argv = argv if argv is not None else sys.argv[1:]
    parser = argparse.ArgumentParser(prog='pre-commit')

    # https://stackoverflow.com/a/8521644/812183
    parser.add_argument(
        '-V', '--version',
        action='version',
        version=f'%(prog)s {C.VERSION}',
    )

    subparsers = parser.add_subparsers(dest='command')

    def _add_cmd(name: str, *, help: str) -> argparse.ArgumentParser:
        parser = subparsers.add_parser(name, help=help)
        add_color_option(parser)
        return parser

    autoupdate_parser = _add_cmd(
        'autoupdate',
        help="Auto-update pre-commit config to the latest repos' versions.",
    )
    _add_config_option(autoupdate_parser)
    autoupdate_parser.add_argument(
        '--bleeding-edge', action='store_true',
        help=(
            'Update to the bleeding edge of `HEAD` instead of the latest '
            'tagged version (the default behavior).'
        ),
    )
    autoupdate_parser.add_argument(
        '--freeze', action='store_true',
        help='Store "frozen" hashes in `rev` instead of tag names',
    )
    autoupdate_parser.add_argument(
        '--repo', dest='repos', action='append', metavar='REPO',
        help='Only update this repository -- may be specified multiple times.',
    )

    _add_cmd('clean', help='Clean out pre-commit files.')

    _add_cmd('gc', help='Clean unused cached repos.')

    init_templatedir_parser = _add_cmd(
        'init-templatedir',
        help=(
            'Install hook script in a directory intended for use with '
            '`git config init.templateDir`.'
        ),
    )
    _add_config_option(init_templatedir_parser)
    init_templatedir_parser.add_argument(
        'directory', help='The directory in which to write the hook script.',
    )
    init_templatedir_parser.add_argument(
        '--no-allow-missing-config',
        action='store_false',
        dest='allow_missing_config',
        help='Assume cloned repos should have a `pre-commit` config.',
    )
    _add_hook_type_option(init_templatedir_parser)

    install_parser = _add_cmd('install', help='Install the pre-commit script.')
    _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 = _add_cmd(
        'install-hooks',
        help=(
            'Install hook environments for all environments in the config '
            'file.  You may find `pre-commit install --install-hooks` more '
            'useful.'
        ),
    )
    _add_config_option(install_hooks_parser)

    migrate_config_parser = _add_cmd(
        'migrate-config',
        help='Migrate list configuration to new map configuration.',
    )
    _add_config_option(migrate_config_parser)

    run_parser = _add_cmd('run', help='Run hooks.')
    _add_config_option(run_parser)
    _add_run_options(run_parser)

    _add_cmd('sample-config', help=f'Produce a sample {C.CONFIG_FILE} file')

    try_repo_parser = _add_cmd(
        'try-repo',
        help='Try the hooks in a repository, useful for developing new hooks.',
    )
    _add_config_option(try_repo_parser)
    try_repo_parser.add_argument(
        'repo', help='Repository to source hooks from.',
    )
    try_repo_parser.add_argument(
        '--ref', '--rev',
        help=(
            'Manually select a rev to run against, otherwise the `HEAD` '
            'revision will be used.'
        ),
    )
    _add_run_options(try_repo_parser)

    uninstall_parser = _add_cmd(
        'uninstall', help='Uninstall the pre-commit script.',
    )
    _add_config_option(uninstall_parser)
    _add_hook_type_option(uninstall_parser)

    validate_config_parser = _add_cmd(
        'validate-config', help='Validate .pre-commit-config.yaml files',
    )
    validate_config_parser.add_argument('filenames', nargs='*')

    validate_manifest_parser = _add_cmd(
        'validate-manifest', help='Validate .pre-commit-hooks.yaml files',
    )
    validate_manifest_parser.add_argument('filenames', nargs='*')

    # does not use `_add_cmd` because it doesn't use `--color`
    help = subparsers.add_parser(
        'help', help='Show help for a specific command.',
    )
    help.add_argument('help_cmd', nargs='?', help='Command to show help for.')

    # not intended for users to call this directly
    hook_impl_parser = subparsers.add_parser('hook-impl')
    add_color_option(hook_impl_parser)
    _add_config_option(hook_impl_parser)
    hook_impl_parser.add_argument('--hook-type')
    hook_impl_parser.add_argument('--hook-dir')
    hook_impl_parser.add_argument(
        '--skip-on-missing-config', action='store_true',
    )
    hook_impl_parser.add_argument(dest='rest', nargs=argparse.REMAINDER)

    # 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' and args.help_cmd:
        parser.parse_args([args.help_cmd, '--help'])
    elif args.command == 'help':
        parser.parse_args(['--help'])

    with error_handler(), logging_handler(args.color):
        git.check_for_cygwin_mismatch()

        store = Store()

        if args.command not in COMMANDS_NO_GIT:
            _adjust_args_and_chdir(args)
            store.mark_config_used(args.config)

        if args.command == 'autoupdate':
            return autoupdate(
                args.config, store,
                tags_only=not args.bleeding_edge,
                freeze=args.freeze,
                repos=args.repos,
            )
        elif args.command == 'clean':
            return clean(store)
        elif args.command == 'gc':
            return gc(store)
        elif args.command == 'hook-impl':
            return hook_impl(
                store,
                config=args.config,
                color=args.color,
                hook_type=args.hook_type,
                hook_dir=args.hook_dir,
                skip_on_missing_config=args.skip_on_missing_config,
                args=args.rest[1:],
            )
        elif args.command == 'install':
            return install(
                args.config, store,
                hook_types=args.hook_types,
                overwrite=args.overwrite,
                hooks=args.install_hooks,
                skip_on_missing_config=args.allow_missing_config,
            )
        elif args.command == 'init-templatedir':
            return init_templatedir(
                args.config, store, args.directory,
                hook_types=args.hook_types,
                skip_on_missing_config=args.allow_missing_config,
            )
        elif args.command == 'install-hooks':
            return install_hooks(args.config, store)
        elif args.command == 'migrate-config':
            return migrate_config(args.config)
        elif args.command == 'run':
            return run(args.config, store, args)
        elif args.command == 'sample-config':
            return sample_config()
        elif args.command == 'try-repo':
            return try_repo(args)
        elif args.command == 'uninstall':
            return uninstall(
                config_file=args.config,
                hook_types=args.hook_types,
            )
        elif args.command == 'validate-config':
            return validate_config(args.filenames)
        elif args.command == 'validate-manifest':
            return validate_manifest(args.filenames)
        else:
            raise NotImplementedError(
                f'Command {args.command} not implemented.',
            )

        raise AssertionError(
            f'Command {args.command} failed to exit with a returncode',
        )
def main(argv: Optional[Sequence[str]] = None) -> int:
    argv = argv if argv is not None else sys.argv[1:]
    parser = argparse.ArgumentParser(prog="pre-commit")

    # https://stackoverflow.com/a/8521644/812183
    parser.add_argument(
        "-V",
        "--version",
        action="version",
        version=f"%(prog)s {C.VERSION}",
    )

    subparsers = parser.add_subparsers(dest="command")

    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(
        "--bleeding-edge",
        action="store_true",
        help=("Update to the bleeding edge of `master` instead of the latest "
              "tagged version (the default behavior)."),
    )
    autoupdate_parser.add_argument(
        "--freeze",
        action="store_true",
        help='Store "frozen" hashes in `rev` instead of tag names',
    )
    autoupdate_parser.add_argument(
        "--repo",
        dest="repos",
        action="append",
        metavar="REPO",
        help="Only update this repository -- may be specified multiple times.",
    )

    clean_parser = subparsers.add_parser(
        "clean",
        help="Clean out pre-commit files.",
    )
    _add_color_option(clean_parser)
    _add_config_option(clean_parser)

    hook_impl_parser = subparsers.add_parser("hook-impl")
    _add_color_option(hook_impl_parser)
    _add_config_option(hook_impl_parser)
    hook_impl_parser.add_argument("--hook-type")
    hook_impl_parser.add_argument("--hook-dir")
    hook_impl_parser.add_argument(
        "--skip-on-missing-config",
        action="store_true",
    )
    hook_impl_parser.add_argument(dest="rest", nargs=argparse.REMAINDER)

    gc_parser = subparsers.add_parser("gc", help="Clean unused cached repos.")
    _add_color_option(gc_parser)
    _add_config_option(gc_parser)

    init_templatedir_parser = subparsers.add_parser(
        "init-templatedir",
        help=("Install hook script in a directory intended for use with "
              "`git config init.templateDir`."),
    )
    _add_color_option(init_templatedir_parser)
    _add_config_option(init_templatedir_parser)
    init_templatedir_parser.add_argument(
        "directory",
        help="The directory in which to write the hook script.",
    )
    _add_hook_type_option(init_templatedir_parser)

    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)

    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)
    _add_run_options(run_parser)

    sample_config_parser = subparsers.add_parser(
        "sample-config",
        help=f"Produce a sample {C.CONFIG_FILE} file",
    )
    _add_color_option(sample_config_parser)
    _add_config_option(sample_config_parser)

    try_repo_parser = subparsers.add_parser(
        "try-repo",
        help="Try the hooks in a repository, useful for developing new hooks.",
    )
    _add_color_option(try_repo_parser)
    _add_config_option(try_repo_parser)
    try_repo_parser.add_argument(
        "repo",
        help="Repository to source hooks from.",
    )
    try_repo_parser.add_argument(
        "--ref",
        "--rev",
        help=("Manually select a rev to run against, otherwise the `HEAD` "
              "revision will be used."),
    )
    _add_run_options(try_repo_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)

    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" and args.help_cmd:
        parser.parse_args([args.help_cmd, "--help"])
    elif args.command == "help":
        parser.parse_args(["--help"])

    with error_handler(), logging_handler(args.color):
        if args.command not in COMMANDS_NO_GIT:
            _adjust_args_and_chdir(args)

        git.check_for_cygwin_mismatch()

        store = Store()
        store.mark_config_used(args.config)

        if args.command == "autoupdate":
            return autoupdate(
                args.config,
                store,
                tags_only=not args.bleeding_edge,
                freeze=args.freeze,
                repos=args.repos,
            )
        elif args.command == "clean":
            return clean(store)
        elif args.command == "gc":
            return gc(store)
        elif args.command == "hook-impl":
            return hook_impl(
                store,
                config=args.config,
                color=args.color,
                hook_type=args.hook_type,
                hook_dir=args.hook_dir,
                skip_on_missing_config=args.skip_on_missing_config,
                args=args.rest[1:],
            )
        elif args.command == "install":
            return install(
                args.config,
                store,
                hook_types=args.hook_types,
                overwrite=args.overwrite,
                hooks=args.install_hooks,
                skip_on_missing_config=args.allow_missing_config,
            )
        elif args.command == "init-templatedir":
            return init_templatedir(
                args.config,
                store,
                args.directory,
                hook_types=args.hook_types,
            )
        elif args.command == "install-hooks":
            return install_hooks(args.config, store)
        elif args.command == "migrate-config":
            return migrate_config(args.config)
        elif args.command == "run":
            return run(args.config, store, args)
        elif args.command == "sample-config":
            return sample_config()
        elif args.command == "try-repo":
            return try_repo(args)
        elif args.command == "uninstall":
            return uninstall(hook_types=args.hook_types)
        else:
            raise NotImplementedError(
                f"Command {args.command} not implemented.", )

        raise AssertionError(
            f"Command {args.command} failed to exit with a returncode", )
Exemple #29
0
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()

    # https://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)

    gc_parser = subparsers.add_parser('gc', help='Clean unused cached repos.')
    _add_color_option(gc_parser)
    _add_config_option(gc_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).'
        ),
    )
    autoupdate_parser.add_argument(
        '--repo', dest='repos', action='append', metavar='REPO',
        help='Only update this repository -- may be specified multiple times.',
    )

    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)
    _add_run_options(run_parser)

    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)

    try_repo_parser = subparsers.add_parser(
        'try-repo',
        help='Try the hooks in a repository, useful for developing new hooks.',
    )
    _add_color_option(try_repo_parser)
    _add_config_option(try_repo_parser)
    try_repo_parser.add_argument(
        'repo', help='Repository to source hooks from.',
    )
    try_repo_parser.add_argument(
        '--ref', '--rev',
        help=(
            'Manually select a rev to run against, otherwise the `HEAD` '
            'revision will be used.'
        ),
    )
    _add_run_options(try_repo_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 == 'help' and args.help_cmd:
        parser.parse_args([args.help_cmd, '--help'])
    elif args.command == 'help':
        parser.parse_args(['--help'])

    with error_handler(), logging_handler(args.color):
        if args.command not in {'clean', 'gc', 'sample-config'}:
            _adjust_args_and_chdir(args)

        git.check_for_cygwin_mismatch()

        store = Store()
        store.mark_config_used(args.config)

        if args.command == 'install':
            return install(
                args.config, store,
                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(args.config, store)
        elif args.command == 'uninstall':
            return uninstall(hook_type=args.hook_type)
        elif args.command == 'clean':
            return clean(store)
        elif args.command == 'gc':
            return gc(store)
        elif args.command == 'autoupdate':
            if args.tags_only:
                logger.warning('--tags-only is the default')
            return autoupdate(
                args.config, store,
                tags_only=not args.bleeding_edge,
                repos=args.repos,
            )
        elif args.command == 'migrate-config':
            return migrate_config(args.config)
        elif args.command == 'run':
            return run(args.config, store, args)
        elif args.command == 'sample-config':
            return sample_config()
        elif args.command == 'try-repo':
            return try_repo(args)
        else:
            raise NotImplementedError(
                'Command {} not implemented.'.format(args.command),
            )

        raise AssertionError(
            'Command {} failed to exit with a returncode'.format(args.command),
        )