Skip to content

Commit eae04bf

Browse files
committed
IndexFile.commit() now runs pre-commit and post-commit and commit-msg hooks.
1 parent c7f657f commit eae04bf

File tree

3 files changed

+108
-32
lines changed

3 files changed

+108
-32
lines changed

‎git/index/base.py

+19
Original file line numberDiff line numberDiff line change
@@ -948,13 +948,32 @@ def commit(self, message, parent_commits=None, head=True, author=None,
948948
:return: Commit object representing the new commit"""
949949
if not skip_hooks:
950950
run_commit_hook('pre-commit', self)
951+
952+
self._write_commit_editmsg(message)
953+
run_commit_hook('commit-msg', self, self._commit_editmsg_filepath())
954+
message = self._read_commit_editmsg()
955+
self._remove_commit_editmsg()
951956
tree = self.write_tree()
952957
rval = Commit.create_from_tree(self.repo, tree, message, parent_commits,
953958
head, author=author, committer=committer,
954959
author_date=author_date, commit_date=commit_date)
955960
if not skip_hooks:
956961
run_commit_hook('post-commit', self)
957962
return rval
963+
964+
def _write_commit_editmsg(self, message):
965+
with open(self._commit_editmsg_filepath(), "wb") as commit_editmsg_file:
966+
commit_editmsg_file.write(message.encode(defenc))
967+
968+
def _remove_commit_editmsg(self):
969+
os.remove(self._commit_editmsg_filepath())
970+
971+
def _read_commit_editmsg(self):
972+
with open(self._commit_editmsg_filepath(), "rb") as commit_editmsg_file:
973+
return commit_editmsg_file.read().decode(defenc)
974+
975+
def _commit_editmsg_filepath(self):
976+
return osp.join(self.repo.common_dir, "COMMIT_EDITMSG")
958977

959978
@classmethod
960979
def _flush_stdin_and_wait(cls, proc, ignore_stdout=False):

‎git/index/fun.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,11 @@ def hook_path(name, git_dir):
6262
return osp.join(git_dir, 'hooks', name)
6363

6464

65-
def run_commit_hook(name, index):
65+
def run_commit_hook(name, index, *args):
6666
"""Run the commit hook of the given name. Silently ignores hooks that do not exist.
6767
:param name: name of hook, like 'pre-commit'
6868
:param index: IndexFile instance
69+
:param args: arguments passed to hook file
6970
:raises HookExecutionError: """
7071
hp = hook_path(name, index.repo.git_dir)
7172
if not os.access(hp, os.X_OK):
@@ -75,7 +76,7 @@ def run_commit_hook(name, index):
7576
env['GIT_INDEX_FILE'] = safe_decode(index.path) if PY3 else safe_encode(index.path)
7677
env['GIT_EDITOR'] = ':'
7778
try:
78-
cmd = subprocess.Popen(hp,
79+
cmd = subprocess.Popen([hp] + list(args),
7980
env=env,
8081
stdout=subprocess.PIPE,
8182
stderr=subprocess.PIPE,
@@ -93,7 +94,7 @@ def run_commit_hook(name, index):
9394
if cmd.returncode != 0:
9495
stdout = force_text(stdout, defenc)
9596
stderr = force_text(stderr, defenc)
96-
raise HookExecutionError(hp, cmd.returncode, stdout, stderr)
97+
raise HookExecutionError(hp, cmd.returncode, stderr, stdout)
9798
# end handle return code
9899

99100

‎git/test/test_index.py

+85-29
Original file line numberDiff line numberDiff line change
@@ -729,35 +729,6 @@ def make_paths():
729729
assert fkey not in index.entries
730730

731731
index.add(files, write=True)
732-
if is_win:
733-
hp = hook_path('pre-commit', index.repo.git_dir)
734-
hpd = osp.dirname(hp)
735-
if not osp.isdir(hpd):
736-
os.mkdir(hpd)
737-
with open(hp, "wt") as fp:
738-
fp.write("#!/usr/bin/env sh\necho stdout; echo stderr 1>&2; exit 1")
739-
# end
740-
os.chmod(hp, 0o744)
741-
try:
742-
index.commit("This should fail")
743-
except HookExecutionError as err:
744-
if is_win:
745-
self.assertIsInstance(err.status, OSError)
746-
self.assertEqual(err.command, [hp])
747-
self.assertEqual(err.stdout, '')
748-
self.assertEqual(err.stderr, '')
749-
assert str(err)
750-
else:
751-
self.assertEqual(err.status, 1)
752-
self.assertEqual(err.command, hp)
753-
self.assertEqual(err.stdout, 'stdout\n')
754-
self.assertEqual(err.stderr, 'stderr\n')
755-
assert str(err)
756-
else:
757-
raise AssertionError("Should have cought a HookExecutionError")
758-
# end exception handling
759-
os.remove(hp)
760-
# end hook testing
761732
nc = index.commit("2 files committed", head=False)
762733

763734
for fkey in keys:
@@ -859,3 +830,88 @@ def test_add_a_file_with_wildcard_chars(self, rw_dir):
859830
r = Repo.init(rw_dir)
860831
r.index.add([fp])
861832
r.index.commit('Added [.exe')
833+
834+
@with_rw_repo('HEAD', bare=True)
835+
def test_pre_commit_hook_success(self, rw_repo):
836+
index = rw_repo.index
837+
hp = hook_path('pre-commit', index.repo.git_dir)
838+
hpd = osp.dirname(hp)
839+
if not osp.isdir(hpd):
840+
os.mkdir(hpd)
841+
with open(hp, "wt") as fp:
842+
fp.write("#!/usr/bin/env sh\nexit 0")
843+
os.chmod(hp, 0o744)
844+
index.commit("This should not fail")
845+
846+
@with_rw_repo('HEAD', bare=True)
847+
def test_pre_commit_hook_fail(self, rw_repo):
848+
index = rw_repo.index
849+
hp = hook_path('pre-commit', index.repo.git_dir)
850+
hpd = osp.dirname(hp)
851+
if not osp.isdir(hpd):
852+
os.mkdir(hpd)
853+
with open(hp, "wt") as fp:
854+
fp.write("#!/usr/bin/env sh\necho stdout; echo stderr 1>&2; exit 1")
855+
os.chmod(hp, 0o744)
856+
try:
857+
index.commit("This should fail")
858+
except HookExecutionError as err:
859+
if is_win:
860+
self.assertIsInstance(err.status, OSError)
861+
self.assertEqual(err.command, [hp])
862+
self.assertEqual(err.stdout, '')
863+
self.assertEqual(err.stderr, '')
864+
assert str(err)
865+
else:
866+
self.assertEqual(err.status, 1)
867+
self.assertEqual(err.command, [hp])
868+
self.assertEqual(err.stdout, "\n stdout: 'stdout\n'")
869+
self.assertEqual(err.stderr, "\n stderr: 'stderr\n'")
870+
assert str(err)
871+
else:
872+
raise AssertionError("Should have cought a HookExecutionError")
873+
874+
@with_rw_repo('HEAD', bare=True)
875+
def test_commit_msg_hook_success(self, rw_repo):
876+
index = rw_repo.index
877+
commit_message = u"commit default head by Frèderic Çaufl€"
878+
from_hook_message = u"from commit-msg"
879+
880+
hp = hook_path('commit-msg', index.repo.git_dir)
881+
hpd = osp.dirname(hp)
882+
if not osp.isdir(hpd):
883+
os.mkdir(hpd)
884+
with open(hp, "wt") as fp:
885+
fp.write('#!/usr/bin/env sh\necho -n " {}" >> "$1"'.format(from_hook_message))
886+
os.chmod(hp, 0o744)
887+
888+
new_commit = index.commit(commit_message)
889+
self.assertEqual(new_commit.message, u"{} {}".format(commit_message, from_hook_message))
890+
891+
@with_rw_repo('HEAD', bare=True)
892+
def test_commit_msg_hook_fail(self, rw_repo):
893+
index = rw_repo.index
894+
hp = hook_path('commit-msg', index.repo.git_dir)
895+
hpd = osp.dirname(hp)
896+
if not osp.isdir(hpd):
897+
os.mkdir(hpd)
898+
with open(hp, "wt") as fp:
899+
fp.write("#!/usr/bin/env sh\necho stdout; echo stderr 1>&2; exit 1")
900+
os.chmod(hp, 0o744)
901+
try:
902+
index.commit("This should fail")
903+
except HookExecutionError as err:
904+
if is_win:
905+
self.assertIsInstance(err.status, OSError)
906+
self.assertEqual(err.command, [hp])
907+
self.assertEqual(err.stdout, '')
908+
self.assertEqual(err.stderr, '')
909+
assert str(err)
910+
else:
911+
self.assertEqual(err.status, 1)
912+
self.assertEqual(err.command, [hp])
913+
self.assertEqual(err.stdout, "\n stdout: 'stdout\n'")
914+
self.assertEqual(err.stderr, "\n stderr: 'stderr\n'")
915+
assert str(err)
916+
else:
917+
raise AssertionError("Should have cought a HookExecutionError")

0 commit comments

Comments
 (0)