c4c5c8063a
The canonical beads database name is issues.jsonl. Tens of thousands of users have issues.jsonl, and beads.jsonl was only used by the Beads project itself due to git history pollution. Changes: - Updated bd doctor to warn about beads.jsonl instead of issues.jsonl - Changed default config from beads.jsonl to issues.jsonl - Reversed precedence in checkGitForIssues to prefer issues.jsonl - Updated git merge driver config to use issues.jsonl - Updated all tests to expect issues.jsonl as the default issues.jsonl is now the canonical default; beads.jsonl is legacy 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
221 lines
5.5 KiB
Go
221 lines
5.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/steveyegge/beads/internal/storage/sqlite"
|
|
"github.com/steveyegge/beads/internal/types"
|
|
)
|
|
|
|
// setupTestStore creates a test storage with issue_prefix configured
|
|
func setupTestStore(t *testing.T, dbPath string) *sqlite.SQLiteStorage {
|
|
t.Helper()
|
|
|
|
store, err := sqlite.New(context.Background(), dbPath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create store: %v", err)
|
|
}
|
|
|
|
ctx := context.Background()
|
|
if err := store.SetConfig(ctx, "issue_prefix", "bd"); err != nil {
|
|
store.Close()
|
|
t.Fatalf("Failed to set issue_prefix: %v", err)
|
|
}
|
|
|
|
return store
|
|
}
|
|
|
|
// TestDBNeedsExport_InSync verifies dbNeedsExport returns false when DB and JSONL are in sync
|
|
func TestDBNeedsExport_InSync(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
dbPath := filepath.Join(tmpDir, "beads.db")
|
|
jsonlPath := filepath.Join(tmpDir, "issues.jsonl")
|
|
|
|
store := setupTestStore(t, dbPath)
|
|
defer store.Close()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create an issue in DB
|
|
issue := &types.Issue{
|
|
Title: "Test Issue",
|
|
Status: types.StatusOpen,
|
|
Priority: 1,
|
|
IssueType: types.TypeBug,
|
|
}
|
|
err := store.CreateIssue(ctx, issue, "test-user")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create issue: %v", err)
|
|
}
|
|
|
|
// Export to JSONL
|
|
if err := exportToJSONLWithStore(ctx, store, jsonlPath); err != nil {
|
|
t.Fatalf("Failed to export: %v", err)
|
|
}
|
|
|
|
// Wait a moment to ensure DB mtime isn't newer
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
// Touch JSONL to make it newer than DB
|
|
now := time.Now()
|
|
if err := os.Chtimes(jsonlPath, now, now); err != nil {
|
|
t.Fatalf("Failed to touch JSONL: %v", err)
|
|
}
|
|
|
|
// DB and JSONL should be in sync
|
|
needsExport, err := dbNeedsExport(ctx, store, jsonlPath)
|
|
if err != nil {
|
|
t.Fatalf("dbNeedsExport failed: %v", err)
|
|
}
|
|
|
|
if needsExport {
|
|
t.Errorf("Expected needsExport=false (DB and JSONL in sync), got true")
|
|
}
|
|
}
|
|
|
|
// TestDBNeedsExport_DBNewer verifies dbNeedsExport returns true when DB is modified
|
|
func TestDBNeedsExport_DBNewer(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
dbPath := filepath.Join(tmpDir, "beads.db")
|
|
jsonlPath := filepath.Join(tmpDir, "issues.jsonl")
|
|
|
|
store := setupTestStore(t, dbPath)
|
|
defer store.Close()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create and export issue
|
|
issue1 := &types.Issue{
|
|
Title: "Test Issue",
|
|
Status: types.StatusOpen,
|
|
Priority: 1,
|
|
IssueType: types.TypeBug,
|
|
}
|
|
err := store.CreateIssue(ctx, issue1, "test-user")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create issue: %v", err)
|
|
}
|
|
|
|
if err := exportToJSONLWithStore(ctx, store, jsonlPath); err != nil {
|
|
t.Fatalf("Failed to export: %v", err)
|
|
}
|
|
|
|
// Wait and modify DB
|
|
time.Sleep(10 * time.Millisecond)
|
|
issue2 := &types.Issue{
|
|
Title: "Another Issue",
|
|
Status: types.StatusOpen,
|
|
Priority: 2,
|
|
IssueType: types.TypeTask,
|
|
}
|
|
err = store.CreateIssue(ctx, issue2, "test-user")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create second issue: %v", err)
|
|
}
|
|
|
|
// DB is newer, should need export
|
|
needsExport, err := dbNeedsExport(ctx, store, jsonlPath)
|
|
if err != nil {
|
|
t.Fatalf("dbNeedsExport failed: %v", err)
|
|
}
|
|
|
|
if !needsExport {
|
|
t.Errorf("Expected needsExport=true (DB modified), got false")
|
|
}
|
|
}
|
|
|
|
// TestDBNeedsExport_CountMismatch verifies dbNeedsExport returns true when counts differ
|
|
func TestDBNeedsExport_CountMismatch(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
dbPath := filepath.Join(tmpDir, "beads.db")
|
|
jsonlPath := filepath.Join(tmpDir, "issues.jsonl")
|
|
|
|
store := setupTestStore(t, dbPath)
|
|
defer store.Close()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create and export issue
|
|
issue1 := &types.Issue{
|
|
Title: "Test Issue",
|
|
Status: types.StatusOpen,
|
|
Priority: 1,
|
|
IssueType: types.TypeBug,
|
|
}
|
|
err := store.CreateIssue(ctx, issue1, "test-user")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create issue: %v", err)
|
|
}
|
|
|
|
if err := exportToJSONLWithStore(ctx, store, jsonlPath); err != nil {
|
|
t.Fatalf("Failed to export: %v", err)
|
|
}
|
|
|
|
// Add another issue to DB but don't export
|
|
issue2 := &types.Issue{
|
|
Title: "Another Issue",
|
|
Status: types.StatusOpen,
|
|
Priority: 2,
|
|
IssueType: types.TypeTask,
|
|
}
|
|
err = store.CreateIssue(ctx, issue2, "test-user")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create second issue: %v", err)
|
|
}
|
|
|
|
// Make JSONL appear newer (but counts differ)
|
|
time.Sleep(10 * time.Millisecond)
|
|
now := time.Now().Add(1 * time.Hour) // Way in the future
|
|
if err := os.Chtimes(jsonlPath, now, now); err != nil {
|
|
t.Fatalf("Failed to touch JSONL: %v", err)
|
|
}
|
|
|
|
// Counts mismatch, should need export
|
|
needsExport, err := dbNeedsExport(ctx, store, jsonlPath)
|
|
if err != nil {
|
|
t.Fatalf("dbNeedsExport failed: %v", err)
|
|
}
|
|
|
|
if !needsExport {
|
|
t.Errorf("Expected needsExport=true (count mismatch), got false")
|
|
}
|
|
}
|
|
|
|
// TestDBNeedsExport_NoJSONL verifies dbNeedsExport returns true when JSONL doesn't exist
|
|
func TestDBNeedsExport_NoJSONL(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
dbPath := filepath.Join(tmpDir, "beads.db")
|
|
jsonlPath := filepath.Join(tmpDir, "issues.jsonl")
|
|
|
|
store := setupTestStore(t, dbPath)
|
|
defer store.Close()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create issue but don't export
|
|
issue := &types.Issue{
|
|
Title: "Test Issue",
|
|
Status: types.StatusOpen,
|
|
Priority: 1,
|
|
IssueType: types.TypeBug,
|
|
}
|
|
err := store.CreateIssue(ctx, issue, "test-user")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create issue: %v", err)
|
|
}
|
|
|
|
// JSONL doesn't exist, should need export
|
|
needsExport, err := dbNeedsExport(ctx, store, jsonlPath)
|
|
if err != nil {
|
|
t.Fatalf("dbNeedsExport failed: %v", err)
|
|
}
|
|
|
|
if !needsExport {
|
|
t.Fatalf("Expected needsExport=true (JSONL missing), got false")
|
|
}
|
|
}
|