Files
beads/internal/git/jujutsu_test.go
beads/crew/lizzy 2fe15e2328 feat(hooks): add jujutsu (jj) version control support
Add detection and hook support for jujutsu repositories:

- IsJujutsuRepo(): detects .jj directory
- IsColocatedJJGit(): detects colocated jj+git repos
- GetJujutsuRoot(): finds jj repo root

For colocated repos (jj git init --colocate):
- Install simplified hooks without staging (jj auto-commits working copy)
- Worktree handling preserved for git worktrees in colocated repos

For pure jj repos (no git):
- Print alias instructions since jj doesn't have native hooks yet

Closes: hq-ew1mbr.12

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 19:13:02 -08:00

188 lines
4.4 KiB
Go

package git
import (
"os"
"path/filepath"
"testing"
)
func TestIsJujutsuRepo(t *testing.T) {
// Save original directory
origDir, err := os.Getwd()
if err != nil {
t.Fatalf("Failed to get current directory: %v", err)
}
defer func() {
_ = os.Chdir(origDir)
ResetCaches()
}()
t.Run("not a jj repo", func(t *testing.T) {
tmpDir := t.TempDir()
if err := os.Chdir(tmpDir); err != nil {
t.Fatalf("Failed to chdir: %v", err)
}
ResetCaches()
if IsJujutsuRepo() {
t.Error("Expected IsJujutsuRepo() to return false for non-jj directory")
}
})
t.Run("jj repo root", func(t *testing.T) {
tmpDir := t.TempDir()
jjDir := filepath.Join(tmpDir, ".jj")
if err := os.Mkdir(jjDir, 0750); err != nil {
t.Fatalf("Failed to create .jj directory: %v", err)
}
if err := os.Chdir(tmpDir); err != nil {
t.Fatalf("Failed to chdir: %v", err)
}
ResetCaches()
if !IsJujutsuRepo() {
t.Error("Expected IsJujutsuRepo() to return true for jj repo root")
}
})
t.Run("jj repo subdirectory", func(t *testing.T) {
tmpDir := t.TempDir()
jjDir := filepath.Join(tmpDir, ".jj")
if err := os.Mkdir(jjDir, 0750); err != nil {
t.Fatalf("Failed to create .jj directory: %v", err)
}
subDir := filepath.Join(tmpDir, "src", "lib")
if err := os.MkdirAll(subDir, 0750); err != nil {
t.Fatalf("Failed to create subdirectory: %v", err)
}
if err := os.Chdir(subDir); err != nil {
t.Fatalf("Failed to chdir: %v", err)
}
ResetCaches()
if !IsJujutsuRepo() {
t.Error("Expected IsJujutsuRepo() to return true for jj repo subdirectory")
}
})
}
func TestIsColocatedJJGit(t *testing.T) {
// Save original directory
origDir, err := os.Getwd()
if err != nil {
t.Fatalf("Failed to get current directory: %v", err)
}
defer func() {
_ = os.Chdir(origDir)
ResetCaches()
}()
t.Run("jj only (not colocated)", func(t *testing.T) {
tmpDir := t.TempDir()
jjDir := filepath.Join(tmpDir, ".jj")
if err := os.Mkdir(jjDir, 0750); err != nil {
t.Fatalf("Failed to create .jj directory: %v", err)
}
if err := os.Chdir(tmpDir); err != nil {
t.Fatalf("Failed to chdir: %v", err)
}
ResetCaches()
if IsColocatedJJGit() {
t.Error("Expected IsColocatedJJGit() to return false for jj-only repo")
}
})
t.Run("not a repo", func(t *testing.T) {
tmpDir := t.TempDir()
if err := os.Chdir(tmpDir); err != nil {
t.Fatalf("Failed to chdir: %v", err)
}
ResetCaches()
if IsColocatedJJGit() {
t.Error("Expected IsColocatedJJGit() to return false for non-repo")
}
})
}
func TestGetJujutsuRoot(t *testing.T) {
// Save original directory
origDir, err := os.Getwd()
if err != nil {
t.Fatalf("Failed to get current directory: %v", err)
}
defer func() {
_ = os.Chdir(origDir)
ResetCaches()
}()
t.Run("not a jj repo", func(t *testing.T) {
tmpDir := t.TempDir()
if err := os.Chdir(tmpDir); err != nil {
t.Fatalf("Failed to chdir: %v", err)
}
ResetCaches()
_, err := GetJujutsuRoot()
if err == nil {
t.Error("Expected GetJujutsuRoot() to return error for non-jj directory")
}
})
t.Run("jj repo root", func(t *testing.T) {
tmpDir := t.TempDir()
// Resolve symlinks for comparison (macOS /var -> /private/var)
tmpDir, _ = filepath.EvalSymlinks(tmpDir)
jjDir := filepath.Join(tmpDir, ".jj")
if err := os.Mkdir(jjDir, 0750); err != nil {
t.Fatalf("Failed to create .jj directory: %v", err)
}
if err := os.Chdir(tmpDir); err != nil {
t.Fatalf("Failed to chdir: %v", err)
}
ResetCaches()
root, err := GetJujutsuRoot()
if err != nil {
t.Fatalf("GetJujutsuRoot() returned error: %v", err)
}
if root != tmpDir {
t.Errorf("Expected root %q, got %q", tmpDir, root)
}
})
t.Run("jj repo subdirectory", func(t *testing.T) {
tmpDir := t.TempDir()
// Resolve symlinks for comparison (macOS /var -> /private/var)
tmpDir, _ = filepath.EvalSymlinks(tmpDir)
jjDir := filepath.Join(tmpDir, ".jj")
if err := os.Mkdir(jjDir, 0750); err != nil {
t.Fatalf("Failed to create .jj directory: %v", err)
}
subDir := filepath.Join(tmpDir, "src", "lib")
if err := os.MkdirAll(subDir, 0750); err != nil {
t.Fatalf("Failed to create subdirectory: %v", err)
}
if err := os.Chdir(subDir); err != nil {
t.Fatalf("Failed to chdir: %v", err)
}
ResetCaches()
root, err := GetJujutsuRoot()
if err != nil {
t.Fatalf("GetJujutsuRoot() returned error: %v", err)
}
if root != tmpDir {
t.Errorf("Expected root %q, got %q", tmpDir, root)
}
})
}