Fix Windows test failures: path handling and bd binary references

- Fix TestFindDatabasePathEnvVar to expect canonicalized absolute paths
- Add getBDCommand() helper for platform-specific bd executable paths
- Update beads_hash_multiclone_test.go to use platform-specific bd paths
- Fix cleanupWALFiles linting error (removed unused error return)
This commit is contained in:
Steve Yegge
2025-11-02 09:49:39 -08:00
parent 361f46346e
commit 9f9b8bbdc2
4 changed files with 32 additions and 21 deletions

View File

@@ -103,7 +103,7 @@
{"id":"bd-7e7ddffa","content_hash":"3b0e0f6e769eb263cf342d64c40de3dc23995ef672d9142fd6f278dc3dee633a","title":"Repair Commands \u0026 AI-Assisted Tooling","description":"Add specialized repair tools to reduce agent repair burden:\n1. Git merge conflicts in JSONL\n2. Duplicate issues from parallel work\n3. Semantic inconsistencies\n4. Orphaned references\n\nSee ~/src/fred/beads/repair_commands.md for full design doc.\n\nReduces agent repair time from 5-10 minutes to \u003c30 seconds per repair.","status":"open","priority":1,"issue_type":"epic","created_at":"2025-10-28T19:30:17.465812-07:00","updated_at":"2025-10-30T17:12:58.179404-07:00"}
{"id":"bd-7e7ddffa.1","content_hash":"df6de1f6a58a995d979a7be59c2fb38800e81b96e8fa0bd39980f8bf9f1a4f37","title":"bd resolve-conflicts - Git merge conflict resolver","description":"Automatically resolve JSONL merge conflicts.\n\nModes:\n- Mechanical: ID remapping (no AI)\n- AI-assisted: Smart merge/keep decisions\n- Interactive: Review each conflict\n\nHandles \u003c\u003c\u003c\u003c\u003c\u003c\u003c conflict markers in .beads/beads.jsonl\n\nFiles: cmd/bd/resolve_conflicts.go (new)","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-28T14:48:30.083642-07:00","updated_at":"2025-10-30T17:12:58.220145-07:00","dependencies":[{"issue_id":"bd-7e7ddffa.1","depends_on_id":"bd-7e7ddffa","type":"parent-child","created_at":"2025-10-29T19:58:28.847736-07:00","created_by":"stevey"}]}
{"id":"bd-7eed","content_hash":"f491845894c23d141399b422109c45015fe725b2d5c27bd68484d2306fcf55dd","title":"Remove obsolete stale.go command (executor tables never implemented)","description":"","status":"closed","priority":2,"issue_type":"chore","created_at":"2025-10-31T21:27:05.555369-07:00","updated_at":"2025-10-31T21:27:11.427631-07:00","closed_at":"2025-10-31T21:27:11.427631-07:00"}
{"id":"bd-7fe8","content_hash":"a404fb9747111bc7091d24ebdcc0bb98ceda0c8833390f2e519fa17cb068f5ed","title":"Fix linting error in migrate.go","description":"Linter reports error:\n```\ncmd/bd/migrate.go:647:37: cleanupWALFiles - result 0 (error) is always nil (unparam)\n```\n\nThe `cleanupWALFiles` function always returns nil, so the error return type should be removed or the function should actually return errors when appropriate.","status":"open","priority":2,"issue_type":"chore","created_at":"2025-11-02T09:29:37.279747-08:00","updated_at":"2025-11-02T09:29:37.279747-08:00","dependencies":[{"issue_id":"bd-7fe8","depends_on_id":"bd-1231","type":"blocks","created_at":"2025-11-02T09:29:37.280881-08:00","created_by":"stevey"}]}
{"id":"bd-7fe8","content_hash":"a404fb9747111bc7091d24ebdcc0bb98ceda0c8833390f2e519fa17cb068f5ed","title":"Fix linting error in migrate.go","description":"Linter reports error:\n```\ncmd/bd/migrate.go:647:37: cleanupWALFiles - result 0 (error) is always nil (unparam)\n```\n\nThe `cleanupWALFiles` function always returns nil, so the error return type should be removed or the function should actually return errors when appropriate.","status":"closed","priority":2,"issue_type":"chore","created_at":"2025-11-02T09:29:37.279747-08:00","updated_at":"2025-11-02T09:46:52.18793-08:00","closed_at":"2025-11-02T09:46:52.18793-08:00","dependencies":[{"issue_id":"bd-7fe8","depends_on_id":"bd-1231","type":"blocks","created_at":"2025-11-02T09:29:37.280881-08:00","created_by":"stevey"}]}
{"id":"bd-81abb639","content_hash":"5af6696b1bbfc76056771aa71ac6f72aaadb72e3fb139c09eb7680b86c9053c8","title":"Investigate jujutsu VCS as potential solution for conflict-free merging","description":"## Context\nCurrent N-way collision resolution struggles with Git line-based merge model. When 5+ clones create issues with same ID, Git merge conflicts require manual resolution, and our collision resolver can fail during convergence rounds.\n\n## Research Question\nCould jujutsu (jj) provide better conflict handling for JSONL files?\n\n## Jujutsu Overview\n- Next-gen VCS built on libgit2\n- Designed to handle conflicts as first-class citizens\n- Supports conflict-free replicated data types (CRDTs) in some scenarios\n- Better handling of concurrent edits\n- Can work with Git repos (compatible with existing infrastructure)\n\n## Investigation Tasks\n1. JSONL Merge Behavior - How does jj handle line-by-line JSONL conflicts?\n2. Integration Feasibility - Can beads use jj as backend while maintaining Git compatibility?\n3. Conflict Resolution Model - Does jj conflict model map to our collision resolution?\n4. Operational Transform Support - Does jj implement operational transforms?\n\n## Deliverables\n1. Technical report on jj merge algorithm for JSONL\n2. Proof-of-concept: 5-clone collision test using jj instead of Git\n3. Performance comparison: Git vs jj for beads workload\n4. Recommendation: Adopt, experiment further, or abandon\n\n## References\n- https://github.com/martinvonz/jj\n- Related to bd-e6d71828, bd-7a2b58fc","status":"closed","priority":2,"issue_type":"task","created_at":"2025-10-29T20:02:47.953008-07:00","updated_at":"2025-10-30T17:12:58.19464-07:00","closed_at":"2025-10-29T20:47:52.910985-07:00"}
{"id":"bd-833559b3","content_hash":"9082c986207b9df7a7a4dc87a53007849e2b9f6e92f3bea41e22d6a14f1f6f42","title":"bd validate - Comprehensive health check","description":"Run all validation checks in one command.\n\nChecks:\n- Duplicates\n- Orphaned dependencies\n- Test pollution\n- Git conflicts\n\nSupports --fix-all for auto-repair.\n\nDepends on bd-cbed9619.1, bd-0dcea000, bd-2752a7a2, bd-9826b69a.\n\nFiles: cmd/bd/validate.go (new)","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-29T20:02:47.957692-07:00","updated_at":"2025-10-30T17:12:58.219095-07:00"}
{"id":"bd-83f0bb64","content_hash":"c7be091ee7e713dd9c8ec0f9a498a9ae12adb09f8b7510a5ec10a815a05322e1","title":"Platform tests: Linux, macOS, Windows","description":"Test event-driven mode on all platforms. Verify inotify (Linux), FSEvents (macOS), ReadDirectoryChangesW (Windows). Test fallback behavior on each.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-29T19:42:29.857419-07:00","updated_at":"2025-10-31T12:00:43.197445-07:00","closed_at":"2025-10-31T12:00:43.197445-07:00"}

View File

@@ -2,6 +2,7 @@ package beads_test
import (
"encoding/json"
"fmt"
"os"
"os/exec"
"path/filepath"
@@ -18,6 +19,14 @@ func getBDPath() string {
return "./bd"
}
// getBDCommand returns the platform-specific command to run bd from current dir
func getBDCommand() string {
if runtime.GOOS == "windows" {
return ".\\bd.exe"
}
return "./bd"
}
// TestHashIDs_MultiCloneConverge verifies that hash-based IDs work correctly
// across multiple clones creating different issues. With hash IDs, each unique
// issue gets a unique ID, so no collision resolution is needed.
@@ -152,16 +161,17 @@ func setupClone(t *testing.T, tmpDir, remoteDir, name, bdPath string) string {
t.Helper()
cloneDir := filepath.Join(tmpDir, "clone-"+strings.ToLower(name))
runCmd(t, tmpDir, "git", "clone", remoteDir, cloneDir)
copyFile(t, bdPath, filepath.Join(cloneDir, "bd"))
bdCmd := getBDCommand()
copyFile(t, bdPath, filepath.Join(cloneDir, filepath.Base(bdCmd)))
if name == "A" {
runCmd(t, cloneDir, "./bd", "init", "--quiet", "--prefix", "test")
runCmd(t, cloneDir, bdCmd, "init", "--quiet", "--prefix", "test")
runCmd(t, cloneDir, "git", "add", ".beads")
runCmd(t, cloneDir, "git", "commit", "-m", "Initialize beads")
runCmd(t, cloneDir, "git", "push", "origin", "master")
} else {
runCmd(t, cloneDir, "git", "pull", "origin", "master")
runCmd(t, cloneDir, "./bd", "init", "--quiet", "--prefix", "test")
runCmd(t, cloneDir, bdCmd, "init", "--quiet", "--prefix", "test")
}
installGitHooks(t, cloneDir)
@@ -170,7 +180,7 @@ func setupClone(t *testing.T, tmpDir, remoteDir, name, bdPath string) string {
func createIssueInClone(t *testing.T, cloneDir, title string) {
t.Helper()
runCmdWithEnv(t, cloneDir, map[string]string{"BEADS_NO_DAEMON": "1"}, "./bd", "create", title, "-t", "task", "-p", "1", "--json")
runCmdWithEnv(t, cloneDir, map[string]string{"BEADS_NO_DAEMON": "1"}, getBDCommand(), "create", title, "-t", "task", "-p", "1", "--json")
}
func getTitlesFromClone(t *testing.T, cloneDir string) map[string]bool {
@@ -178,7 +188,7 @@ func getTitlesFromClone(t *testing.T, cloneDir string) map[string]bool {
listJSON := runCmdOutputWithEnv(t, cloneDir, map[string]string{
"BEADS_NO_DAEMON": "1",
"BD_NO_AUTO_IMPORT": "1",
}, "./bd", "list", "--json")
}, getBDCommand(), "list", "--json")
jsonStart := strings.Index(listJSON, "[")
if jsonStart == -1 {
@@ -226,16 +236,17 @@ func resolveConflictMarkersIfPresent(t *testing.T, cloneDir string) {
func installGitHooks(t *testing.T, repoDir string) {
t.Helper()
hooksDir := filepath.Join(repoDir, ".git", "hooks")
bdCmd := getBDCommand()
preCommit := `#!/bin/sh
./bd --no-daemon export -o .beads/issues.jsonl >/dev/null 2>&1 || true
preCommit := fmt.Sprintf(`#!/bin/sh
%s --no-daemon export -o .beads/issues.jsonl >/dev/null 2>&1 || true
git add .beads/issues.jsonl >/dev/null 2>&1 || true
exit 0
`
postMerge := `#!/bin/sh
./bd --no-daemon import -i .beads/issues.jsonl >/dev/null 2>&1 || true
`, bdCmd)
postMerge := fmt.Sprintf(`#!/bin/sh
%s --no-daemon import -i .beads/issues.jsonl >/dev/null 2>&1 || true
exit 0
`
`, bdCmd)
os.WriteFile(filepath.Join(hooksDir, "pre-commit"), []byte(preCommit), 0755)
os.WriteFile(filepath.Join(hooksDir, "post-merge"), []byte(postMerge), 0755)
}

View File

@@ -17,13 +17,15 @@ func TestFindDatabasePathEnvVar(t *testing.T) {
}
}()
// Set env var to a test path
testPath := "/test/path/test.db"
// Set env var to a test path (platform-agnostic)
testPath := filepath.Join("test", "path", "test.db")
_ = os.Setenv("BEADS_DB", testPath)
result := FindDatabasePath()
if result != testPath {
t.Errorf("Expected '%s', got '%s'", testPath, result)
// FindDatabasePath canonicalizes to absolute path
expectedPath, _ := filepath.Abs(testPath)
if result != expectedPath {
t.Errorf("Expected '%s', got '%s'", expectedPath, result)
}
}

View File

@@ -227,7 +227,7 @@ This command:
}
// Clean up orphaned WAL files from old database
_ = cleanupWALFiles(oldDB.path)
cleanupWALFiles(oldDB.path)
// Update current DB reference
currentDB = oldDB
@@ -246,7 +246,7 @@ This command:
}
// Clean up WAL files before opening to avoid "disk I/O error"
_ = cleanupWALFiles(currentDB.path)
cleanupWALFiles(currentDB.path)
store, err := sqlite.New(currentDB.path)
if err != nil {
@@ -644,15 +644,13 @@ func loadOrCreateConfig(beadsDir string) (*configfile.Config, error) {
}
// cleanupWALFiles removes orphaned WAL and SHM files for a given database path
func cleanupWALFiles(dbPath string) error {
func cleanupWALFiles(dbPath string) {
walPath := dbPath + "-wal"
shmPath := dbPath + "-shm"
// Best effort - don't fail if these don't exist
_ = os.Remove(walPath)
_ = os.Remove(shmPath)
return nil
}
func init() {