test_hooks.py 5.6 KB

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