Skip to content

Commit 171fd18

Browse files
authored
Merge pull request #1395 from pre-commit/argument_length
validate argument length as part of hook-impl
2 parents 282527e + 80a59db commit 171fd18

File tree

2 files changed

+75
-1
lines changed

2 files changed

+75
-1
lines changed

pre_commit/commands/hook_impl.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,15 +147,44 @@ def _pre_push_ns(
147147
return None
148148

149149

150+
_EXPECTED_ARG_LENGTH_BY_HOOK = {
151+
'commit-msg': 1,
152+
'post-checkout': 3,
153+
'pre-commit': 0,
154+
'pre-merge-commit': 0,
155+
'pre-push': 2,
156+
}
157+
158+
159+
def _check_args_length(hook_type: str, args: Sequence[str]) -> None:
160+
if hook_type == 'prepare-commit-msg':
161+
if len(args) < 1 or len(args) > 3:
162+
raise SystemExit(
163+
f'hook-impl for {hook_type} expected 1, 2, or 3 arguments '
164+
f'but got {len(args)}: {args}',
165+
)
166+
elif hook_type in _EXPECTED_ARG_LENGTH_BY_HOOK:
167+
expected = _EXPECTED_ARG_LENGTH_BY_HOOK[hook_type]
168+
if len(args) != expected:
169+
arguments_s = 'argument' if expected == 1 else 'arguments'
170+
raise SystemExit(
171+
f'hook-impl for {hook_type} expected {expected} {arguments_s} '
172+
f'but got {len(args)}: {args}',
173+
)
174+
else:
175+
raise AssertionError(f'unexpected hook type: {hook_type}')
176+
177+
150178
def _run_ns(
151179
hook_type: str,
152180
color: bool,
153181
args: Sequence[str],
154182
stdin: bytes,
155183
) -> Optional[argparse.Namespace]:
184+
_check_args_length(hook_type, args)
156185
if hook_type == 'pre-push':
157186
return _pre_push_ns(color, args, stdin)
158-
elif hook_type in {'prepare-commit-msg', 'commit-msg'}:
187+
elif hook_type in {'commit-msg', 'prepare-commit-msg'}:
159188
return _ns(hook_type, color, commit_msg_filename=args[0])
160189
elif hook_type in {'pre-merge-commit', 'pre-commit'}:
161190
return _ns(hook_type, color)

tests/commands/hook_impl_test.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,51 @@ def call(*_, **__):
8989
call()
9090

9191

92+
@pytest.mark.parametrize(
93+
('hook_type', 'args'),
94+
(
95+
('pre-commit', []),
96+
('pre-merge-commit', []),
97+
('pre-push', ['branch_name', 'remote_name']),
98+
('commit-msg', ['.git/COMMIT_EDITMSG']),
99+
('post-checkout', ['old_head', 'new_head', '1']),
100+
# multiple choices for commit-editmsg
101+
('prepare-commit-msg', ['.git/COMMIT_EDITMSG']),
102+
('prepare-commit-msg', ['.git/COMMIT_EDITMSG', 'message']),
103+
('prepare-commit-msg', ['.git/COMMIT_EDITMSG', 'commit', 'deadbeef']),
104+
),
105+
)
106+
def test_check_args_length_ok(hook_type, args):
107+
hook_impl._check_args_length(hook_type, args)
108+
109+
110+
def test_check_args_length_error_too_many_plural():
111+
with pytest.raises(SystemExit) as excinfo:
112+
hook_impl._check_args_length('pre-commit', ['run', '--all-files'])
113+
msg, = excinfo.value.args
114+
assert msg == (
115+
'hook-impl for pre-commit expected 0 arguments but got 2: '
116+
"['run', '--all-files']"
117+
)
118+
119+
120+
def test_check_args_length_error_too_many_singluar():
121+
with pytest.raises(SystemExit) as excinfo:
122+
hook_impl._check_args_length('commit-msg', [])
123+
msg, = excinfo.value.args
124+
assert msg == 'hook-impl for commit-msg expected 1 argument but got 0: []'
125+
126+
127+
def test_check_args_length_prepare_commit_msg_error():
128+
with pytest.raises(SystemExit) as excinfo:
129+
hook_impl._check_args_length('prepare-commit-msg', [])
130+
msg, = excinfo.value.args
131+
assert msg == (
132+
'hook-impl for prepare-commit-msg expected 1, 2, or 3 arguments '
133+
'but got 0: []'
134+
)
135+
136+
92137
def test_run_ns_pre_commit():
93138
ns = hook_impl._run_ns('pre-commit', True, (), b'')
94139
assert ns is not None

0 commit comments

Comments
 (0)