Merge branch 'claudedo/340b4a2df0f14235a34fe0d02b2dc06f'
This commit is contained in:
@@ -643,6 +643,154 @@ public class TaskMergeServiceTests : IDisposable
|
||||
Assert.Equal(TaskMergeService.PreviewUnavailable, preview.Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PreviewAsync_RunVerifyTrue_NoVerifyCommandConfigured_NeverInvokesRunner()
|
||||
{
|
||||
if (!GitRepoFixture.IsGitAvailable()) return;
|
||||
var repo = NewRepo();
|
||||
var db = NewDb();
|
||||
var (list, task) = await SeedListAndTask(db, repo.RepoDir, TaskStatus.WaitingForReview);
|
||||
|
||||
var wtMgr = BuildWorktreeManager(db);
|
||||
var wtCtx = await wtMgr.CreateAsync(task, list, CancellationToken.None);
|
||||
_wtCleanups.Add((repo.RepoDir, wtCtx.WorktreePath));
|
||||
File.WriteAllText(Path.Combine(wtCtx.WorktreePath, "added.txt"), "x\n");
|
||||
await wtMgr.CommitIfChangedAsync(wtCtx, task, list, CancellationToken.None);
|
||||
|
||||
var fakeVerify = new FakeVerifyCommandRunner { Result = new VerifyCommandResult(1, false, "should never run") };
|
||||
var (svc, _) = BuildService(db, fakeVerify);
|
||||
var target = await new GitService().GetCurrentBranchAsync(repo.RepoDir);
|
||||
|
||||
var preview = await svc.PreviewAsync(task.Id, target, runVerify: true, CancellationToken.None);
|
||||
|
||||
Assert.Equal(TaskMergeService.PreviewClean, preview.Status);
|
||||
Assert.Null(preview.VerifyExitCode);
|
||||
Assert.Null(fakeVerify.CapturedCommand);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PreviewAsync_RunVerifyFalse_VerifyCommandConfigured_NeverInvokesRunner()
|
||||
{
|
||||
if (!GitRepoFixture.IsGitAvailable()) return;
|
||||
var repo = NewRepo();
|
||||
var db = NewDb();
|
||||
var (list, task) = await SeedListAndTask(db, repo.RepoDir, TaskStatus.WaitingForReview);
|
||||
await SeedVerifyCommand(db, list.Id, "dotnet build");
|
||||
|
||||
var wtMgr = BuildWorktreeManager(db);
|
||||
var wtCtx = await wtMgr.CreateAsync(task, list, CancellationToken.None);
|
||||
_wtCleanups.Add((repo.RepoDir, wtCtx.WorktreePath));
|
||||
File.WriteAllText(Path.Combine(wtCtx.WorktreePath, "added.txt"), "x\n");
|
||||
await wtMgr.CommitIfChangedAsync(wtCtx, task, list, CancellationToken.None);
|
||||
|
||||
var fakeVerify = new FakeVerifyCommandRunner { Result = new VerifyCommandResult(1, false, "should never run") };
|
||||
var (svc, _) = BuildService(db, fakeVerify);
|
||||
var target = await new GitService().GetCurrentBranchAsync(repo.RepoDir);
|
||||
|
||||
var preview = await svc.PreviewAsync(task.Id, target, CancellationToken.None);
|
||||
|
||||
Assert.Equal(TaskMergeService.PreviewClean, preview.Status);
|
||||
Assert.Null(preview.VerifyExitCode);
|
||||
Assert.Null(fakeVerify.CapturedCommand);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PreviewAsync_RunVerifyTrue_VerifyPasses_ReturnsCleanBuildAndLeavesTargetUntouched()
|
||||
{
|
||||
if (!GitRepoFixture.IsGitAvailable()) return;
|
||||
var repo = NewRepo();
|
||||
var db = NewDb();
|
||||
var (list, task) = await SeedListAndTask(db, repo.RepoDir, TaskStatus.WaitingForReview);
|
||||
await SeedVerifyCommand(db, list.Id, "dotnet build");
|
||||
|
||||
var wtMgr = BuildWorktreeManager(db);
|
||||
var wtCtx = await wtMgr.CreateAsync(task, list, CancellationToken.None);
|
||||
_wtCleanups.Add((repo.RepoDir, wtCtx.WorktreePath));
|
||||
File.WriteAllText(Path.Combine(wtCtx.WorktreePath, "added.txt"), "x\n");
|
||||
await wtMgr.CommitIfChangedAsync(wtCtx, task, list, CancellationToken.None);
|
||||
|
||||
var fakeVerify = new FakeVerifyCommandRunner
|
||||
{
|
||||
Result = new VerifyCommandResult(0, false, "build ok"),
|
||||
FileToCheck = "added.txt",
|
||||
};
|
||||
var (svc, _) = BuildService(db, fakeVerify);
|
||||
var git = new GitService();
|
||||
var target = await git.GetCurrentBranchAsync(repo.RepoDir);
|
||||
var statusBefore = await git.GetStatusPorcelainAsync(repo.RepoDir);
|
||||
var headBefore = await git.RevParseHeadAsync(repo.RepoDir);
|
||||
|
||||
var preview = await svc.PreviewAsync(task.Id, target, runVerify: true, CancellationToken.None);
|
||||
|
||||
Assert.Equal(TaskMergeService.PreviewClean, preview.Status);
|
||||
Assert.Equal(0, preview.VerifyExitCode);
|
||||
Assert.NotNull(preview.VerifyDurationMs);
|
||||
Assert.Equal("dotnet build", fakeVerify.CapturedCommand);
|
||||
Assert.NotEqual(repo.RepoDir, fakeVerify.CapturedWorkingDir);
|
||||
Assert.True(fakeVerify.WorkingDirHadFile, "the merged file must be present in the scratch worktree at verify time");
|
||||
|
||||
// Scratch worktree removed afterward; the real target working tree never changed.
|
||||
Assert.False(Directory.Exists(fakeVerify.CapturedWorkingDir));
|
||||
Assert.Equal(statusBefore, await git.GetStatusPorcelainAsync(repo.RepoDir));
|
||||
Assert.Equal(headBefore, await git.RevParseHeadAsync(repo.RepoDir));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PreviewAsync_RunVerifyTrue_VerifyFails_ReturnsExitCodeAndOutputTailWithoutTouchingTarget()
|
||||
{
|
||||
if (!GitRepoFixture.IsGitAvailable()) return;
|
||||
var repo = NewRepo();
|
||||
var db = NewDb();
|
||||
var (list, task) = await SeedListAndTask(db, repo.RepoDir, TaskStatus.WaitingForReview);
|
||||
await SeedVerifyCommand(db, list.Id, "dotnet build");
|
||||
|
||||
var wtMgr = BuildWorktreeManager(db);
|
||||
var wtCtx = await wtMgr.CreateAsync(task, list, CancellationToken.None);
|
||||
_wtCleanups.Add((repo.RepoDir, wtCtx.WorktreePath));
|
||||
File.WriteAllText(Path.Combine(wtCtx.WorktreePath, "added.txt"), "x\n");
|
||||
await wtMgr.CommitIfChangedAsync(wtCtx, task, list, CancellationToken.None);
|
||||
|
||||
var fakeVerify = new FakeVerifyCommandRunner { Result = new VerifyCommandResult(1, false, "build broke: CS0103") };
|
||||
var (svc, _) = BuildService(db, fakeVerify);
|
||||
var git = new GitService();
|
||||
var target = await git.GetCurrentBranchAsync(repo.RepoDir);
|
||||
var headBefore = await git.RevParseHeadAsync(repo.RepoDir);
|
||||
|
||||
var preview = await svc.PreviewAsync(task.Id, target, runVerify: true, CancellationToken.None);
|
||||
|
||||
// The merge-tree result itself is still clean -- only the build/test of it failed.
|
||||
Assert.Equal(TaskMergeService.PreviewClean, preview.Status);
|
||||
Assert.Equal(1, preview.VerifyExitCode);
|
||||
Assert.Contains("build broke: CS0103", preview.VerifyOutputTail);
|
||||
Assert.False(Directory.Exists(fakeVerify.CapturedWorkingDir));
|
||||
Assert.Equal(headBefore, await git.RevParseHeadAsync(repo.RepoDir));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PreviewAsync_RunVerifyTrue_CleansUpScratchWorktreeRegistration()
|
||||
{
|
||||
if (!GitRepoFixture.IsGitAvailable()) return;
|
||||
var repo = NewRepo();
|
||||
var db = NewDb();
|
||||
var (list, task) = await SeedListAndTask(db, repo.RepoDir, TaskStatus.WaitingForReview);
|
||||
await SeedVerifyCommand(db, list.Id, "dotnet build");
|
||||
|
||||
var wtMgr = BuildWorktreeManager(db);
|
||||
var wtCtx = await wtMgr.CreateAsync(task, list, CancellationToken.None);
|
||||
_wtCleanups.Add((repo.RepoDir, wtCtx.WorktreePath));
|
||||
File.WriteAllText(Path.Combine(wtCtx.WorktreePath, "added.txt"), "x\n");
|
||||
await wtMgr.CommitIfChangedAsync(wtCtx, task, list, CancellationToken.None);
|
||||
|
||||
var fakeVerify = new FakeVerifyCommandRunner { Result = new VerifyCommandResult(0, false, "ok") };
|
||||
var (svc, _) = BuildService(db, fakeVerify);
|
||||
var target = await new GitService().GetCurrentBranchAsync(repo.RepoDir);
|
||||
|
||||
await svc.PreviewAsync(task.Id, target, runVerify: true, CancellationToken.None);
|
||||
|
||||
var worktreeListing = GitRepoFixture.RunGit(repo.RepoDir, "worktree", "list", "--porcelain");
|
||||
Assert.DoesNotContain(fakeVerify.CapturedWorkingDir!, worktreeListing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ApproveAndMergeAsync_CleanWorktree_MergesAndMarksDone()
|
||||
{
|
||||
@@ -1213,10 +1361,17 @@ internal sealed class FakeVerifyCommandRunner : IVerifyCommandRunner
|
||||
public string? CapturedWorkingDir { get; private set; }
|
||||
public string? CapturedCommand { get; private set; }
|
||||
|
||||
// Set before the call to snapshot, at call time, whether this file exists in workingDir --
|
||||
// lets a preview-verify test prove the scratch worktree actually contains the merged content.
|
||||
public string? FileToCheck { get; set; }
|
||||
public bool? WorkingDirHadFile { get; private set; }
|
||||
|
||||
public Task<VerifyCommandResult> RunAsync(string workingDir, string command, TimeSpan timeout, CancellationToken ct)
|
||||
{
|
||||
CapturedWorkingDir = workingDir;
|
||||
CapturedCommand = command;
|
||||
if (FileToCheck is not null)
|
||||
WorkingDirHadFile = File.Exists(Path.Combine(workingDir, FileToCheck));
|
||||
return Task.FromResult(Result);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user