diff --git a/cmd/entire/cli/strategy/hooks.go b/cmd/entire/cli/strategy/hooks.go index 4f9fc2d38..c05dc55db 100644 --- a/cmd/entire/cli/strategy/hooks.go +++ b/cmd/entire/cli/strategy/hooks.go @@ -344,25 +344,25 @@ fi // hookCmdPrefix returns the command prefix for hook scripts and warning messages. // Returns "go run ./cmd/entire/main.go" when local_dev is enabled. -// When absolutePath is true, resolves the full binary path via os.Executable() -// and returns an error if resolution fails. This is needed for GUI git clients -// (Xcode, Tower, etc.) that don't source shell profiles. -func hookCmdPrefix(localDev, absolutePath bool) (string, error) { +// By default, resolves the full binary path via os.Executable() so that hooks +// work in GUI git clients (Xcode, Tower, etc.) that don't source shell profiles. +// Falls back to bare "entire" only if binary path resolution fails. +func hookCmdPrefix(localDev, _ bool) (string, error) { if localDev { return "go run ./cmd/entire/main.go", nil } - if absolutePath { - exe, err := os.Executable() - if err != nil { - return "", fmt.Errorf("--absolute-git-hook-path: failed to resolve binary path: %w", err) - } - resolved, err := filepath.EvalSymlinks(exe) - if err != nil { - return "", fmt.Errorf("--absolute-git-hook-path: failed to resolve symlinks for %s: %w", exe, err) - } - return shellQuote(resolved), nil + // Always resolve the absolute path so hooks work in environments + // that don't source shell profiles (GUI git clients, IDEs, cron). + exe, err := os.Executable() + if err != nil { + // Fall back to bare command name if resolution fails + return "entire", nil //nolint:nilerr // Graceful fallback to PATH-based lookup + } + resolved, err := filepath.EvalSymlinks(exe) + if err != nil { + return "entire", nil //nolint:nilerr // Graceful fallback to PATH-based lookup } - return "entire", nil + return shellQuote(resolved), nil } // shellQuote wraps a string in single quotes for safe use in #!/bin/sh scripts. diff --git a/cmd/entire/cli/strategy/hooks_test.go b/cmd/entire/cli/strategy/hooks_test.go index 4fa7c0e0c..2d9dbfc23 100644 --- a/cmd/entire/cli/strategy/hooks_test.go +++ b/cmd/entire/cli/strategy/hooks_test.go @@ -599,7 +599,7 @@ func TestInstallGitHook_LocalDevCommandPrefix(t *testing.T) { } } - // Reinstall with localDev=false — hooks should update to use "entire" prefix + // Reinstall with localDev=false - hooks should update to use absolute path count, err = InstallGitHook(context.Background(), true, false, false) if err != nil { t.Fatalf("InstallGitHook(localDev=false) error = %v", err) @@ -617,22 +617,23 @@ func TestInstallGitHook_LocalDevCommandPrefix(t *testing.T) { if strings.Contains(content, "go run") { t.Errorf("hook %s should not use 'go run' prefix when localDev=false, got:\n%s", hook, content) } - if !strings.Contains(content, "\nentire ") { - t.Errorf("hook %s should use bare 'entire' prefix when localDev=false", hook) + // Should contain an absolute path (resolved via os.Executable), not bare "entire" + if !strings.Contains(content, "/") { + t.Errorf("hook %s should use absolute path when localDev=false, got:\n%s", hook, content) } } } -func TestInstallGitHook_AbsoluteGitHookPath(t *testing.T) { +func TestInstallGitHook_AbsolutePathByDefault(t *testing.T) { _, hooksDir := initHooksTestRepo(t) - // Install with absolutePath=true - count, err := InstallGitHook(context.Background(), true, false, true) + // Install with default settings (localDev=false) - should use absolute path + count, err := InstallGitHook(context.Background(), true, false, false) if err != nil { - t.Fatalf("InstallGitHook(absolutePath=true) error = %v", err) + t.Fatalf("InstallGitHook() error = %v", err) } if count == 0 { - t.Fatal("InstallGitHook(absolutePath=true) should install hooks") + t.Fatal("InstallGitHook() should install hooks") } // Get the expected absolute path (shell-quoted) @@ -656,7 +657,7 @@ func TestInstallGitHook_AbsoluteGitHookPath(t *testing.T) { t.Errorf("hook %s should contain shell-quoted absolute path %q, got:\n%s", hook, quoted, content) } if strings.Contains(content, "\nentire ") { - t.Errorf("hook %s should not use bare 'entire' prefix when absolutePath=true", hook) + t.Errorf("hook %s should not use bare 'entire' prefix", hook) } } }