from __future__ import annotations import os.path import re import time from unittest import mock import re_assert from pre_commit import git from pre_commit.commands.try_repo import try_repo from pre_commit.util import cmd_output from testing.auto_namedtuple import auto_namedtuple from testing.fixtures import git_dir from testing.fixtures import make_repo from testing.fixtures import modify_manifest from testing.util import cwd from testing.util import git_commit from testing.util import run_opts def try_repo_opts(repo, ref=None, **kwargs): return auto_namedtuple(repo=repo, ref=ref, **run_opts(**kwargs)._asdict()) def _get_out(cap_out): out = re.sub(r'\[INFO\].+\n', '', cap_out.get()) start, using_config, config, rest = out.split(f'{"=" * 79}\n') assert using_config == 'Using config:\n' return start, config, rest def _add_test_file(): open('test-file', 'a').close() cmd_output('git', 'add', '.') def _run_try_repo(tempdir_factory, **kwargs): repo = make_repo(tempdir_factory, 'modified_file_returns_zero_repo') with cwd(git_dir(tempdir_factory)): _add_test_file() assert not try_repo(try_repo_opts(repo, **kwargs)) def test_try_repo_repo_only(cap_out, tempdir_factory): with mock.patch.object(time, 'monotonic', return_value=0.0): _run_try_repo(tempdir_factory, verbose=True) start, config, rest = _get_out(cap_out) assert start == '' config_pattern = re_assert.Matches( '^repos:\n' '- repo: .+\n' ' rev: .+\n' ' hooks:\n' ' - id: bash_hook\n' ' - id: bash_hook2\n' ' - id: bash_hook3\n$', ) config_pattern.assert_matches(config) assert rest == '''\ Bash hook............................................(no files to check)Skipped - hook id: bash_hook Bash hook................................................................Passed - hook id: bash_hook2 - duration: 0s test-file Bash hook............................................(no files to check)Skipped - hook id: bash_hook3 ''' def test_try_repo_with_specific_hook(cap_out, tempdir_factory): _run_try_repo(tempdir_factory, hook='bash_hook', verbose=True) start, config, rest = _get_out(cap_out) assert start == '' config_pattern = re_assert.Matches( '^repos:\n' '- repo: .+\n' ' rev: .+\n' ' hooks:\n' ' - id: bash_hook\n$', ) config_pattern.assert_matches(config) assert rest == '''\ Bash hook............................................(no files to check)Skipped - hook id: bash_hook ''' def test_try_repo_relative_path(cap_out, tempdir_factory): repo = make_repo(tempdir_factory, 'modified_file_returns_zero_repo') with cwd(git_dir(tempdir_factory)): _add_test_file() relative_repo = os.path.relpath(repo, '.') # previously crashed on cloning a relative path assert not try_repo(try_repo_opts(relative_repo, hook='bash_hook')) def test_try_repo_bare_repo(cap_out, tempdir_factory): repo = make_repo(tempdir_factory, 'modified_file_returns_zero_repo') with cwd(git_dir(tempdir_factory)): _add_test_file() bare_repo = os.path.join(repo, '.git') # previously crashed attempting modification changes assert not try_repo(try_repo_opts(bare_repo, hook='bash_hook')) def test_try_repo_specific_revision(cap_out, tempdir_factory): repo = make_repo(tempdir_factory, 'script_hooks_repo') ref = git.head_rev(repo) git_commit(cwd=repo) with cwd(git_dir(tempdir_factory)): _add_test_file() assert not try_repo(try_repo_opts(repo, ref=ref)) _, config, _ = _get_out(cap_out) assert ref in config def test_try_repo_uncommitted_changes(cap_out, tempdir_factory): repo = make_repo(tempdir_factory, 'script_hooks_repo') # make an uncommitted change with modify_manifest(repo, commit=False) as manifest: manifest[0]['name'] = 'modified name!' with cwd(git_dir(tempdir_factory)): open('test-fie', 'a').close() cmd_output('git', 'add', '.') assert not try_repo(try_repo_opts(repo)) start, config, rest = _get_out(cap_out) assert start == '[WARNING] Creating temporary repo with uncommitted changes...\n' # noqa: E501 config_pattern = re_assert.Matches( '^repos:\n' '- repo: .+shadow-repo\n' ' rev: .+\n' ' hooks:\n' ' - id: bash_hook\n$', ) config_pattern.assert_matches(config) assert rest == 'modified name!...........................................................Passed\n' # noqa: E501 def test_try_repo_staged_changes(tempdir_factory): repo = make_repo(tempdir_factory, 'modified_file_returns_zero_repo') with cwd(repo): open('staged-file', 'a').close() open('second-staged-file', 'a').close() cmd_output('git', 'add', '.') with cwd(git_dir(tempdir_factory)): assert not try_repo(try_repo_opts(repo, hook='bash_hook'))