diff --git a/cmd/bd/nodb.go b/cmd/bd/nodb.go index 5ba47368..012ac5d4 100644 --- a/cmd/bd/nodb.go +++ b/cmd/bd/nodb.go @@ -72,8 +72,11 @@ func initializeNoDbMode() error { debug.Logf("using prefix '%s'", prefix) - // Set global store + // Set global store and mark as active (fixes bd comment --no-db) + storeMutex.Lock() store = memStore + storeActive = true + storeMutex.Unlock() return nil } diff --git a/cmd/bd/nodb_test.go b/cmd/bd/nodb_test.go index 56be64e9..0063c58e 100644 --- a/cmd/bd/nodb_test.go +++ b/cmd/bd/nodb_test.go @@ -158,6 +158,90 @@ func TestDetectPrefix(t *testing.T) { }) } +func TestInitializeNoDbMode_SetsStoreActive(t *testing.T) { + // This test verifies the fix for bd comment --no-db not working. + // The bug was that initializeNoDbMode() set `store` but not `storeActive`, + // so ensureStoreActive() would try to find a SQLite database. + + tempDir := t.TempDir() + beadsDir := filepath.Join(tempDir, ".beads") + if err := os.MkdirAll(beadsDir, 0o755); err != nil { + t.Fatalf("Failed to create .beads dir: %v", err) + } + + // Create a minimal JSONL file with one issue + jsonlPath := filepath.Join(beadsDir, "issues.jsonl") + content := `{"id":"bd-1","title":"Test Issue","status":"open"} +` + if err := os.WriteFile(jsonlPath, []byte(content), 0o600); err != nil { + t.Fatalf("Failed to write JSONL: %v", err) + } + + // Save and restore global state + oldStore := store + oldStoreActive := storeActive + oldCwd, _ := os.Getwd() + defer func() { + storeMutex.Lock() + store = oldStore + storeActive = oldStoreActive + storeMutex.Unlock() + _ = os.Chdir(oldCwd) + }() + + // Change to temp dir so initializeNoDbMode finds .beads + if err := os.Chdir(tempDir); err != nil { + t.Fatalf("Failed to chdir: %v", err) + } + + // Reset global state + storeMutex.Lock() + store = nil + storeActive = false + storeMutex.Unlock() + + // Initialize no-db mode + if err := initializeNoDbMode(); err != nil { + t.Fatalf("initializeNoDbMode failed: %v", err) + } + + // Verify storeActive is now true + storeMutex.Lock() + active := storeActive + s := store + storeMutex.Unlock() + + if !active { + t.Error("storeActive should be true after initializeNoDbMode") + } + if s == nil { + t.Fatal("store should not be nil after initializeNoDbMode") + } + + // ensureStoreActive should now return immediately without error + if err := ensureStoreActive(); err != nil { + t.Errorf("ensureStoreActive should succeed after initializeNoDbMode: %v", err) + } + + // Verify comments work (this was the failing case) + ctx := rootCtx + comment, err := s.AddIssueComment(ctx, "bd-1", "testuser", "Test comment") + if err != nil { + t.Fatalf("AddIssueComment failed: %v", err) + } + if comment.Text != "Test comment" { + t.Errorf("Expected 'Test comment', got %s", comment.Text) + } + + comments, err := s.GetIssueComments(ctx, "bd-1") + if err != nil { + t.Fatalf("GetIssueComments failed: %v", err) + } + if len(comments) != 1 { + t.Errorf("Expected 1 comment, got %d", len(comments)) + } +} + func TestWriteIssuesToJSONL(t *testing.T) { tempDir := t.TempDir() beadsDir := filepath.Join(tempDir, ".beads")