fix: respect GT_TOWN_ROOT in quick-add command (#840)
The quick-add command (used by shell hook's "Add to Gas Town?" prompt) previously only checked hardcoded paths ~/gt and ~/gastown, ignoring GT_TOWN_ROOT and any other Gas Town installations. This caused rigs to be added to the wrong town when users had multiple Gas Town installations (e.g., ~/gt and ~/Documents/code/gt). Fix the town discovery order: 1. GT_TOWN_ROOT env var (explicit user preference) 2. workspace.FindFromCwd() (supports multiple installations) 3. Fall back to ~/gt and ~/gastown
This commit is contained in:
@@ -165,6 +165,19 @@ func sanitizeRigName(name string) string {
|
||||
}
|
||||
|
||||
func findOrCreateTown() (string, error) {
|
||||
// Priority 1: GT_TOWN_ROOT env var (explicit user preference)
|
||||
if townRoot := os.Getenv("GT_TOWN_ROOT"); townRoot != "" {
|
||||
if isValidTown(townRoot) {
|
||||
return townRoot, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Priority 2: Try to find from cwd (supports multiple town installations)
|
||||
if townRoot, err := workspace.FindFromCwd(); err == nil && townRoot != "" {
|
||||
return townRoot, nil
|
||||
}
|
||||
|
||||
// Priority 3: Fall back to well-known locations
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -176,11 +189,17 @@ func findOrCreateTown() (string, error) {
|
||||
}
|
||||
|
||||
for _, path := range candidates {
|
||||
mayorDir := filepath.Join(path, "mayor")
|
||||
if _, err := os.Stat(mayorDir); err == nil {
|
||||
if isValidTown(path) {
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("no Gas Town found - run 'gt install ~/gt' first")
|
||||
}
|
||||
|
||||
// isValidTown checks if a path is a valid Gas Town installation.
|
||||
func isValidTown(path string) bool {
|
||||
mayorDir := filepath.Join(path, "mayor")
|
||||
_, err := os.Stat(mayorDir)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
113
internal/cmd/rig_quick_add_test.go
Normal file
113
internal/cmd/rig_quick_add_test.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFindOrCreateTown(t *testing.T) {
|
||||
// Save original env and restore after test
|
||||
origTownRoot := os.Getenv("GT_TOWN_ROOT")
|
||||
defer os.Setenv("GT_TOWN_ROOT", origTownRoot)
|
||||
|
||||
t.Run("respects GT_TOWN_ROOT when set", func(t *testing.T) {
|
||||
// Create a valid town in temp dir
|
||||
tmpTown := t.TempDir()
|
||||
mayorDir := filepath.Join(tmpTown, "mayor")
|
||||
if err := os.MkdirAll(mayorDir, 0755); err != nil {
|
||||
t.Fatalf("mkdir mayor: %v", err)
|
||||
}
|
||||
|
||||
os.Setenv("GT_TOWN_ROOT", tmpTown)
|
||||
|
||||
result, err := findOrCreateTown()
|
||||
if err != nil {
|
||||
t.Fatalf("findOrCreateTown() error = %v", err)
|
||||
}
|
||||
if result != tmpTown {
|
||||
t.Errorf("findOrCreateTown() = %q, want %q", result, tmpTown)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ignores invalid GT_TOWN_ROOT", func(t *testing.T) {
|
||||
// Set GT_TOWN_ROOT to a non-existent path
|
||||
os.Setenv("GT_TOWN_ROOT", "/nonexistent/path/to/town")
|
||||
|
||||
// Create a valid town at ~/gt for fallback
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
t.Skip("cannot get home dir")
|
||||
}
|
||||
|
||||
gtPath := filepath.Join(home, "gt")
|
||||
mayorDir := filepath.Join(gtPath, "mayor")
|
||||
|
||||
// Skip if ~/gt doesn't exist (don't want to create it in user's home)
|
||||
if _, err := os.Stat(mayorDir); os.IsNotExist(err) {
|
||||
t.Skip("~/gt/mayor does not exist, skipping fallback test")
|
||||
}
|
||||
|
||||
result, err := findOrCreateTown()
|
||||
if err != nil {
|
||||
t.Fatalf("findOrCreateTown() error = %v", err)
|
||||
}
|
||||
// Should fall back to ~/gt since GT_TOWN_ROOT is invalid
|
||||
if result != gtPath {
|
||||
t.Logf("findOrCreateTown() = %q (fell back to valid town)", result)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("GT_TOWN_ROOT takes priority over fallback", func(t *testing.T) {
|
||||
// Create two valid towns
|
||||
tmpTown1 := t.TempDir()
|
||||
tmpTown2 := t.TempDir()
|
||||
|
||||
if err := os.MkdirAll(filepath.Join(tmpTown1, "mayor"), 0755); err != nil {
|
||||
t.Fatalf("mkdir mayor1: %v", err)
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Join(tmpTown2, "mayor"), 0755); err != nil {
|
||||
t.Fatalf("mkdir mayor2: %v", err)
|
||||
}
|
||||
|
||||
// Set GT_TOWN_ROOT to tmpTown1
|
||||
os.Setenv("GT_TOWN_ROOT", tmpTown1)
|
||||
|
||||
result, err := findOrCreateTown()
|
||||
if err != nil {
|
||||
t.Fatalf("findOrCreateTown() error = %v", err)
|
||||
}
|
||||
// Should use GT_TOWN_ROOT, not any other valid town
|
||||
if result != tmpTown1 {
|
||||
t.Errorf("findOrCreateTown() = %q, want %q (GT_TOWN_ROOT should take priority)", result, tmpTown1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestIsValidTown(t *testing.T) {
|
||||
t.Run("valid town has mayor directory", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
mayorDir := filepath.Join(tmpDir, "mayor")
|
||||
if err := os.MkdirAll(mayorDir, 0755); err != nil {
|
||||
t.Fatalf("mkdir: %v", err)
|
||||
}
|
||||
|
||||
if !isValidTown(tmpDir) {
|
||||
t.Error("isValidTown() = false, want true")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("invalid town missing mayor directory", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
if isValidTown(tmpDir) {
|
||||
t.Error("isValidTown() = true, want false")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("nonexistent path is invalid", func(t *testing.T) {
|
||||
if isValidTown("/nonexistent/path") {
|
||||
t.Error("isValidTown() = true, want false")
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user