-
Notifications
You must be signed in to change notification settings - Fork 3
/
pre_commit_ci_config.py
127 lines (100 loc) · 3.35 KB
/
pre_commit_ci_config.py
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
from __future__ import annotations
import argparse
import functools
from collections.abc import Sequence
from typing import Any
import cfgv
import yaml
Loader = getattr(yaml, 'CSafeLoader', yaml.SafeLoader)
yaml_load = functools.partial(yaml.load, Loader=Loader)
def _check_non_empty_string(val: str) -> None:
if not val:
raise cfgv.ValidationError('string cannot be empty')
def _check_autoupdate_branch(val: str) -> None:
if val == 'pre-commit-ci-update-config':
raise cfgv.ValidationError(f'autoupdate branch cannot be {val!r}')
class ValidateSkip:
def check(self, dct: dict[str, Any]) -> None:
all_ids = {
hook_id
for repo in dct['repos']
for hook in repo['hooks']
for hook_id in (hook['id'], hook.get('alias'))
if hook_id is not None
}
unexpected_skip = set(dct.get('ci', {}).get('skip', ())) - all_ids
if unexpected_skip:
with cfgv.validate_context('At key: ci'):
with cfgv.validate_context('At key: skip'):
raise cfgv.ValidationError(
f'unexpected hook ids: '
f'{", ".join(sorted(unexpected_skip))}',
)
apply_default = cfgv.Required.apply_default
remove_default = cfgv.Required.remove_default
HOOK_DICT = cfgv.Map(
'Hook', 'id',
cfgv.Required('id', cfgv.check_string),
cfgv.OptionalNoDefault('alias', cfgv.check_string),
)
CONFIG_REPO_DICT = cfgv.Map(
'Repository', 'repo',
cfgv.Required('repo', cfgv.check_string),
cfgv.RequiredRecurse('hooks', cfgv.Array(HOOK_DICT)),
)
AUTOFIX_DEFAULT_COMMIT_MSG = '''\
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
'''
CI_DICT = cfgv.Map(
'CI', None,
cfgv.Optional(
'autofix_commit_msg',
cfgv.check_and(cfgv.check_string, _check_non_empty_string),
AUTOFIX_DEFAULT_COMMIT_MSG,
),
cfgv.Optional('autofix_prs', cfgv.check_bool, True),
cfgv.Optional(
'autoupdate_branch',
cfgv.check_and(cfgv.check_string, _check_autoupdate_branch),
'',
),
cfgv.Optional(
'autoupdate_commit_msg',
cfgv.check_and(cfgv.check_string, _check_non_empty_string),
'[pre-commit.ci] pre-commit autoupdate',
),
cfgv.Optional(
'autoupdate_schedule',
cfgv.check_one_of(('weekly', 'monthly', 'quarterly')),
'weekly',
),
cfgv.Optional('skip', cfgv.check_array(cfgv.check_string), []),
cfgv.Optional('submodules', cfgv.check_bool, False),
)
SCHEMA = cfgv.Map(
'Config', None,
# to cross-validate hook values
cfgv.RequiredRecurse('repos', cfgv.Array(CONFIG_REPO_DICT)),
# our configuration
cfgv.OptionalRecurse('ci', CI_DICT, {}),
ValidateSkip(),
)
def main(argv: Sequence[str] | None = None) -> int:
parser = argparse.ArgumentParser()
parser.add_argument('filenames', nargs='*')
args = parser.parse_args(argv)
retv = 0
for filename in args.filenames:
try:
cfgv.load_from_filename(
filename,
schema=SCHEMA,
load_strategy=yaml_load,
)
except cfgv.ValidationError as e:
print(str(e).strip())
retv = 1
return retv
if __name__ == '__main__':
raise SystemExit(main())