Add staged_files_only context manager. · precommit/pre-commit@4ed9120 · GitHub
Skip to content

Commit 4ed9120

Browse files
committed
Add staged_files_only context manager.
1 parent 7496151 commit 4ed9120

7 files changed

Lines changed: 287 additions & 9 deletions

File tree

pre_commit/prefixed_command_runner.py

Lines changed: 12 additions & 9 deletions

pre_commit/staged_files_only.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
2+
import contextlib
3+
import time
4+
5+
from pre_commit.prefixed_command_runner import CalledProcessError
6+
7+
8+
@contextlib.contextmanager
9+
def staged_files_only(cmd_runner):
10+
"""Clear any unstaged changes from the git working directory inside this
11+
context.
12+
13+
Args:
14+
cmd_runner - PrefixedCommandRunner
15+
"""
16+
# Determine if there are unstaged files
17+
retcode, _, _ = cmd_runner.run(
18+
['git', 'diff-files', '--quiet'],
19+
retcode=None,
20+
)
21+
if retcode:
22+
# TODO: print a warning message that unstaged things are being stashed
23+
# Save the current unstaged changes as a patch
24+
# TODO: use a more unique patch filename
25+
patch_filename = cmd_runner.path('patch{0}'.format(time.time()))
26+
with open(patch_filename, 'w') as patch_file:
27+
cmd_runner.run(['git', 'diff', '--binary'], stdout=patch_file)
28+
29+
# Clear the working directory of unstaged changes
30+
cmd_runner.run(['git', 'checkout', '--', '.'])
31+
try:
32+
yield
33+
finally:
34+
# Try to apply the patch we saved
35+
try:
36+
cmd_runner.run(['git', 'apply', patch_filename])
37+
except CalledProcessError:
38+
# TOOD: print a warning about rolling back changes made by hooks
39+
# We failed to apply the patch, presumably due to fixes made
40+
# by hooks.
41+
# Roll back the changes made by hooks.
42+
cmd_runner.run(['git', 'checkout', '--', '.'])
43+
cmd_runner.run(['git', 'apply', patch_filename])
44+
else:
45+
# There weren't any staged files so we don't need to do anything
46+
# special
47+
yield

testing/resources/img1.jpg

843 Bytes
Loading

testing/resources/img2.jpg

891 Bytes
Loading

testing/resources/img3.jpg

859 Bytes
Loading

tests/prefixed_command_runner_test.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@
99
from pre_commit.prefixed_command_runner import PrefixedCommandRunner
1010

1111

12+
def test_CalledProcessError_str():
13+
error = CalledProcessError(1, ['git', 'status'], 0, ('stdout', 'stderr'))
14+
assert str(error) == (
15+
"Command: ['git', 'status']\n"
16+
"Return code: 1\n"
17+
"Expected return code: 0\n"
18+
"Output: ('stdout', 'stderr')\n"
19+
)
20+
21+
1222
@pytest.fixture
1323
def popen_mock():
1424
popen = mock.Mock(spec=subprocess.Popen)

tests/staged_files_only_test.py

Lines changed: 218 additions & 0 deletions

0 commit comments

Comments
 (0)