@@ -1099,9 +1099,35 @@ class Mocked:
10991099 def test_run_commit_hook (self , rw_repo ):
11001100 index = rw_repo .index
11011101 _make_hook (index .repo .git_dir , "fake-hook" , "echo 'ran fake hook' >output.txt" )
1102- run_commit_hook ("fake-hook" , index )
1103- output = Path (rw_repo .git_dir , "output.txt" ).read_text (encoding = "utf-8" )
1104- self .assertEqual (output , "ran fake hook\n " )
1102+ output = Path (rw_repo .git_dir , "output.txt" )
1103+ with mock .patch .object (Repo , "config_level" , ("repository" ,)):
1104+ with mock .patch .object (Git , "execute" , side_effect = AssertionError ("hook lookup must not run git" )):
1105+ run_commit_hook ("fake-hook" , index )
1106+ self .assertEqual (output .read_text (encoding = "utf-8" ), "ran fake hook\n " )
1107+
1108+ output .unlink ()
1109+ with index .repo .config_writer () as writer :
1110+ writer .set_value ("core" , "hooksPath" , "" )
1111+ run_commit_hook ("fake-hook" , index )
1112+
1113+ self .assertEqual (output .read_text (encoding = "utf-8" ), "ran fake hook\n " )
1114+
1115+ @with_rw_directory
1116+ def test_run_commit_hook_outside_worktree_on_windows (self , rw_dir ):
1117+ root = Path (rw_dir ).resolve ()
1118+ repo = Repo .init (root / "repo" )
1119+ hooks_dir = root / "hooks"
1120+ _make_hook (root , "fake-hook" , "exit 0" )
1121+ with repo .config_writer () as writer :
1122+ writer .set_value ("core" , "hooksPath" , str (hooks_dir ))
1123+
1124+ with mock .patch ("git.index.fun.sys.platform" , "win32" ):
1125+ with mock .patch ("git.index.fun.safer_popen" ) as popen , mock .patch ("git.index.fun.handle_process_output" ):
1126+ popen .return_value .returncode = 0
1127+ run_commit_hook ("fake-hook" , repo .index )
1128+
1129+ command = popen .call_args [0 ][0 ]
1130+ self .assertEqual (command , ["bash.exe" , "../hooks/fake-hook" ])
11051131
11061132 @ddt .data ((False ,), (True ,))
11071133 @with_rw_directory
@@ -1160,6 +1186,32 @@ def test_pre_commit_hook_success(self, rw_repo):
11601186 _make_hook (index .repo .git_dir , "pre-commit" , "exit 0" )
11611187 index .commit ("This should not fail" )
11621188
1189+ @pytest .mark .xfail (
1190+ type (_win_bash_status ) is WinBashStatus .Absent ,
1191+ reason = "Can't run a hook on Windows without bash.exe." ,
1192+ raises = HookExecutionError ,
1193+ )
1194+ @pytest .mark .xfail (
1195+ type (_win_bash_status ) is WinBashStatus .WslNoDistro ,
1196+ reason = "Currently uses the bash.exe of WSL, even with no WSL distro installed" ,
1197+ raises = HookExecutionError ,
1198+ )
1199+ @with_rw_repo ("HEAD" )
1200+ def test_pre_commit_hook_respects_core_hooks_path (self , rw_repo ):
1201+ index = rw_repo .index
1202+ hooks_dir = Path (index .repo .working_dir , "custom-hooks" )
1203+ hooks_dir .mkdir ()
1204+ hp = hooks_dir / "pre-commit"
1205+ hp .write_text (HOOKS_SHEBANG + "echo 'ran custom hook' >custom-hook-output.txt" , encoding = "utf-8" )
1206+ os .chmod (hp , 0o744 )
1207+
1208+ with index .repo .config_writer () as writer :
1209+ writer .set_value ("core" , "hooksPath" , "custom-hooks" )
1210+
1211+ index .commit ("This should run the custom hook" )
1212+ output = Path (rw_repo .working_dir , "custom-hook-output.txt" ).read_text (encoding = "utf-8" )
1213+ self .assertEqual (output , "ran custom hook\n " )
1214+
11631215 @pytest .mark .xfail (
11641216 type (_win_bash_status ) is WinBashStatus .WslNoDistro ,
11651217 reason = "Currently uses the bash.exe of WSL, even with no WSL distro installed" ,
0 commit comments