feat(worker,ui): wire EF Core into DI and update all consumers to IDbContextFactory
Worker and App Program.cs: replace SqliteConnectionFactory+SchemaInitializer with AddDbContextFactory<ClaudeDoDbContext> + Database.Migrate(). Repos changed from AddSingleton to AddScoped. All singleton services (QueueService, StaleTaskRecovery, WorktreeManager, TaskRunner) and singleton ViewModels (MainWindowViewModel, TaskDetailViewModel, TaskListViewModel, TaskEditorViewModel) now take IDbContextFactory<ClaudeDoDbContext> and create short-lived contexts per operation. Test infrastructure: DbFixture now uses EF migrations instead of SchemaInitializer; all test classes create contexts via DbFixture.CreateContext(). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using ClaudeDo.Data;
|
||||
using ClaudeDo.Data.Git;
|
||||
using ClaudeDo.Data.Models;
|
||||
using ClaudeDo.Data.Repositories;
|
||||
@@ -24,19 +25,19 @@ public class WorktreeManagerTests : IDisposable
|
||||
return f;
|
||||
}
|
||||
|
||||
private async Task<(WorktreeManager mgr, WorktreeRepository wtRepo)> CreateManagerAsync(
|
||||
private async Task<(WorktreeManager mgr, DbFixture db)> CreateManagerAsync(
|
||||
TaskEntity task, ListEntity list, string strategy = "sibling", string? centralRoot = null)
|
||||
{
|
||||
var db = new DbFixture();
|
||||
_dbFixtures.Add(db);
|
||||
|
||||
// Seed the DB with list and task so FK constraints pass.
|
||||
var listRepo = new ListRepository(db.Factory);
|
||||
var taskRepo = new TaskRepository(db.Factory);
|
||||
using var seedCtx = db.CreateContext();
|
||||
var listRepo = new ListRepository(seedCtx);
|
||||
var taskRepo = new TaskRepository(seedCtx);
|
||||
await listRepo.AddAsync(list);
|
||||
await taskRepo.AddAsync(task);
|
||||
|
||||
var wtRepo = new WorktreeRepository(db.Factory);
|
||||
var cfg = new WorkerConfig
|
||||
{
|
||||
WorktreeRootStrategy = strategy,
|
||||
@@ -45,8 +46,8 @@ public class WorktreeManagerTests : IDisposable
|
||||
cfg.CentralWorktreeRoot = centralRoot;
|
||||
|
||||
var mgr = new WorktreeManager(
|
||||
new GitService(), wtRepo, cfg, NullLogger<WorktreeManager>.Instance);
|
||||
return (mgr, wtRepo);
|
||||
new GitService(), db.CreateFactory(), cfg, NullLogger<WorktreeManager>.Instance);
|
||||
return (mgr, db);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -56,7 +57,7 @@ public class WorktreeManagerTests : IDisposable
|
||||
|
||||
var repo = CreateRepo();
|
||||
var (task, list) = MakeEntities(repo.RepoDir);
|
||||
var (mgr, wtRepo) = await CreateManagerAsync(task, list);
|
||||
var (mgr, db) = await CreateManagerAsync(task, list);
|
||||
|
||||
var ctx = await mgr.CreateAsync(task, list, CancellationToken.None);
|
||||
_worktreeCleanups.Add((repo.RepoDir, ctx.WorktreePath));
|
||||
@@ -66,6 +67,8 @@ public class WorktreeManagerTests : IDisposable
|
||||
Assert.Equal($"claudedo/{task.Id.Replace("-", "")}", ctx.BranchName);
|
||||
Assert.Equal(repo.BaseCommit, ctx.BaseCommit);
|
||||
|
||||
using var readCtx = db.CreateContext();
|
||||
var wtRepo = new WorktreeRepository(readCtx);
|
||||
var row = await wtRepo.GetByTaskIdAsync(task.Id);
|
||||
Assert.NotNull(row);
|
||||
Assert.Equal(WorktreeState.Active, row!.State);
|
||||
@@ -80,7 +83,7 @@ public class WorktreeManagerTests : IDisposable
|
||||
|
||||
var repo = CreateRepo();
|
||||
var (task, list) = MakeEntities(repo.RepoDir);
|
||||
var (mgr, wtRepo) = await CreateManagerAsync(task, list);
|
||||
var (mgr, db) = await CreateManagerAsync(task, list);
|
||||
|
||||
var ctx = await mgr.CreateAsync(task, list, CancellationToken.None);
|
||||
_worktreeCleanups.Add((repo.RepoDir, ctx.WorktreePath));
|
||||
@@ -88,6 +91,8 @@ public class WorktreeManagerTests : IDisposable
|
||||
var committed = await mgr.CommitIfChangedAsync(ctx, task, list, CancellationToken.None);
|
||||
|
||||
Assert.False(committed);
|
||||
using var readCtx = db.CreateContext();
|
||||
var wtRepo = new WorktreeRepository(readCtx);
|
||||
var row = await wtRepo.GetByTaskIdAsync(task.Id);
|
||||
Assert.Null(row!.HeadCommit);
|
||||
}
|
||||
@@ -99,7 +104,7 @@ public class WorktreeManagerTests : IDisposable
|
||||
|
||||
var repo = CreateRepo();
|
||||
var (task, list) = MakeEntities(repo.RepoDir);
|
||||
var (mgr, wtRepo) = await CreateManagerAsync(task, list);
|
||||
var (mgr, db) = await CreateManagerAsync(task, list);
|
||||
|
||||
var ctx = await mgr.CreateAsync(task, list, CancellationToken.None);
|
||||
_worktreeCleanups.Add((repo.RepoDir, ctx.WorktreePath));
|
||||
@@ -109,6 +114,8 @@ public class WorktreeManagerTests : IDisposable
|
||||
var committed = await mgr.CommitIfChangedAsync(ctx, task, list, CancellationToken.None);
|
||||
|
||||
Assert.True(committed);
|
||||
using var readCtx = db.CreateContext();
|
||||
var wtRepo = new WorktreeRepository(readCtx);
|
||||
var row = await wtRepo.GetByTaskIdAsync(task.Id);
|
||||
Assert.NotNull(row!.HeadCommit);
|
||||
Assert.NotEqual(ctx.BaseCommit, row.HeadCommit);
|
||||
@@ -129,20 +136,24 @@ public class WorktreeManagerTests : IDisposable
|
||||
|
||||
var db = new DbFixture();
|
||||
_dbFixtures.Add(db);
|
||||
var listRepo = new ListRepository(db.Factory);
|
||||
var taskRepo = new TaskRepository(db.Factory);
|
||||
await listRepo.AddAsync(list);
|
||||
await taskRepo.AddAsync(task);
|
||||
using (var seedCtx = db.CreateContext())
|
||||
{
|
||||
var listRepo = new ListRepository(seedCtx);
|
||||
var taskRepo = new TaskRepository(seedCtx);
|
||||
await listRepo.AddAsync(list);
|
||||
await taskRepo.AddAsync(task);
|
||||
}
|
||||
|
||||
var wtRepo = new WorktreeRepository(db.Factory);
|
||||
var cfg = new WorkerConfig { WorktreeRootStrategy = "sibling" };
|
||||
var mgr = new WorktreeManager(
|
||||
new GitService(), wtRepo, cfg, NullLogger<WorktreeManager>.Instance);
|
||||
new GitService(), db.CreateFactory(), cfg, NullLogger<WorktreeManager>.Instance);
|
||||
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => mgr.CreateAsync(task, list, CancellationToken.None));
|
||||
Assert.Contains("not a git repository", ex.Message);
|
||||
|
||||
using var readCtx = db.CreateContext();
|
||||
var wtRepo = new WorktreeRepository(readCtx);
|
||||
var row = await wtRepo.GetByTaskIdAsync(task.Id);
|
||||
Assert.Null(row);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user