summaryrefslogtreecommitdiffstats
path: root/testing/fixtures.py
blob: f7def081f50e1c2df4d7503851a122fb5ae66f18 (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
import contextlib
import os.path
import shutil

from cfgv import apply_defaults
from cfgv import validate

import pre_commit.constants as C
from pre_commit import git
from pre_commit.clientlib import CONFIG_SCHEMA
from pre_commit.clientlib import load_manifest
from pre_commit.util import cmd_output
from pre_commit.util import yaml_dump
from pre_commit.util import yaml_load
from testing.util import get_resource_path
from testing.util import git_commit


def copy_tree_to_path(src_dir, dest_dir):
    """Copies all of the things inside src_dir to an already existing dest_dir.

    This looks eerily similar to shutil.copytree, but copytree has no option
    for not creating dest_dir.
    """
    names = os.listdir(src_dir)

    for name in names:
        srcname = os.path.join(src_dir, name)
        destname = os.path.join(dest_dir, name)

        if os.path.isdir(srcname):
            shutil.copytree(srcname, destname)
        else:
            shutil.copy(srcname, destname)


def git_dir(tempdir_factory):
    path = tempdir_factory.get()
    cmd_output('git', 'init', path)
    return path


def make_repo(tempdir_factory, repo_source):
    path = git_dir(tempdir_factory)
    copy_tree_to_path(get_resource_path(repo_source), path)
    cmd_output('git', 'add', '.', cwd=path)
    git_commit(msg=make_repo.__name__, cwd=path)
    return path


@contextlib.contextmanager
def modify_manifest(path, commit=True):
    """Modify the manifest yielded by this context to write to
    .pre-commit-hooks.yaml.
    """
    manifest_path = os.path.join(path, C.MANIFEST_FILE)
    with open(manifest_path) as f:
        manifest = yaml_load(f.read())
    yield manifest
    with open(manifest_path, 'w') as manifest_file:
        manifest_file.write(yaml_dump(manifest))
    if commit:
        git_commit(msg=modify_manifest.__name__, cwd=path)


@contextlib.contextmanager
def modify_config(path='.', commit=True):
    """Modify the config yielded by this context to write to
    .pre-commit-config.yaml
    """
    config_path = os.path.join(path, C.CONFIG_FILE)
    with open(config_path) as f:
        config = yaml_load(f.read())
    yield config
    with open(config_path, 'w', encoding='UTF-8') as config_file:
        config_file.write(yaml_dump(config))
    if commit:
        git_commit(msg=modify_config.__name__, cwd=path)


def sample_local_config():
    return {
        'repo': 'local',
        'hooks': [{
            'id': 'do_not_commit',
            'name': 'Block if "DO NOT COMMIT" is found',
            'entry': 'DO NOT COMMIT',
            'language': 'pygrep',
        }],
    }


def sample_meta_config():
    return {'repo': 'meta', 'hooks': [{'id': 'check-useless-excludes'}]}


def make_config_from_repo(repo_path, rev=None, hooks=None, check=True):
    manifest = load_manifest(os.path.join(repo_path, C.MANIFEST_FILE))
    config = {
        'repo': f'file://{repo_path}',
        'rev': rev or git.head_rev(repo_path),
        'hooks': hooks or [{'id': hook['id']} for hook in manifest],
    }

    if check:
        wrapped = validate({'repos': [config]}, CONFIG_SCHEMA)
        wrapped = apply_defaults(wrapped, CONFIG_SCHEMA)
        config, = wrapped['repos']
        return config
    else:
        return config


def read_config(directory, config_file=C.CONFIG_FILE):
    config_path = os.path.join(directory, config_file)
    with open(config_path) as f:
        config = yaml_load(f.read())
    return config


def write_config(directory, config, config_file=C.CONFIG_FILE):
    if type(config) is not list and 'repos' not in config:
        assert isinstance(config, dict), config
        config = {'repos': [config]}
    with open(os.path.join(directory, config_file), 'w') as outfile:
        outfile.write(yaml_dump(config))


def add_config_to_repo(git_path, config, config_file=C.CONFIG_FILE):
    write_config(git_path, config, config_file=config_file)
    cmd_output('git', 'add', config_file, cwd=git_path)
    git_commit(msg=add_config_to_repo.__name__, cwd=git_path)
    return git_path


def remove_config_from_repo(git_path, config_file=C.CONFIG_FILE):
    cmd_output('git', 'rm', config_file, cwd=git_path)
    git_commit(msg=remove_config_from_repo.__name__, cwd=git_path)
    return git_path


def make_consuming_repo(tempdir_factory, repo_source):
    path = make_repo(tempdir_factory, repo_source)
    config = make_config_from_repo(path)
    git_path = git_dir(tempdir_factory)
    return add_config_to_repo(git_path, config)