def test_install_hooks_directory_not_present(tempdir_factory): path = git_dir(tempdir_factory) # Simulate some git clients which don't make .git/hooks #234 hooks = os.path.join(path, '.git', 'hooks') if os.path.exists(hooks): # pragma: no cover (latest git) shutil.rmtree(hooks) runner = Runner(path, C.CONFIG_FILE) install(runner) assert os.path.exists(runner.pre_commit_path)
def test_install_hooks_dead_symlink( tempdir_factory, ): # pragma: no cover (non-windows) path = git_dir(tempdir_factory) runner = Runner(path, C.CONFIG_FILE) mkdirp(os.path.dirname(runner.pre_commit_path)) os.symlink('/fake/baz', os.path.join(path, '.git', 'hooks', 'pre-commit')) install(runner) assert os.path.exists(runner.pre_commit_path)
def test_autoupdate_local_hooks(tempdir_factory): git_path = git_dir(tempdir_factory) config = config_with_local_hooks() path = add_config_to_repo(git_path, config) runner = Runner(path, C.CONFIG_FILE) assert autoupdate(runner) == 0 new_config_writen = load_config(runner.config_file_path) assert len(new_config_writen) == 1 assert new_config_writen[0] == config
def test_commit_msg_integration_failing( commit_msg_repo, tempdir_factory, store, ): runner = Runner(commit_msg_repo, C.CONFIG_FILE) install(runner, store, hook_type='commit-msg') retc, out = _get_commit_output(tempdir_factory) assert retc == 1 assert out.startswith('Must have "Signed off by:"...') assert out.strip().endswith('...Failed')
def test_install_overwrite_no_existing_hooks(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path, C.CONFIG_FILE) assert install(runner, store, overwrite=True) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert NORMAL_PRE_COMMIT_RUN.match(output)
def test_unicode_merge_commit_message(tempdir_factory): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): assert install(Runner(path, C.CONFIG_FILE)) == 0 cmd_output('git', 'checkout', 'master', '-b', 'foo') cmd_output('git', 'commit', '--allow-empty', '-m', 'branch2') cmd_output('git', 'checkout', 'master') cmd_output('git', 'merge', 'foo', '--no-ff', '--no-commit', '-m', '☃') # Used to crash cmd_output('git', 'commit', '--no-edit')
def test_pre_push_integration_empty_push(tempdir_factory): upstream = make_consuming_repo(tempdir_factory, 'script_hooks_repo') path = tempdir_factory.get() cmd_output('git', 'clone', upstream, path) with cwd(path): install(Runner(path, C.CONFIG_FILE), hook_type='pre-push') _get_push_output(tempdir_factory) retc, output = _get_push_output(tempdir_factory) assert output == 'Everything up-to-date\n' assert retc == 0
def test_get_hook_path(tmpdir_factory): path = git_dir(tmpdir_factory) with cwd(path): runner = Runner(path) expected_paths = (os.path.join(path, '.git/hooks/pre-commit'), os.path.join(path, '.git/hooks/pre-commit.legacy')) assert expected_paths == get_hook_path(runner, 'pre-commit') expected_paths = (os.path.join(path, '.git/hooks/pre-push'), os.path.join(path, '.git/hooks/pre-push.legacy')) assert expected_paths == get_hook_path(runner, 'pre-push')
def test_installs_hooks_with_hooks_True(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): install(Runner(path, C.CONFIG_FILE), store, hooks=True) 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): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path, C.CONFIG_FILE) remove_config_from_repo(path) assert install(runner, overwrite=True, skip_on_missing_conf=False) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 1
def test_install_pre_commit_and_run_custom_path(tempdir_factory, store): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): cmd_output('git', 'mv', C.CONFIG_FILE, 'custom-config.yaml') cmd_output('git', 'commit', '-m', 'move pre-commit config') assert install(Runner(path, 'custom-config.yaml'), store) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert NORMAL_PRE_COMMIT_RUN.match(output)
def test_autoupdate_tags_only(tagged_repo_with_more_commits, in_tmpdir, store): config = make_config_from_repo( tagged_repo_with_more_commits.path, rev=tagged_repo_with_more_commits.original_rev, ) write_config('.', config) ret = autoupdate(Runner('.', C.CONFIG_FILE), store, tags_only=True) assert ret == 0 assert 'v1.2.3' in open(C.CONFIG_FILE).read()
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_install_in_worktree_and_run(tempdir_factory, store): src_path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') path = tempdir_factory.get() cmd_output('git', '-C', src_path, 'branch', '-m', 'notmaster') cmd_output('git', '-C', src_path, 'worktree', 'add', path, '-b', 'master') with cwd(path): assert install(Runner(path, C.CONFIG_FILE), store) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert NORMAL_PRE_COMMIT_RUN.match(output)
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('.', C.CONFIG_FILE), tags_only=False) assert ret == 0 assert 'v1.2.3' in open(C.CONFIG_FILE).read()
def test_uninstall_doesnt_remove_not_our_hooks(tmpdir_factory): path = git_dir(tmpdir_factory) with cwd(path): runner = Runner(path) with io.open(runner.pre_commit_path, 'w') as pre_commit_file: pre_commit_file.write('#!/usr/bin/env bash\necho 1\n') make_executable(runner.pre_commit_path) assert uninstall(runner) == 0 assert os.path.exists(runner.pre_commit_path)
def test_autoupdate_tagged_repo(tagged_repo, in_tmpdir, store): config = make_config_from_repo( tagged_repo.path, rev=tagged_repo.original_rev, ) write_config('.', config) ret = autoupdate(Runner('.', C.CONFIG_FILE), store, tags_only=False) assert ret == 0 with open(C.CONFIG_FILE) as f: assert 'v1.2.3' in f.read()
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) before = open(C.CONFIG_FILE).read() assert '^$' not in before ret = autoupdate(Runner('.', C.CONFIG_FILE), store, tags_only=False) after = open(C.CONFIG_FILE).read() assert ret == 0 assert before == after
def test_pre_push_integration_accepted(tmpdir_factory): upstream = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') path = tmpdir_factory.get() cmd_output('git', 'clone', upstream, path) with cwd(path): install(Runner(path), hook_type='pre-push') assert _get_commit_output(tmpdir_factory)[0] == 0 retc, output = _get_push_output(tmpdir_factory) assert retc == 0 assert 'Bash hook' in output assert 'Passed' in output
def test_install_hooks_command(tempdir_factory, mock_out_store_directory): path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') with cwd(path): runner = Runner(path, C.CONFIG_FILE) install(runner) install_hooks(runner) ret, output = _get_commit_output( tempdir_factory, pre_commit_home=mock_out_store_directory, ) assert ret == 0 assert PRE_INSTALLED.match(output)
def test_non_ascii_hook_id( repo_with_passing_hook, mock_out_store_directory, tempdir_factory, ): with cwd(repo_with_passing_hook): install(Runner(repo_with_passing_hook, C.CONFIG_FILE)) _, stdout, _ = cmd_output_mocked_pre_commit_home( sys.executable, '-m', 'pre_commit.main', 'run', '☃', retcode=None, tempdir_factory=tempdir_factory, ) assert 'UnicodeDecodeError' not in stdout # Doesn't actually happen, but a reasonable assertion assert 'UnicodeEncodeError' not in stdout
def test_uninstall_doesnt_remove_not_our_hooks(tempdir_factory): path = git_dir(tempdir_factory) with cwd(path): runner = Runner(path, C.CONFIG_FILE) mkdirp(os.path.join(path, '.git/hooks')) with io.open(os.path.join(path, '.git/hooks/pre-commit'), 'w') as f: f.write('#!/usr/bin/env bash\necho 1\n') make_executable(f.name) assert uninstall(runner) == 0 assert os.path.exists(os.path.join(path, '.git/hooks/pre-commit'))
def test_install_in_submodule_and_run(tempdir_factory, store): src_path = make_consuming_repo(tempdir_factory, 'script_hooks_repo') parent_path = git_dir(tempdir_factory) cmd_output('git', 'submodule', 'add', src_path, 'sub', cwd=parent_path) cmd_output('git', 'commit', '-m', 'foo', cwd=parent_path) sub_pth = os.path.join(parent_path, 'sub') with cwd(sub_pth): assert install(Runner(sub_pth, C.CONFIG_FILE), store) == 0 ret, output = _get_commit_output(tempdir_factory) assert ret == 0 assert NORMAL_PRE_COMMIT_RUN.match(output)
def test_installs_hooks_with_hooks_True( tmpdir_factory, mock_out_store_directory, ): path = make_consuming_repo(tmpdir_factory, 'script_hooks_repo') with cwd(path): install(Runner(path), hooks=True) ret, output = _get_commit_output( tmpdir_factory, home=mock_out_store_directory, ) assert ret == 0 assert PRE_INSTALLED.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_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_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_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_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_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()