fix: Support both canonical and legacy JSONL filenames in merge driver check

The mergeDriverInstalled() function was only checking for the legacy
"beads.jsonl" filename, but installMergeDriver() writes the canonical
"issues.jsonl" filename. This caused false negatives where users with
the correct canonical configuration would be incorrectly flagged as
"not installed", potentially triggering unnecessary reinstalls.

Changes:
- Update mergeDriverInstalled() to check for both filenames
- Add test for canonical issues.jsonl filename detection
- Ensure existing correct configs are not unnecessarily overwritten

This fixes the inconsistency found during code review of bd-3sz0.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-11-23 20:07:15 -08:00
parent d9d0189e77
commit 035b006e25
2 changed files with 65 additions and 2 deletions

View File

@@ -776,9 +776,12 @@ func mergeDriverInstalled() bool {
return false
}
// Look for beads JSONL merge attribute
return strings.Contains(string(content), ".beads/beads.jsonl") &&
// Look for beads JSONL merge attribute (either canonical or legacy filename)
hasCanonical := strings.Contains(string(content), ".beads/issues.jsonl") &&
strings.Contains(string(content), "merge=beads")
hasLegacy := strings.Contains(string(content), ".beads/beads.jsonl") &&
strings.Contains(string(content), "merge=beads")
return hasCanonical || hasLegacy
}
// installMergeDriver configures git to use bd merge for JSONL files

View File

@@ -848,6 +848,66 @@ func TestInitMergeDriverAutoConfiguration(t *testing.T) {
t.Errorf("Merge driver should not contain invalid %%L or %%R placeholders, got %q", driver)
}
})
t.Run("detect canonical issues.jsonl filename in gitattributes", func(t *testing.T) {
// Reset global state
origDBPath := dbPath
defer func() { dbPath = origDBPath }()
dbPath = ""
tmpDir := t.TempDir()
originalWd, err := os.Getwd()
if err != nil {
t.Fatalf("Failed to get working directory: %v", err)
}
defer os.Chdir(originalWd)
if err := os.Chdir(tmpDir); err != nil {
t.Fatalf("Failed to change to temp directory: %v", err)
}
// Initialize git repo
if err := runCommandInDir(tmpDir, "git", "init"); err != nil {
t.Fatalf("Failed to init git: %v", err)
}
// Pre-configure correct merge driver and canonical filename in .gitattributes
if err := runCommandInDir(tmpDir, "git", "config", "merge.beads.driver", "bd merge %A %O %A %B"); err != nil {
t.Fatalf("Failed to set git config: %v", err)
}
// Create .gitattributes with canonical filename (issues.jsonl, not beads.jsonl)
gitattrsPath := filepath.Join(tmpDir, ".gitattributes")
if err := os.WriteFile(gitattrsPath, []byte(".beads/issues.jsonl merge=beads\n"), 0644); err != nil {
t.Fatalf("Failed to create .gitattributes: %v", err)
}
// Run bd init - should detect existing correct config and NOT reinstall
rootCmd.SetArgs([]string{"init", "--prefix", "test", "--quiet"})
if err := rootCmd.Execute(); err != nil {
t.Fatalf("Init failed: %v", err)
}
// Verify merge driver is still correct (not reinstalled unnecessarily)
driver, err := runCommandInDirWithOutput(tmpDir, "git", "config", "merge.beads.driver")
if err != nil {
t.Fatalf("Failed to get merge.beads.driver: %v", err)
}
driver = strings.TrimSpace(driver)
expected := "bd merge %A %O %A %B"
if driver != expected {
t.Errorf("Expected merge driver to remain %q, got %q", expected, driver)
}
// Verify .gitattributes still has canonical filename (not overwritten)
content, err := os.ReadFile(gitattrsPath)
if err != nil {
t.Fatalf("Failed to read .gitattributes: %v", err)
}
if !strings.Contains(string(content), ".beads/issues.jsonl merge=beads") {
t.Errorf(".gitattributes should still contain canonical filename pattern")
}
})
}
// TestReadFirstIssueFromJSONL_ValidFile verifies reading first issue from valid JSONL