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:
dustin
2026-01-22 01:31:16 +07:00
committed by GitHub
parent 3afd1a1dcd
commit 4fbe00e224
2 changed files with 134 additions and 2 deletions

View File

@@ -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
}

View 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")
}
})
}