test_hooks.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. # test_hooks.py -- Tests for executing hooks
  2. #
  3. # Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
  4. # General Public License as public by the Free Software Foundation; version 2.0
  5. # or (at your option) any later version. You can redistribute it and/or
  6. # modify it under the terms of either of these two licenses.
  7. #
  8. # Unless required by applicable law or agreed to in writing, software
  9. # distributed under the License is distributed on an "AS IS" BASIS,
  10. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. # See the License for the specific language governing permissions and
  12. # limitations under the License.
  13. #
  14. # You should have received a copy of the licenses; if not, see
  15. # <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
  16. # and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
  17. # License, Version 2.0.
  18. #
  19. """Tests for executing hooks."""
  20. import os
  21. import shutil
  22. import stat
  23. import sys
  24. import tempfile
  25. from dulwich import errors
  26. from dulwich.hooks import CommitMsgShellHook, PostCommitShellHook, PreCommitShellHook
  27. from . import TestCase
  28. class ShellHookTests(TestCase):
  29. def setUp(self):
  30. super().setUp()
  31. if os.name != "posix":
  32. self.skipTest("shell hook tests requires POSIX shell")
  33. self.assertTrue(os.path.exists("/bin/sh"))
  34. def test_hook_pre_commit(self):
  35. repo_dir = os.path.join(tempfile.mkdtemp())
  36. os.mkdir(os.path.join(repo_dir, "hooks"))
  37. self.addCleanup(shutil.rmtree, repo_dir)
  38. pre_commit_fail = """#!/bin/sh
  39. exit 1
  40. """
  41. pre_commit_success = """#!/bin/sh
  42. exit 0
  43. """
  44. pre_commit_cwd = (
  45. """#!/bin/sh
  46. if [ "$(pwd)" != '"""
  47. + repo_dir
  48. + """' ]; then
  49. echo "Expected path '"""
  50. + repo_dir
  51. + """', got '$(pwd)'"
  52. exit 1
  53. fi
  54. exit 0
  55. """
  56. )
  57. pre_commit = os.path.join(repo_dir, "hooks", "pre-commit")
  58. hook = PreCommitShellHook(repo_dir, repo_dir)
  59. with open(pre_commit, "w") as f:
  60. f.write(pre_commit_fail)
  61. os.chmod(pre_commit, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
  62. self.assertRaises(errors.HookError, hook.execute)
  63. if sys.platform != "darwin":
  64. # Don't bother running this test on darwin since path
  65. # canonicalization messages with our simple string comparison.
  66. with open(pre_commit, "w") as f:
  67. f.write(pre_commit_cwd)
  68. os.chmod(pre_commit, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
  69. hook.execute()
  70. with open(pre_commit, "w") as f:
  71. f.write(pre_commit_success)
  72. os.chmod(pre_commit, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
  73. hook.execute()
  74. def test_hook_commit_msg(self):
  75. repo_dir = os.path.join(tempfile.mkdtemp())
  76. os.mkdir(os.path.join(repo_dir, "hooks"))
  77. self.addCleanup(shutil.rmtree, repo_dir)
  78. commit_msg_fail = """#!/bin/sh
  79. exit 1
  80. """
  81. commit_msg_success = """#!/bin/sh
  82. exit 0
  83. """
  84. commit_msg_cwd = (
  85. """#!/bin/sh
  86. if [ "$(pwd)" = '"""
  87. + repo_dir
  88. + "' ]; then exit 0; else exit 1; fi\n"
  89. )
  90. commit_msg = os.path.join(repo_dir, "hooks", "commit-msg")
  91. hook = CommitMsgShellHook(repo_dir)
  92. with open(commit_msg, "w") as f:
  93. f.write(commit_msg_fail)
  94. os.chmod(commit_msg, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
  95. self.assertRaises(errors.HookError, hook.execute, b"failed commit")
  96. if sys.platform != "darwin":
  97. # Don't bother running this test on darwin since path
  98. # canonicalization messages with our simple string comparison.
  99. with open(commit_msg, "w") as f:
  100. f.write(commit_msg_cwd)
  101. os.chmod(commit_msg, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
  102. hook.execute(b"cwd test commit")
  103. with open(commit_msg, "w") as f:
  104. f.write(commit_msg_success)
  105. os.chmod(commit_msg, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
  106. hook.execute(b"empty commit")
  107. def test_hook_post_commit(self):
  108. (fd, path) = tempfile.mkstemp()
  109. os.close(fd)
  110. repo_dir = os.path.join(tempfile.mkdtemp())
  111. os.mkdir(os.path.join(repo_dir, "hooks"))
  112. self.addCleanup(shutil.rmtree, repo_dir)
  113. post_commit_success = (
  114. """#!/bin/sh
  115. rm """
  116. + path
  117. + "\n"
  118. )
  119. post_commit_fail = """#!/bin/sh
  120. exit 1
  121. """
  122. post_commit_cwd = (
  123. """#!/bin/sh
  124. if [ "$(pwd)" = '"""
  125. + repo_dir
  126. + "' ]; then exit 0; else exit 1; fi\n"
  127. )
  128. post_commit = os.path.join(repo_dir, "hooks", "post-commit")
  129. hook = PostCommitShellHook(repo_dir)
  130. with open(post_commit, "w") as f:
  131. f.write(post_commit_fail)
  132. os.chmod(post_commit, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
  133. self.assertRaises(errors.HookError, hook.execute)
  134. if sys.platform != "darwin":
  135. # Don't bother running this test on darwin since path
  136. # canonicalization messages with our simple string comparison.
  137. with open(post_commit, "w") as f:
  138. f.write(post_commit_cwd)
  139. os.chmod(post_commit, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
  140. hook.execute()
  141. with open(post_commit, "w") as f:
  142. f.write(post_commit_success)
  143. os.chmod(post_commit, stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC)
  144. hook.execute()
  145. self.assertFalse(os.path.exists(path))