Skip to content

Commit a3f78bc

Browse files
committed
Fail a hook if it makes modifications. Resolves pre-commit#285
1 parent 67f6f81 commit a3f78bc

File tree

5 files changed

+47
-0
lines changed

5 files changed

+47
-0
lines changed

pre_commit/commands/run.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,13 @@ def _run_single_hook(hook, repo, args, write, skips=frozenset()):
8585
write(get_hook_message(_hook_msg_start(hook, args.verbose), end_len=6))
8686
sys.stdout.flush()
8787

88+
diff_before = cmd_output('git', 'diff', retcode=None)
8889
retcode, stdout, stderr = repo.run_hook(hook, filenames)
90+
diff_after = cmd_output('git', 'diff', retcode=None)
91+
92+
# If the hook makes changes, fail the commit
93+
if diff_before != diff_after:
94+
retcode = 1
8995

9096
if retcode:
9197
retcode = 1
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env bash
2+
3+
for f in $@; do
4+
echo modified > "$f"
5+
echo "Modified: $f!"
6+
done
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/usr/bin/env bash
2+
echo $@
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
- id: bash_hook
2+
name: Bash hook
3+
entry: bin/hook.sh
4+
language: script
5+
files: ''
6+
- id: bash_hook2
7+
name: Bash hook
8+
entry: bin/hook2.sh
9+
language: script
10+
files: ''

tests/commands/run_test.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,29 @@ def test_arbitrary_bytes_hook(tempdir_factory, mock_out_store_directory):
120120
_test_run(git_path, {}, (b'\xe2\x98\x83\xb2\n',), 1, True)
121121

122122

123+
def test_hook_that_modifies_but_returns_zero(
124+
tempdir_factory, mock_out_store_directory,
125+
):
126+
git_path = make_consuming_repo(
127+
tempdir_factory, 'modified_file_returns_zero_repo',
128+
)
129+
with cwd(git_path):
130+
_test_run(
131+
git_path,
132+
{},
133+
(
134+
# The first should fail
135+
b'Failed',
136+
# With a modified file (the hook's output)
137+
b'Modified: foo.py',
138+
# The next hook should pass despite the first modifying
139+
b'Passed',
140+
),
141+
1,
142+
True,
143+
)
144+
145+
123146
@pytest.mark.parametrize(
124147
('options', 'outputs', 'expected_ret', 'stage'),
125148
(

0 commit comments

Comments
 (0)