summaryrefslogtreecommitdiffstats
path: root/tests/commands/try_repo_test.py
blob: c5f891ea7716a24d130a1def5385b4ef3de7692f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
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'))