@@ -14,6 +14,8 @@ import (
1414 "github.com/entireio/cli/cmd/entire/cli/paths"
1515)
1616
17+ const goosWindows = "windows"
18+
1719// readEntireDevScript returns the contents of the committed scripts/entire-dev
1820// launcher, located relative to this test file's position in the source tree.
1921func readEntireDevScript (t * testing.T ) string {
@@ -328,7 +330,7 @@ func TestInstallGitHook_HooksPathNotADirectory(t *testing.T) {
328330 }
329331
330332 hooksPath := "/dev/null"
331- if runtime .GOOS == "windows" {
333+ if runtime .GOOS == goosWindows {
332334 hooksPath = filepath .Join (tmpDir , "not-a-dir" )
333335 if err := os .WriteFile (hooksPath , []byte ("x" ), 0o600 ); err != nil {
334336 t .Fatalf ("failed to create non-directory hooks path: %v" , err )
@@ -360,6 +362,80 @@ func TestInstallGitHook_HooksPathNotADirectory(t *testing.T) {
360362 }
361363}
362364
365+ func TestInstallGitHook_HooksPathUnderNonDirectory (t * testing.T ) {
366+ // core.hooksPath pointing below a non-directory (e.g. /dev/null/hooks)
367+ // makes os.Stat fail with ENOTDIR instead of succeeding on a non-dir;
368+ // the guidance must fire for this variant too.
369+ if runtime .GOOS == goosWindows {
370+ t .Skip ("ENOTDIR detection is POSIX-specific; Windows falls back to the raw mkdir error" )
371+ }
372+ tmpDir := t .TempDir ()
373+ ctx := context .Background ()
374+
375+ cmd := exec .CommandContext (ctx , "git" , "init" )
376+ cmd .Dir = tmpDir
377+ if err := cmd .Run (); err != nil {
378+ t .Fatalf ("failed to init git repo: %v" , err )
379+ }
380+ cmd = exec .CommandContext (ctx , "git" , "config" , "core.hooksPath" , "/dev/null/hooks" )
381+ cmd .Dir = tmpDir
382+ if err := cmd .Run (); err != nil {
383+ t .Fatalf ("failed to set core.hooksPath: %v" , err )
384+ }
385+
386+ t .Chdir (tmpDir )
387+ ClearHooksDirCache ()
388+ paths .ClearWorktreeRootCache ()
389+
390+ _ , err := InstallGitHook (ctx , true , false , false )
391+ if err == nil {
392+ t .Fatal ("InstallGitHook() should fail when hooks path is under a non-directory" )
393+ }
394+ if ! strings .Contains (err .Error (), "core.hooksPath" ) {
395+ t .Errorf ("error should name core.hooksPath, got: %s" , err )
396+ }
397+ }
398+
399+ func TestInstallGitHook_HooksPathNonexistentIsCreated (t * testing.T ) {
400+ // A configured-but-missing core.hooksPath is legitimate: the guard must
401+ // not fire, and MkdirAll must create the directory and install hooks.
402+ tmpDir := t .TempDir ()
403+ ctx := context .Background ()
404+
405+ cmd := exec .CommandContext (ctx , "git" , "init" )
406+ cmd .Dir = tmpDir
407+ if err := cmd .Run (); err != nil {
408+ t .Fatalf ("failed to init git repo: %v" , err )
409+ }
410+ hooksPath := filepath .Join (tmpDir , "githooks-not-yet-created" )
411+ cmd = exec .CommandContext (ctx , "git" , "config" , "core.hooksPath" , hooksPath )
412+ cmd .Dir = tmpDir
413+ if err := cmd .Run (); err != nil {
414+ t .Fatalf ("failed to set core.hooksPath: %v" , err )
415+ }
416+
417+ t .Chdir (tmpDir )
418+ ClearHooksDirCache ()
419+ paths .ClearWorktreeRootCache ()
420+
421+ count , err := InstallGitHook (ctx , true , false , false )
422+ if err != nil {
423+ t .Fatalf ("InstallGitHook() should create a nonexistent hooks path: %v" , err )
424+ }
425+ if count == 0 {
426+ t .Fatal ("InstallGitHook() should install hooks into the created directory" )
427+ }
428+ for _ , hook := range gitHookNames {
429+ data , readErr := os .ReadFile (filepath .Join (hooksPath , hook ))
430+ if readErr != nil {
431+ t .Fatalf ("expected hook %s in created hooks dir: %v" , hook , readErr )
432+ }
433+ if ! strings .Contains (string (data ), entireHookMarker ) {
434+ t .Errorf ("hook %s should contain Entire marker" , hook )
435+ }
436+ }
437+ }
438+
363439func TestInstallGitHook_WorktreeInstallsInCommonHooks (t * testing.T ) {
364440 mainRepo , worktreeDir := initHooksWorktreeRepo (t )
365441 t .Chdir (worktreeDir )
@@ -1776,7 +1852,7 @@ func TestResolveHookExePath(t *testing.T) {
17761852 t .Parallel ()
17771853 got , err := resolveHookExePath (exe , func (string ) (string , error ) {
17781854 return "" , junctionErr
1779- }, "windows" )
1855+ }, goosWindows )
17801856 if err != nil {
17811857 t .Fatalf ("windows should fall back, got error: %v" , err )
17821858 }
0 commit comments