feat(merge): fold parent branch into combined-diff for improvement parents
This commit is contained in:
@@ -43,17 +43,24 @@ public sealed class PlanningAggregator
|
|||||||
string planningTaskId, CancellationToken ct)
|
string planningTaskId, CancellationToken ct)
|
||||||
{
|
{
|
||||||
using var ctx = _dbFactory.CreateDbContext();
|
using var ctx = _dbFactory.CreateDbContext();
|
||||||
var children = await ctx.Tasks
|
var parent = await ctx.Tasks
|
||||||
.Include(t => t.Worktree)
|
.Include(t => t.Worktree)
|
||||||
.Where(t => t.ParentTaskId == planningTaskId)
|
.Include(t => t.Children).ThenInclude(c => c.Worktree)
|
||||||
.OrderBy(t => t.SortOrder)
|
.SingleOrDefaultAsync(t => t.Id == planningTaskId, ct);
|
||||||
.ToListAsync(ct);
|
if (parent is null) return new List<SubtaskDiff>();
|
||||||
|
|
||||||
|
var nodes = new List<TaskEntity>();
|
||||||
|
// An improvement parent carries its own code branch — fold it in first so the
|
||||||
|
// combined diff matches what the tree-merge will produce.
|
||||||
|
if (parent.PlanningPhase == PlanningPhase.None && parent.Worktree is { State: WorktreeState.Active })
|
||||||
|
nodes.Add(parent);
|
||||||
|
nodes.AddRange(parent.Children.OrderBy(c => c.SortOrder));
|
||||||
|
|
||||||
var result = new List<SubtaskDiff>();
|
var result = new List<SubtaskDiff>();
|
||||||
foreach (var child in children)
|
foreach (var node in nodes)
|
||||||
{
|
{
|
||||||
if (child.Worktree is null) continue;
|
if (node.Worktree is null) continue;
|
||||||
var wt = child.Worktree;
|
var wt = node.Worktree;
|
||||||
var head = wt.HeadCommit ?? await _git.RevParseHeadAsync(wt.Path, ct);
|
var head = wt.HeadCommit ?? await _git.RevParseHeadAsync(wt.Path, ct);
|
||||||
string unified;
|
string unified;
|
||||||
try
|
try
|
||||||
@@ -62,11 +69,11 @@ public sealed class PlanningAggregator
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogWarning(ex, "diff failed for subtask {Id}", child.Id);
|
_logger.LogWarning(ex, "diff failed for node {Id}", node.Id);
|
||||||
unified = "";
|
unified = "";
|
||||||
}
|
}
|
||||||
result.Add(new SubtaskDiff(
|
result.Add(new SubtaskDiff(
|
||||||
child.Id, child.Title, wt.BranchName, wt.BaseCommit, head, wt.DiffStat, unified));
|
node.Id, node.Title, wt.BranchName, wt.BaseCommit, head, wt.DiffStat, unified));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -87,12 +94,18 @@ public sealed class PlanningAggregator
|
|||||||
|
|
||||||
await GitRawAsync(repoDir, ct, "checkout", "-b", integrationBranch);
|
await GitRawAsync(repoDir, ct, "checkout", "-b", integrationBranch);
|
||||||
|
|
||||||
foreach (var child in childSubtasks)
|
var nodes = new List<TaskEntity>();
|
||||||
|
// Fold the improvement parent's own branch in first (planning parents have none).
|
||||||
|
if (planning.PlanningPhase == PlanningPhase.None && planning.Worktree is { State: WorktreeState.Active })
|
||||||
|
nodes.Add(planning);
|
||||||
|
nodes.AddRange(childSubtasks);
|
||||||
|
|
||||||
|
foreach (var node in nodes)
|
||||||
{
|
{
|
||||||
if (child.Worktree is null) continue;
|
if (node.Worktree is null) continue;
|
||||||
var (code, _) = await _git.MergeNoFfAsync(
|
var (code, _) = await _git.MergeNoFfAsync(
|
||||||
repoDir, child.Worktree.BranchName,
|
repoDir, node.Worktree.BranchName,
|
||||||
$"Integrate subtask: {child.Title}", ct);
|
$"Integrate: {node.Title}", ct);
|
||||||
if (code != 0)
|
if (code != 0)
|
||||||
{
|
{
|
||||||
List<string> files;
|
List<string> files;
|
||||||
@@ -104,7 +117,7 @@ public sealed class PlanningAggregator
|
|||||||
try { await _git.BranchDeleteAsync(repoDir, integrationBranch, force: true, ct); } catch { }
|
try { await _git.BranchDeleteAsync(repoDir, integrationBranch, force: true, ct); } catch { }
|
||||||
|
|
||||||
return new CombinedDiffResult.Failed(
|
return new CombinedDiffResult.Failed(
|
||||||
new CombinedDiffFailure(child.Id, files));
|
new CombinedDiffFailure(node.Id, files));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +148,7 @@ public sealed class PlanningAggregator
|
|||||||
using var ctx = _dbFactory.CreateDbContext();
|
using var ctx = _dbFactory.CreateDbContext();
|
||||||
var planning = await ctx.Tasks
|
var planning = await ctx.Tasks
|
||||||
.Include(t => t.List)
|
.Include(t => t.List)
|
||||||
|
.Include(t => t.Worktree)
|
||||||
.Include(t => t.Children).ThenInclude(c => c.Worktree)
|
.Include(t => t.Children).ThenInclude(c => c.Worktree)
|
||||||
.SingleOrDefaultAsync(t => t.Id == planningTaskId, ct)
|
.SingleOrDefaultAsync(t => t.Id == planningTaskId, ct)
|
||||||
?? throw new KeyNotFoundException($"Planning task '{planningTaskId}' not found.");
|
?? throw new KeyNotFoundException($"Planning task '{planningTaskId}' not found.");
|
||||||
|
|||||||
Reference in New Issue
Block a user