Optimize sync_test.go: eliminate redundant git init calls
- Add setupGitRepo(), setupGitRepoWithBranch(), and setupMinimalGitRepo() helpers - Refactor 19 test functions to use shared git repo setup - Reduces duplicate git initialization boilerplate by ~300 lines - All tests pass with improved maintainability Related to bd-ktng
This commit is contained in:
@@ -41,7 +41,7 @@
|
|||||||
{"id":"bd-hdt","content_hash":"8e6cf1653ef2ea583b39a421b3d708763ab7c042d6cd494e77202a92af0a7398","title":"Implement auto-merge functionality in duplicates command","description":"The duplicates.go file has a TODO at line 95 to implement the performMerge function for automatic duplicate merging. Currently it just prints a warning message. This would automate the merge process instead of just suggesting commands.","status":"open","priority":2,"issue_type":"feature","created_at":"2025-11-21T18:55:02.828619-05:00","updated_at":"2025-11-21T18:55:02.828619-05:00","source_repo":"."}
|
{"id":"bd-hdt","content_hash":"8e6cf1653ef2ea583b39a421b3d708763ab7c042d6cd494e77202a92af0a7398","title":"Implement auto-merge functionality in duplicates command","description":"The duplicates.go file has a TODO at line 95 to implement the performMerge function for automatic duplicate merging. Currently it just prints a warning message. This would automate the merge process instead of just suggesting commands.","status":"open","priority":2,"issue_type":"feature","created_at":"2025-11-21T18:55:02.828619-05:00","updated_at":"2025-11-21T18:55:02.828619-05:00","source_repo":"."}
|
||||||
{"id":"bd-j3zt","content_hash":"531ad51101f41375a93d66b8d22105ce7c4913261db78b662bb759e802bc01e2","title":"Fix mypy errors in beads-mcp","description":"Running `mypy .` in `integrations/beads-mcp` reports 287 errors. These should be addressed to improve type safety and code quality.","status":"open","priority":3,"issue_type":"task","created_at":"2025-11-20T18:53:28.557708-05:00","updated_at":"2025-11-20T18:53:28.557708-05:00","source_repo":"."}
|
{"id":"bd-j3zt","content_hash":"531ad51101f41375a93d66b8d22105ce7c4913261db78b662bb759e802bc01e2","title":"Fix mypy errors in beads-mcp","description":"Running `mypy .` in `integrations/beads-mcp` reports 287 errors. These should be addressed to improve type safety and code quality.","status":"open","priority":3,"issue_type":"task","created_at":"2025-11-20T18:53:28.557708-05:00","updated_at":"2025-11-20T18:53:28.557708-05:00","source_repo":"."}
|
||||||
{"id":"bd-koab","content_hash":"1b5e9a3a60f61472698af52ab6b2cbe46c839660900e7da3b562d9c3d5c608f6","title":"Import should continue on FOREIGN KEY constraint violations from deletions","description":"# Problem\n\nWhen importing JSONL after a merge that includes deletions, we may encounter FOREIGN KEY constraint violations if:\n- Issue A was deleted in one branch\n- Issue B (that depends on A) was modified in another branch \n- The merge keeps the deletion of A and the modification of B\n- Import tries to import B with a dependency/reference to deleted A\n\nCurrently import fails completely on such constraint violations, requiring manual intervention.\n\n# Solution\n\nAdd IsForeignKeyConstraintError() helper similar to IsUniqueConstraintError()\n\nUpdate import code to:\n1. Detect FOREIGN KEY constraint violations\n2. Log a warning with the issue ID and constraint\n3. Continue importing remaining issues\n4. Report summary of skipped issues at the end\n\n# Implementation Notes\n\n- Add to internal/storage/sqlite/util.go\n- Pattern: strings.Contains(err.Error(), \"FOREIGN KEY constraint failed\")\n- Update importer to handle these errors gracefully\n- Keep track of skipped issues for summary reporting","notes":"## Progress\n\nAdded IsForeignKeyConstraintError() helper function:\n- Located in internal/storage/sqlite/util.go \n- Detects both uppercase and lowercase variants\n- Full test coverage added to util_test.go\n- Tests pass ✓\n\n## Next Steps\n\nWhen FK constraint error is reproduced:\n1. Update importer.go to use IsForeignKeyConstraintError()\n2. Log warning with issue ID and constraint details\n3. Track skipped issues in Result struct\n4. Continue import instead of failing\n5. Report skipped issues in summary\n\nThe helper is ready to use when you encounter the actual constraint violation.","status":"open","priority":2,"issue_type":"feature","created_at":"2025-11-23T21:37:02.811665-08:00","updated_at":"2025-11-23T21:37:50.739917-08:00","source_repo":"."}
|
{"id":"bd-koab","content_hash":"1b5e9a3a60f61472698af52ab6b2cbe46c839660900e7da3b562d9c3d5c608f6","title":"Import should continue on FOREIGN KEY constraint violations from deletions","description":"# Problem\n\nWhen importing JSONL after a merge that includes deletions, we may encounter FOREIGN KEY constraint violations if:\n- Issue A was deleted in one branch\n- Issue B (that depends on A) was modified in another branch \n- The merge keeps the deletion of A and the modification of B\n- Import tries to import B with a dependency/reference to deleted A\n\nCurrently import fails completely on such constraint violations, requiring manual intervention.\n\n# Solution\n\nAdd IsForeignKeyConstraintError() helper similar to IsUniqueConstraintError()\n\nUpdate import code to:\n1. Detect FOREIGN KEY constraint violations\n2. Log a warning with the issue ID and constraint\n3. Continue importing remaining issues\n4. Report summary of skipped issues at the end\n\n# Implementation Notes\n\n- Add to internal/storage/sqlite/util.go\n- Pattern: strings.Contains(err.Error(), \"FOREIGN KEY constraint failed\")\n- Update importer to handle these errors gracefully\n- Keep track of skipped issues for summary reporting","notes":"## Progress\n\nAdded IsForeignKeyConstraintError() helper function:\n- Located in internal/storage/sqlite/util.go \n- Detects both uppercase and lowercase variants\n- Full test coverage added to util_test.go\n- Tests pass ✓\n\n## Next Steps\n\nWhen FK constraint error is reproduced:\n1. Update importer.go to use IsForeignKeyConstraintError()\n2. Log warning with issue ID and constraint details\n3. Track skipped issues in Result struct\n4. Continue import instead of failing\n5. Report skipped issues in summary\n\nThe helper is ready to use when you encounter the actual constraint violation.","status":"open","priority":2,"issue_type":"feature","created_at":"2025-11-23T21:37:02.811665-08:00","updated_at":"2025-11-23T21:37:50.739917-08:00","source_repo":"."}
|
||||||
{"id":"bd-ktng","content_hash":"0a09f3e1549a70817f23aa57444811aaf18683ff9336944ff6e8c277ac5684b4","title":"Optimize CLI test suite - eliminate redundant git init calls","description":"Current: Each of 13 CLI tests calls git init (31s total). Solution: Use single test binary built once in init(), skip git operations where possible, or use mock filesystem.","status":"open","priority":2,"issue_type":"task","created_at":"2025-11-04T11:23:13.660276-08:00","updated_at":"2025-11-04T11:23:13.660276-08:00","source_repo":"."}
|
{"id":"bd-ktng","content_hash":"b303c08fd8c8f4d34bc245e3dfa7898e232a63e7c8d635da1d89f3ccd206cba4","title":"Optimize CLI test suite - eliminate redundant git init calls","description":"Current: Each of 13 CLI tests calls git init (31s total). Solution: Use single test binary built once in init(), skip git operations where possible, or use mock filesystem.","status":"in_progress","priority":2,"issue_type":"task","created_at":"2025-11-04T11:23:13.660276-08:00","updated_at":"2025-11-23T22:45:34.031792-08:00","source_repo":"."}
|
||||||
{"id":"bd-l954","content_hash":"263dd2111cf0353b307f2e47489aa42ecf607e49b1316b54a6497cad9d3722b0","title":"Performance Testing Framework","description":"Add comprehensive performance testing for beads focusing on optimization guidance and validating 10K+ database scale. Uses standard Go tooling, follows existing patterns, minimal complexity.\n\nComponents:\n- Benchmark suite for critical operations at 10K-20K scale\n- Fixture generator for realistic test data (epic hierarchies, cross-links)\n- User diagnostics via bd doctor --perf\n- Always-on profiling integration\n\nGoals:\n- Identify bottlenecks for optimization work\n- Validate performance at 10K+ issue scale\n- Enable users to collect diagnostics for bug reports\n- Support both SQLite and JSONL import paths","status":"open","priority":2,"issue_type":"epic","created_at":"2025-11-13T22:22:11.203467-08:00","updated_at":"2025-11-13T22:22:11.203467-08:00","source_repo":"."}
|
{"id":"bd-l954","content_hash":"263dd2111cf0353b307f2e47489aa42ecf607e49b1316b54a6497cad9d3722b0","title":"Performance Testing Framework","description":"Add comprehensive performance testing for beads focusing on optimization guidance and validating 10K+ database scale. Uses standard Go tooling, follows existing patterns, minimal complexity.\n\nComponents:\n- Benchmark suite for critical operations at 10K-20K scale\n- Fixture generator for realistic test data (epic hierarchies, cross-links)\n- User diagnostics via bd doctor --perf\n- Always-on profiling integration\n\nGoals:\n- Identify bottlenecks for optimization work\n- Validate performance at 10K+ issue scale\n- Enable users to collect diagnostics for bug reports\n- Support both SQLite and JSONL import paths","status":"open","priority":2,"issue_type":"epic","created_at":"2025-11-13T22:22:11.203467-08:00","updated_at":"2025-11-13T22:22:11.203467-08:00","source_repo":"."}
|
||||||
{"id":"bd-m0w","content_hash":"e8641e225f1d4cf13fbd97c4a83046e3597df180d3ee134125e4a35abc6941cd","title":"Add test coverage for internal/validation package","description":"","design":"Validation package has 1 test file. Critical for data integrity. Target: 80% coverage","acceptance_criteria":"- At least 4 test files\n- Package coverage \u003e= 80%\n- Tests cover all validation rules","status":"open","priority":2,"issue_type":"task","created_at":"2025-11-20T21:21:24.129559-05:00","updated_at":"2025-11-20T21:21:24.129559-05:00","source_repo":".","dependencies":[{"issue_id":"bd-m0w","depends_on_id":"bd-ge7","type":"blocks","created_at":"2025-11-20T21:21:31.350477-05:00","created_by":"daemon"}]}
|
{"id":"bd-m0w","content_hash":"e8641e225f1d4cf13fbd97c4a83046e3597df180d3ee134125e4a35abc6941cd","title":"Add test coverage for internal/validation package","description":"","design":"Validation package has 1 test file. Critical for data integrity. Target: 80% coverage","acceptance_criteria":"- At least 4 test files\n- Package coverage \u003e= 80%\n- Tests cover all validation rules","status":"open","priority":2,"issue_type":"task","created_at":"2025-11-20T21:21:24.129559-05:00","updated_at":"2025-11-20T21:21:24.129559-05:00","source_repo":".","dependencies":[{"issue_id":"bd-m0w","depends_on_id":"bd-ge7","type":"blocks","created_at":"2025-11-20T21:21:31.350477-05:00","created_by":"daemon"}]}
|
||||||
{"id":"bd-m7ge","content_hash":"bb08f2bcbbdd2e392733d92bff2e46a51000337ac019d306dd6a2983916873c4","title":"Add .beads/README.md during 'bd init' for project documentation and promotion","description":"When 'bd init' is run, automatically generate a .beads/README.md file that:\n\n1. Briefly explains what Beads is (AI-native issue tracking that lives in your repo)\n2. Links to the main repository: https://github.com/steveyegge/beads\n3. Provides a quick reference of essential commands:\n - bd create: Create new issues\n - bd list: View all issues\n - bd update: Modify issue status/details\n - bd show: View issue details\n - bd sync: Sync with git remote\n4. Highlights key benefits for AI coding agents and developers\n5. Encourages developers to try it out\n\nThe README should be enthusiastic and compelling to get open source contributors excited about using Beads for their AI-assisted development workflows.","status":"open","priority":2,"issue_type":"feature","created_at":"2025-11-16T22:32:50.478681-08:00","updated_at":"2025-11-16T22:32:58.492868-08:00","source_repo":"."}
|
{"id":"bd-m7ge","content_hash":"bb08f2bcbbdd2e392733d92bff2e46a51000337ac019d306dd6a2983916873c4","title":"Add .beads/README.md during 'bd init' for project documentation and promotion","description":"When 'bd init' is run, automatically generate a .beads/README.md file that:\n\n1. Briefly explains what Beads is (AI-native issue tracking that lives in your repo)\n2. Links to the main repository: https://github.com/steveyegge/beads\n3. Provides a quick reference of essential commands:\n - bd create: Create new issues\n - bd list: View all issues\n - bd update: Modify issue status/details\n - bd show: View issue details\n - bd sync: Sync with git remote\n4. Highlights key benefits for AI coding agents and developers\n5. Encourages developers to try it out\n\nThe README should be enthusiastic and compelling to get open source contributors excited about using Beads for their AI-assisted development workflows.","status":"open","priority":2,"issue_type":"feature","created_at":"2025-11-16T22:32:50.478681-08:00","updated_at":"2025-11-16T22:32:58.492868-08:00","source_repo":"."}
|
||||||
|
|||||||
@@ -32,20 +32,8 @@ func TestIsGitRepo_NotInGitRepo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGitHasUpstream_NoUpstream(t *testing.T) {
|
func TestGitHasUpstream_NoUpstream(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
_, cleanup := setupGitRepo(t)
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a fresh git repo without upstream
|
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init").Run()
|
|
||||||
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
|
||||||
exec.Command("git", "config", "user.name", "Test User").Run()
|
|
||||||
|
|
||||||
// Create initial commit
|
|
||||||
os.WriteFile("test.txt", []byte("test"), 0644)
|
|
||||||
exec.Command("git", "add", "test.txt").Run()
|
|
||||||
exec.Command("git", "commit", "-m", "initial").Run()
|
|
||||||
|
|
||||||
// Should not have upstream
|
// Should not have upstream
|
||||||
if gitHasUpstream() {
|
if gitHasUpstream() {
|
||||||
@@ -55,23 +43,10 @@ func TestGitHasUpstream_NoUpstream(t *testing.T) {
|
|||||||
|
|
||||||
func TestGitHasChanges_NoFile(t *testing.T) {
|
func TestGitHasChanges_NoFile(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
tmpDir := t.TempDir()
|
_, cleanup := setupGitRepo(t)
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a git repo
|
// Check - should have no changes (test.txt was committed by setupGitRepo)
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init").Run()
|
|
||||||
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
|
||||||
exec.Command("git", "config", "user.name", "Test User").Run()
|
|
||||||
|
|
||||||
// Create and commit a file
|
|
||||||
testFile := filepath.Join(tmpDir, "test.txt")
|
|
||||||
os.WriteFile(testFile, []byte("original"), 0644)
|
|
||||||
exec.Command("git", "add", "test.txt").Run()
|
|
||||||
exec.Command("git", "commit", "-m", "initial").Run()
|
|
||||||
|
|
||||||
// Check - should have no changes
|
|
||||||
hasChanges, err := gitHasChanges(ctx, "test.txt")
|
hasChanges, err := gitHasChanges(ctx, "test.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("gitHasChanges() error = %v", err)
|
t.Fatalf("gitHasChanges() error = %v", err)
|
||||||
@@ -83,23 +58,11 @@ func TestGitHasChanges_NoFile(t *testing.T) {
|
|||||||
|
|
||||||
func TestGitHasChanges_ModifiedFile(t *testing.T) {
|
func TestGitHasChanges_ModifiedFile(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
tmpDir := t.TempDir()
|
tmpDir, cleanup := setupGitRepo(t)
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a git repo
|
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init").Run()
|
|
||||||
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
|
||||||
exec.Command("git", "config", "user.name", "Test User").Run()
|
|
||||||
|
|
||||||
// Create and commit a file
|
|
||||||
testFile := filepath.Join(tmpDir, "test.txt")
|
|
||||||
os.WriteFile(testFile, []byte("original"), 0644)
|
|
||||||
exec.Command("git", "add", "test.txt").Run()
|
|
||||||
exec.Command("git", "commit", "-m", "initial").Run()
|
|
||||||
|
|
||||||
// Modify the file
|
// Modify the file
|
||||||
|
testFile := filepath.Join(tmpDir, "test.txt")
|
||||||
os.WriteFile(testFile, []byte("modified"), 0644)
|
os.WriteFile(testFile, []byte("modified"), 0644)
|
||||||
|
|
||||||
// Check - should have changes
|
// Check - should have changes
|
||||||
@@ -113,20 +76,8 @@ func TestGitHasChanges_ModifiedFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGitHasUnmergedPaths_CleanRepo(t *testing.T) {
|
func TestGitHasUnmergedPaths_CleanRepo(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
_, cleanup := setupGitRepo(t)
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a git repo
|
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init").Run()
|
|
||||||
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
|
||||||
exec.Command("git", "config", "user.name", "Test User").Run()
|
|
||||||
|
|
||||||
// Create initial commit
|
|
||||||
os.WriteFile("test.txt", []byte("test"), 0644)
|
|
||||||
exec.Command("git", "add", "test.txt").Run()
|
|
||||||
exec.Command("git", "commit", "-m", "initial").Run()
|
|
||||||
|
|
||||||
// Should not have unmerged paths
|
// Should not have unmerged paths
|
||||||
hasUnmerged, err := gitHasUnmergedPaths()
|
hasUnmerged, err := gitHasUnmergedPaths()
|
||||||
@@ -140,23 +91,11 @@ func TestGitHasUnmergedPaths_CleanRepo(t *testing.T) {
|
|||||||
|
|
||||||
func TestGitCommit_Success(t *testing.T) {
|
func TestGitCommit_Success(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
tmpDir := t.TempDir()
|
_, cleanup := setupGitRepo(t)
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a git repo
|
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init").Run()
|
|
||||||
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
|
||||||
exec.Command("git", "config", "user.name", "Test User").Run()
|
|
||||||
|
|
||||||
// Create initial commit
|
|
||||||
os.WriteFile("initial.txt", []byte("initial"), 0644)
|
|
||||||
exec.Command("git", "add", "initial.txt").Run()
|
|
||||||
exec.Command("git", "commit", "-m", "initial").Run()
|
|
||||||
|
|
||||||
// Create a new file
|
// Create a new file
|
||||||
testFile := "test.txt"
|
testFile := "new.txt"
|
||||||
os.WriteFile(testFile, []byte("content"), 0644)
|
os.WriteFile(testFile, []byte("content"), 0644)
|
||||||
|
|
||||||
// Commit the file
|
// Commit the file
|
||||||
@@ -177,23 +116,11 @@ func TestGitCommit_Success(t *testing.T) {
|
|||||||
|
|
||||||
func TestGitCommit_AutoMessage(t *testing.T) {
|
func TestGitCommit_AutoMessage(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
tmpDir := t.TempDir()
|
_, cleanup := setupGitRepo(t)
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a git repo
|
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init").Run()
|
|
||||||
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
|
||||||
exec.Command("git", "config", "user.name", "Test User").Run()
|
|
||||||
|
|
||||||
// Create initial commit
|
|
||||||
os.WriteFile("initial.txt", []byte("initial"), 0644)
|
|
||||||
exec.Command("git", "add", "initial.txt").Run()
|
|
||||||
exec.Command("git", "commit", "-m", "initial").Run()
|
|
||||||
|
|
||||||
// Create a new file
|
// Create a new file
|
||||||
testFile := "test.txt"
|
testFile := "new.txt"
|
||||||
os.WriteFile(testFile, []byte("content"), 0644)
|
os.WriteFile(testFile, []byte("content"), 0644)
|
||||||
|
|
||||||
// Commit with auto-generated message (empty string)
|
// Commit with auto-generated message (empty string)
|
||||||
@@ -275,20 +202,8 @@ not valid json
|
|||||||
|
|
||||||
func TestGetCurrentBranch(t *testing.T) {
|
func TestGetCurrentBranch(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
tmpDir := t.TempDir()
|
_, cleanup := setupGitRepo(t)
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a git repo
|
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init").Run()
|
|
||||||
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
|
||||||
exec.Command("git", "config", "user.name", "Test User").Run()
|
|
||||||
|
|
||||||
// Create initial commit
|
|
||||||
os.WriteFile("test.txt", []byte("test"), 0644)
|
|
||||||
exec.Command("git", "add", "test.txt").Run()
|
|
||||||
exec.Command("git", "commit", "-m", "initial").Run()
|
|
||||||
|
|
||||||
// Get current branch
|
// Get current branch
|
||||||
branch, err := getCurrentBranch(ctx)
|
branch, err := getCurrentBranch(ctx)
|
||||||
@@ -304,20 +219,8 @@ func TestGetCurrentBranch(t *testing.T) {
|
|||||||
|
|
||||||
func TestMergeSyncBranch_NoSyncBranchConfigured(t *testing.T) {
|
func TestMergeSyncBranch_NoSyncBranchConfigured(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
tmpDir := t.TempDir()
|
_, cleanup := setupGitRepo(t)
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a git repo
|
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init").Run()
|
|
||||||
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
|
||||||
exec.Command("git", "config", "user.name", "Test User").Run()
|
|
||||||
|
|
||||||
// Create initial commit
|
|
||||||
os.WriteFile("test.txt", []byte("test"), 0644)
|
|
||||||
exec.Command("git", "add", "test.txt").Run()
|
|
||||||
exec.Command("git", "commit", "-m", "initial").Run()
|
|
||||||
|
|
||||||
// Try to merge without sync.branch configured (or database)
|
// Try to merge without sync.branch configured (or database)
|
||||||
err := mergeSyncBranch(ctx, false)
|
err := mergeSyncBranch(ctx, false)
|
||||||
@@ -332,20 +235,8 @@ func TestMergeSyncBranch_NoSyncBranchConfigured(t *testing.T) {
|
|||||||
|
|
||||||
func TestMergeSyncBranch_OnSyncBranch(t *testing.T) {
|
func TestMergeSyncBranch_OnSyncBranch(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
tmpDir := t.TempDir()
|
tmpDir, cleanup := setupGitRepo(t)
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a git repo
|
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init").Run()
|
|
||||||
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
|
||||||
exec.Command("git", "config", "user.name", "Test User").Run()
|
|
||||||
|
|
||||||
// Create initial commit on main
|
|
||||||
os.WriteFile("test.txt", []byte("test"), 0644)
|
|
||||||
exec.Command("git", "add", "test.txt").Run()
|
|
||||||
exec.Command("git", "commit", "-m", "initial").Run()
|
|
||||||
|
|
||||||
// Create sync branch
|
// Create sync branch
|
||||||
exec.Command("git", "checkout", "-b", "beads-metadata").Run()
|
exec.Command("git", "checkout", "-b", "beads-metadata").Run()
|
||||||
@@ -363,20 +254,8 @@ func TestMergeSyncBranch_OnSyncBranch(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMergeSyncBranch_DirtyWorkingTree(t *testing.T) {
|
func TestMergeSyncBranch_DirtyWorkingTree(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
_, cleanup := setupGitRepo(t)
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a git repo
|
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init").Run()
|
|
||||||
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
|
||||||
exec.Command("git", "config", "user.name", "Test User").Run()
|
|
||||||
|
|
||||||
// Create initial commit
|
|
||||||
os.WriteFile("test.txt", []byte("test"), 0644)
|
|
||||||
exec.Command("git", "add", "test.txt").Run()
|
|
||||||
exec.Command("git", "commit", "-m", "initial").Run()
|
|
||||||
|
|
||||||
// Create uncommitted changes
|
// Create uncommitted changes
|
||||||
os.WriteFile("test.txt", []byte("modified"), 0644)
|
os.WriteFile("test.txt", []byte("modified"), 0644)
|
||||||
@@ -443,20 +322,8 @@ func TestGetSyncBranch_EnvOverridesDB(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIsInRebase_NotInRebase(t *testing.T) {
|
func TestIsInRebase_NotInRebase(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
_, cleanup := setupGitRepo(t)
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a git repo
|
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init").Run()
|
|
||||||
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
|
||||||
exec.Command("git", "config", "user.name", "Test User").Run()
|
|
||||||
|
|
||||||
// Create initial commit
|
|
||||||
os.WriteFile("test.txt", []byte("test"), 0644)
|
|
||||||
exec.Command("git", "add", "test.txt").Run()
|
|
||||||
exec.Command("git", "commit", "-m", "initial").Run()
|
|
||||||
|
|
||||||
// Should not be in rebase
|
// Should not be in rebase
|
||||||
if isInRebase() {
|
if isInRebase() {
|
||||||
@@ -465,20 +332,8 @@ func TestIsInRebase_NotInRebase(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIsInRebase_InRebase(t *testing.T) {
|
func TestIsInRebase_InRebase(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir, cleanup := setupGitRepo(t)
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a git repo
|
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init").Run()
|
|
||||||
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
|
||||||
exec.Command("git", "config", "user.name", "Test User").Run()
|
|
||||||
|
|
||||||
// Create initial commit
|
|
||||||
os.WriteFile("test.txt", []byte("test"), 0644)
|
|
||||||
exec.Command("git", "add", "test.txt").Run()
|
|
||||||
exec.Command("git", "commit", "-m", "initial").Run()
|
|
||||||
|
|
||||||
// Simulate rebase by creating rebase-merge directory
|
// Simulate rebase by creating rebase-merge directory
|
||||||
os.MkdirAll(filepath.Join(tmpDir, ".git", "rebase-merge"), 0755)
|
os.MkdirAll(filepath.Join(tmpDir, ".git", "rebase-merge"), 0755)
|
||||||
@@ -490,13 +345,8 @@ func TestIsInRebase_InRebase(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIsInRebase_InRebaseApply(t *testing.T) {
|
func TestIsInRebase_InRebaseApply(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir, cleanup := setupMinimalGitRepo(t)
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a git repo
|
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init").Run()
|
|
||||||
|
|
||||||
// Simulate non-interactive rebase by creating rebase-apply directory
|
// Simulate non-interactive rebase by creating rebase-apply directory
|
||||||
os.MkdirAll(filepath.Join(tmpDir, ".git", "rebase-apply"), 0755)
|
os.MkdirAll(filepath.Join(tmpDir, ".git", "rebase-apply"), 0755)
|
||||||
@@ -508,20 +358,8 @@ func TestIsInRebase_InRebaseApply(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestHasJSONLConflict_NoConflict(t *testing.T) {
|
func TestHasJSONLConflict_NoConflict(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
_, cleanup := setupGitRepo(t)
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a git repo
|
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init").Run()
|
|
||||||
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
|
||||||
exec.Command("git", "config", "user.name", "Test User").Run()
|
|
||||||
|
|
||||||
// Create initial commit
|
|
||||||
os.WriteFile("test.txt", []byte("test"), 0644)
|
|
||||||
exec.Command("git", "add", "test.txt").Run()
|
|
||||||
exec.Command("git", "commit", "-m", "initial").Run()
|
|
||||||
|
|
||||||
// Should not have JSONL conflict
|
// Should not have JSONL conflict
|
||||||
if hasJSONLConflict() {
|
if hasJSONLConflict() {
|
||||||
@@ -530,22 +368,15 @@ func TestHasJSONLConflict_NoConflict(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestHasJSONLConflict_OnlyJSONLConflict(t *testing.T) {
|
func TestHasJSONLConflict_OnlyJSONLConflict(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir, cleanup := setupGitRepoWithBranch(t, "main")
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a git repo
|
// Create initial commit with beads.jsonl
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init", "-b", "main").Run()
|
|
||||||
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
|
||||||
exec.Command("git", "config", "user.name", "Test User").Run()
|
|
||||||
|
|
||||||
// Create initial commit
|
|
||||||
beadsDir := filepath.Join(tmpDir, ".beads")
|
beadsDir := filepath.Join(tmpDir, ".beads")
|
||||||
os.MkdirAll(beadsDir, 0755)
|
os.MkdirAll(beadsDir, 0755)
|
||||||
os.WriteFile(filepath.Join(beadsDir, "beads.jsonl"), []byte(`{"id":"bd-1","title":"original"}`), 0644)
|
os.WriteFile(filepath.Join(beadsDir, "beads.jsonl"), []byte(`{"id":"bd-1","title":"original"}`), 0644)
|
||||||
exec.Command("git", "add", ".").Run()
|
exec.Command("git", "add", ".").Run()
|
||||||
exec.Command("git", "commit", "-m", "initial").Run()
|
exec.Command("git", "commit", "-m", "add beads.jsonl").Run()
|
||||||
|
|
||||||
// Create a second commit on main (modify same issue)
|
// Create a second commit on main (modify same issue)
|
||||||
os.WriteFile(filepath.Join(beadsDir, "beads.jsonl"), []byte(`{"id":"bd-1","title":"main-version"}`), 0644)
|
os.WriteFile(filepath.Join(beadsDir, "beads.jsonl"), []byte(`{"id":"bd-1","title":"main-version"}`), 0644)
|
||||||
@@ -568,15 +399,8 @@ func TestHasJSONLConflict_OnlyJSONLConflict(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestHasJSONLConflict_MultipleConflicts(t *testing.T) {
|
func TestHasJSONLConflict_MultipleConflicts(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir, cleanup := setupGitRepoWithBranch(t, "main")
|
||||||
originalWd, _ := os.Getwd()
|
defer cleanup()
|
||||||
defer os.Chdir(originalWd)
|
|
||||||
|
|
||||||
// Create a git repo
|
|
||||||
os.Chdir(tmpDir)
|
|
||||||
exec.Command("git", "init", "-b", "main").Run()
|
|
||||||
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
|
||||||
exec.Command("git", "config", "user.name", "Test User").Run()
|
|
||||||
|
|
||||||
// Create initial commit with beads.jsonl and another file
|
// Create initial commit with beads.jsonl and another file
|
||||||
beadsDir := filepath.Join(tmpDir, ".beads")
|
beadsDir := filepath.Join(tmpDir, ".beads")
|
||||||
@@ -584,7 +408,7 @@ func TestHasJSONLConflict_MultipleConflicts(t *testing.T) {
|
|||||||
os.WriteFile(filepath.Join(beadsDir, "beads.jsonl"), []byte(`{"id":"bd-1","title":"original"}`), 0644)
|
os.WriteFile(filepath.Join(beadsDir, "beads.jsonl"), []byte(`{"id":"bd-1","title":"original"}`), 0644)
|
||||||
os.WriteFile("other.txt", []byte("line1\nline2\nline3"), 0644)
|
os.WriteFile("other.txt", []byte("line1\nline2\nline3"), 0644)
|
||||||
exec.Command("git", "add", ".").Run()
|
exec.Command("git", "add", ".").Run()
|
||||||
exec.Command("git", "commit", "-m", "initial").Run()
|
exec.Command("git", "commit", "-m", "add initial files").Run()
|
||||||
|
|
||||||
// Create a second commit on main (modify both files)
|
// Create a second commit on main (modify both files)
|
||||||
os.WriteFile(filepath.Join(beadsDir, "beads.jsonl"), []byte(`{"id":"bd-1","title":"main-version"}`), 0644)
|
os.WriteFile(filepath.Join(beadsDir, "beads.jsonl"), []byte(`{"id":"bd-1","title":"main-version"}`), 0644)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -18,3 +20,122 @@ func waitFor(t *testing.T, timeout, poll time.Duration, pred func() bool) {
|
|||||||
}
|
}
|
||||||
t.Fatalf("condition not met within %v", timeout)
|
t.Fatalf("condition not met within %v", timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setupGitRepo creates a temporary git repository and returns its path and cleanup function.
|
||||||
|
// The repo is initialized with git config and an initial commit.
|
||||||
|
// The current directory is changed to the new repo.
|
||||||
|
func setupGitRepo(t *testing.T) (repoPath string, cleanup func()) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
originalWd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to get working directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Chdir(tmpDir); err != nil {
|
||||||
|
t.Fatalf("failed to change to temp directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize git repo
|
||||||
|
if err := exec.Command("git", "init").Run(); err != nil {
|
||||||
|
os.Chdir(originalWd)
|
||||||
|
t.Fatalf("failed to init git repo: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure git
|
||||||
|
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
||||||
|
exec.Command("git", "config", "user.name", "Test User").Run()
|
||||||
|
|
||||||
|
// Create initial commit
|
||||||
|
if err := os.WriteFile("test.txt", []byte("test"), 0644); err != nil {
|
||||||
|
os.Chdir(originalWd)
|
||||||
|
t.Fatalf("failed to write test file: %v", err)
|
||||||
|
}
|
||||||
|
exec.Command("git", "add", "test.txt").Run()
|
||||||
|
if err := exec.Command("git", "commit", "-m", "initial").Run(); err != nil {
|
||||||
|
os.Chdir(originalWd)
|
||||||
|
t.Fatalf("failed to create initial commit: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup = func() {
|
||||||
|
os.Chdir(originalWd)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmpDir, cleanup
|
||||||
|
}
|
||||||
|
|
||||||
|
// setupGitRepoWithBranch creates a git repo and checks out a specific branch.
|
||||||
|
// Use this when tests need a specific branch name (e.g., "main").
|
||||||
|
func setupGitRepoWithBranch(t *testing.T, branch string) (repoPath string, cleanup func()) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
originalWd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to get working directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Chdir(tmpDir); err != nil {
|
||||||
|
t.Fatalf("failed to change to temp directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize git repo with specific branch
|
||||||
|
if err := exec.Command("git", "init", "-b", branch).Run(); err != nil {
|
||||||
|
os.Chdir(originalWd)
|
||||||
|
t.Fatalf("failed to init git repo: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure git
|
||||||
|
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
||||||
|
exec.Command("git", "config", "user.name", "Test User").Run()
|
||||||
|
|
||||||
|
// Create initial commit
|
||||||
|
if err := os.WriteFile("test.txt", []byte("test"), 0644); err != nil {
|
||||||
|
os.Chdir(originalWd)
|
||||||
|
t.Fatalf("failed to write test file: %v", err)
|
||||||
|
}
|
||||||
|
exec.Command("git", "add", "test.txt").Run()
|
||||||
|
if err := exec.Command("git", "commit", "-m", "initial").Run(); err != nil {
|
||||||
|
os.Chdir(originalWd)
|
||||||
|
t.Fatalf("failed to create initial commit: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup = func() {
|
||||||
|
os.Chdir(originalWd)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmpDir, cleanup
|
||||||
|
}
|
||||||
|
|
||||||
|
// setupMinimalGitRepo creates a git repo without an initial commit.
|
||||||
|
// Use this when tests need to control the initial state more precisely.
|
||||||
|
func setupMinimalGitRepo(t *testing.T) (repoPath string, cleanup func()) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
originalWd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to get working directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Chdir(tmpDir); err != nil {
|
||||||
|
t.Fatalf("failed to change to temp directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize git repo
|
||||||
|
if err := exec.Command("git", "init").Run(); err != nil {
|
||||||
|
os.Chdir(originalWd)
|
||||||
|
t.Fatalf("failed to init git repo: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure git
|
||||||
|
exec.Command("git", "config", "user.email", "test@test.com").Run()
|
||||||
|
exec.Command("git", "config", "user.name", "Test User").Run()
|
||||||
|
|
||||||
|
cleanup = func() {
|
||||||
|
os.Chdir(originalWd)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmpDir, cleanup
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user