Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,27 @@ type aggregate struct {
Unsupported int
Changed int
Unchanged int
Additions int
Deletions int
}

func countDiffLines(current, proposed string) (int, int) {
a := difflib.SplitLines(current)
b := difflib.SplitLines(proposed)
m := difflib.NewMatcher(a, b)
var adds, dels int
for _, op := range m.GetOpCodes() {
switch op.Tag {
case 'r':
dels += op.I2 - op.I1
adds += op.J2 - op.J1
case 'd':
dels += op.I2 - op.I1
case 'i':
adds += op.J2 - op.J1
}
}
return adds, dels
}

func aggregateResults(results []agentResult) aggregate {
Expand All @@ -166,6 +187,10 @@ func aggregateResults(results []agentResult) aggregate {
}
if r.HasChanges != nil && *r.HasChanges {
a.Changed++
adds, dels := countDiffLines(r.Current, r.Proposed)
a.Additions += adds
a.Deletions += dels
Comment on lines +190 to +192
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New behavior aggregates Additions/Deletions based on diffs, but the tests currently only assert the final title string and do not verify that aggregateResults computes Additions/Deletions correctly across multiple agents / multi-line changes. Add a focused unit test (and/or tests for countDiffLines) that asserts expected additions/deletions counts for representative diffs and ensures unchanged/unsupported/errored agents don’t affect the totals.

Suggested change
adds, dels := countDiffLines(r.Current, r.Proposed)
a.Additions += adds
a.Deletions += dels
if r.Status == db.DeploymentPlanTargetStatusCompleted {
adds, dels := countDiffLines(r.Current, r.Proposed)
a.Additions += adds
a.Deletions += dels
}

Copilot uses AI. Check for mistakes.
continue
}
if r.HasChanges != nil && !*r.HasChanges {
a.Unchanged++
Expand Down Expand Up @@ -228,25 +253,12 @@ func (a aggregate) checkTitle() string {
if a.Total > 0 && a.Unsupported == a.Total {
return "All agents unsupported"
}

diffSummary := fmt.Sprintf("+%d -%d", a.Additions, a.Deletions)
if a.Errored > 0 {
return fmt.Sprintf(
"%d errored, %d changed, %d unchanged, %d unsupported",
a.Errored, a.Changed, a.Unchanged, a.Unsupported,
)
return fmt.Sprintf("%s (%d errored)", diffSummary, a.Errored)
}
if a.Changed > 0 {
return fmt.Sprintf(
"%d changed, %d unchanged, %d unsupported",
a.Changed, a.Unchanged, a.Unsupported,
)
}
if a.Unsupported > 0 {
return fmt.Sprintf(
"No changes (%d unsupported)",
a.Unsupported,
)
}
return "No changes"
return diffSummary
Comment on lines +256 to +261
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

UX: "+0 -0" replaces the old "No changes" summary.

When every agent reports HasChanges=false, the title now reads +0 -0 (confirmed by the "final no changes shows zero diff counts" and "final all clean" test cases). That's technically correct, but arguably less informative than the prior "No changes" / human-readable summary. If intentional per the linked issue (#1033 asks specifically for line totals), feel free to ignore; otherwise consider falling back to "No changes" when a.Additions == 0 && a.Deletions == 0 && a.Changed == 0.

Optional fallback
 	diffSummary := fmt.Sprintf("+%d -%d", a.Additions, a.Deletions)
 	if a.Errored > 0 {
 		return fmt.Sprintf("%s (%d errored)", diffSummary, a.Errored)
 	}
+	if a.Additions == 0 && a.Deletions == 0 && a.Changed == 0 {
+		return "No changes"
+	}
 	return diffSummary
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
diffSummary := fmt.Sprintf("+%d -%d", a.Additions, a.Deletions)
if a.Errored > 0 {
return fmt.Sprintf(
"%d errored, %d changed, %d unchanged, %d unsupported",
a.Errored, a.Changed, a.Unchanged, a.Unsupported,
)
return fmt.Sprintf("%s (%d errored)", diffSummary, a.Errored)
}
if a.Changed > 0 {
return fmt.Sprintf(
"%d changed, %d unchanged, %d unsupported",
a.Changed, a.Unchanged, a.Unsupported,
)
}
if a.Unsupported > 0 {
return fmt.Sprintf(
"No changes (%d unsupported)",
a.Unsupported,
)
}
return "No changes"
return diffSummary
diffSummary := fmt.Sprintf("+%d -%d", a.Additions, a.Deletions)
if a.Errored > 0 {
return fmt.Sprintf("%s (%d errored)", diffSummary, a.Errored)
}
if a.Additions == 0 && a.Deletions == 0 && a.Changed == 0 {
return "No changes"
}
return diffSummary
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/workspace-engine/svc/controllers/deploymentplanresult/github_check.go`
around lines 264 - 269, The diff summary currently returns "+0 -0" when there
are no changes; update the logic in the formatting function that produces
diffSummary (the block using a.Additions, a.Deletions, a.Errored) to first
detect the all-clean case (a.Additions == 0 && a.Deletions == 0 && a.Changed ==
0) and return "No changes" in that case, otherwise build the "+%d -%d" summary
as before and still append the "(%d errored)" suffix when a.Errored > 0; keep
references to the same variables (a.Additions, a.Deletions, a.Changed,
a.Errored) so the change is a simple conditional early-return.

}

// formatAgentSection renders the markdown block for one agent in the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,53 @@ func TestAggregateResults_Counts(t *testing.T) {
assert.Equal(t, 1, agg.Unsupported)
assert.Equal(t, 1, agg.Changed)
assert.Equal(t, 1, agg.Unchanged)
assert.Equal(t, 1, agg.Additions)
assert.Equal(t, 1, agg.Deletions)
}

func TestAggregateResults_AdditionsDeletionsSumAcrossAgents(t *testing.T) {
// Two changed agents contribute their own diff counts; unchanged,
// errored, and unsupported agents must not contribute.
results := []agentResult{
completedResult("a", true, "a\nb\nc\n", "a\nX\nc\nd\n"), // 2 adds, 1 del
completedResult("b", true, "x\ny\nz\n", "x\nz\n"), // 0 adds, 1 del
completedResult("unchanged", false, "same\n", "same\n"), // ignored
erroredResult("errored", "boom"), // ignored
unsupportedResult("unsupported"), // ignored
}

agg := aggregateResults(results)

assert.Equal(t, 2, agg.Changed)
assert.Equal(t, 2, agg.Additions)
assert.Equal(t, 2, agg.Deletions)
}

func TestCountDiffLines(t *testing.T) {
tests := []struct {
name string
current string
proposed string
wantAdditions int
wantDeletions int
}{
{"identical", "a\nb\nc\n", "a\nb\nc\n", 0, 0},
{"pure insert", "a\nb\n", "a\nb\nc\n", 1, 0},
{"pure delete", "a\nb\nc\n", "a\n", 0, 2},
{"single-line replace", "foo\n", "bar\n", 1, 1},
{"multi-line mixed (replace + insert)", "a\nb\nc\n", "a\nX\nc\nd\n", 2, 1},
{"empty both", "", "", 0, 0},
{"empty current, content proposed", "", "a\nb\n", 2, 0},
{"content current, empty proposed", "a\nb\n", "", 0, 2},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
adds, dels := countDiffLines(tc.current, tc.proposed)
assert.Equal(t, tc.wantAdditions, adds, "additions")
assert.Equal(t, tc.wantDeletions, dels, "deletions")
})
}
}

func TestAggregateResults_Empty(t *testing.T) {
Expand Down Expand Up @@ -154,24 +201,40 @@ func TestAggregate_CheckTitle(t *testing.T) {
"1 errored, 0 unsupported (2/3 agents complete)",
},
{
"final errored summary includes unsupported",
aggregate{Total: 3, Completed: 1, Errored: 1, Unsupported: 1, Changed: 1},
"1 errored, 1 changed, 0 unchanged, 1 unsupported",
"final errored summary shows diff counts and errored count",
aggregate{
Total: 3,
Completed: 1,
Errored: 1,
Unsupported: 1,
Changed: 1,
Additions: 7,
Deletions: 3,
},
"+7 -3 (1 errored)",
},
{
"final with changes includes unsupported",
aggregate{Total: 3, Completed: 2, Changed: 1, Unchanged: 1, Unsupported: 1},
"1 changed, 1 unchanged, 1 unsupported",
"final with changes shows diff counts",
aggregate{
Total: 3,
Completed: 2,
Changed: 1,
Unchanged: 1,
Unsupported: 1,
Additions: 12,
Deletions: 4,
},
"+12 -4",
},
{
"final no changes with some unsupported",
"final no changes shows zero diff counts",
aggregate{Total: 3, Completed: 2, Unchanged: 2, Unsupported: 1},
"No changes (1 unsupported)",
"+0 -0",
},
{
"final no changes",
"final all clean",
aggregate{Total: 2, Completed: 2, Unchanged: 2},
"No changes",
"+0 -0",
},
{
"all unsupported",
Expand Down
Loading