Skip to content

Commit bca5940

Browse files
wesmclaude
andcommitted
Fix Windows path detection in GetHooksPath and add tests
- Use filepath.IsAbs() instead of Unix-only "/" prefix check - Add test coverage for GetHooksPath with default, absolute, and relative core.hooksPath configurations Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 663f80b commit bca5940

File tree

2 files changed

+99
-1
lines changed

2 files changed

+99
-1
lines changed

internal/git/git.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ func GetHooksPath(repoPath string) (string, error) {
230230
hooksPath := strings.TrimSpace(string(out))
231231

232232
// If the path is relative, make it absolute relative to repoPath
233-
if !strings.HasPrefix(hooksPath, "/") {
233+
if !filepath.IsAbs(hooksPath) {
234234
hooksPath = filepath.Join(repoPath, hooksPath)
235235
}
236236

internal/git/git_test.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package git
2+
3+
import (
4+
"os"
5+
"os/exec"
6+
"path/filepath"
7+
"strings"
8+
"testing"
9+
)
10+
11+
func TestGetHooksPath(t *testing.T) {
12+
// Create a temp git repo
13+
tmpDir := t.TempDir()
14+
15+
cmd := exec.Command("git", "init")
16+
cmd.Dir = tmpDir
17+
if out, err := cmd.CombinedOutput(); err != nil {
18+
t.Fatalf("git init failed: %v\n%s", err, out)
19+
}
20+
21+
t.Run("default hooks path", func(t *testing.T) {
22+
hooksPath, err := GetHooksPath(tmpDir)
23+
if err != nil {
24+
t.Fatalf("GetHooksPath failed: %v", err)
25+
}
26+
27+
// Should be absolute
28+
if !filepath.IsAbs(hooksPath) {
29+
t.Errorf("hooks path should be absolute, got: %s", hooksPath)
30+
}
31+
32+
// Should end with .git/hooks (or .git\hooks on Windows)
33+
expectedSuffix := filepath.Join(".git", "hooks")
34+
if !strings.HasSuffix(hooksPath, expectedSuffix) {
35+
t.Errorf("hooks path should end with %s, got: %s", expectedSuffix, hooksPath)
36+
}
37+
38+
// Should be under tmpDir
39+
if !strings.HasPrefix(hooksPath, tmpDir) {
40+
t.Errorf("hooks path should be under %s, got: %s", tmpDir, hooksPath)
41+
}
42+
})
43+
44+
t.Run("custom core.hooksPath absolute", func(t *testing.T) {
45+
// Create a custom hooks directory
46+
customHooksDir := filepath.Join(tmpDir, "my-hooks")
47+
if err := os.MkdirAll(customHooksDir, 0755); err != nil {
48+
t.Fatal(err)
49+
}
50+
51+
// Set core.hooksPath to absolute path
52+
cmd := exec.Command("git", "config", "core.hooksPath", customHooksDir)
53+
cmd.Dir = tmpDir
54+
if out, err := cmd.CombinedOutput(); err != nil {
55+
t.Fatalf("git config failed: %v\n%s", err, out)
56+
}
57+
58+
hooksPath, err := GetHooksPath(tmpDir)
59+
if err != nil {
60+
t.Fatalf("GetHooksPath failed: %v", err)
61+
}
62+
63+
// Should return the custom absolute path
64+
if hooksPath != customHooksDir {
65+
t.Errorf("expected %s, got %s", customHooksDir, hooksPath)
66+
}
67+
68+
// Reset for other tests
69+
cmd = exec.Command("git", "config", "--unset", "core.hooksPath")
70+
cmd.Dir = tmpDir
71+
cmd.Run() // ignore error if not set
72+
})
73+
74+
t.Run("custom core.hooksPath relative", func(t *testing.T) {
75+
// Set core.hooksPath to relative path
76+
cmd := exec.Command("git", "config", "core.hooksPath", "custom-hooks")
77+
cmd.Dir = tmpDir
78+
if out, err := cmd.CombinedOutput(); err != nil {
79+
t.Fatalf("git config failed: %v\n%s", err, out)
80+
}
81+
82+
hooksPath, err := GetHooksPath(tmpDir)
83+
if err != nil {
84+
t.Fatalf("GetHooksPath failed: %v", err)
85+
}
86+
87+
// Should be made absolute
88+
if !filepath.IsAbs(hooksPath) {
89+
t.Errorf("hooks path should be absolute, got: %s", hooksPath)
90+
}
91+
92+
// Should resolve to tmpDir/custom-hooks
93+
expected := filepath.Join(tmpDir, "custom-hooks")
94+
if hooksPath != expected {
95+
t.Errorf("expected %s, got %s", expected, hooksPath)
96+
}
97+
})
98+
}

0 commit comments

Comments
 (0)