Skip to content

Commit 1a76fa4

Browse files
committed
fix(cmd): count abort-queued repos as skipped in rain summary
Abort cancels the shared runCtx, so workers hit the parent-context guard and dropped remaining jobs without StateSkipped or skipped++. Route all not-yet-started cancels through the existing per-repo skip path so the interrupted partial summary includes queued work.
1 parent a26a459 commit 1a76fa4

2 files changed

Lines changed: 39 additions & 3 deletions

File tree

‎cmd/rain_parallel_test.go‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,39 @@ func TestRunRainReposParallel_PreStartCancelCountsSkipped(t *testing.T) {
164164
t.Fatal("expected skipped progress event for pre-start cancel")
165165
}
166166
}
167+
168+
func TestRunRainReposParallel_ParentAbortCountsQueuedSkipped(t *testing.T) {
169+
// Mirror TUI Abort: cancel per-repo contexts and the shared runCtx while more
170+
// repos are queued than workers can run at once.
171+
repos := []git.Repository{
172+
{Name: "queued-a", Path: "/tmp/git-rain-never-a"},
173+
{Name: "queued-b", Path: "/tmp/git-rain-never-b"},
174+
{Name: "queued-c", Path: "/tmp/git-rain-never-c"},
175+
}
176+
paths := []string{repos[0].Path, repos[1].Path, repos[2].Path}
177+
runCtx, abortRun := context.WithCancel(context.Background())
178+
coord := newRainCoordinator(runCtx, paths)
179+
coord.AbortAll()
180+
abortRun()
181+
182+
progress := make(chan rainexec.Event, 16)
183+
totals, _ := runRainReposParallel(&registry.Registry{}, repos, git.RainOptions{RunCtx: runCtx}, false, 1, progress, coord, true)
184+
close(progress)
185+
186+
if totals.skipped != len(repos) {
187+
t.Fatalf("totals.skipped = %d, want %d (abort must count queued repos)", totals.skipped, len(repos))
188+
}
189+
if totals.updated != 0 || totals.frozen != 0 || totals.failed != 0 {
190+
t.Fatalf("unexpected non-skip totals: %+v", totals)
191+
}
192+
193+
skippedEvents := 0
194+
for e := range progress {
195+
if e.State == rainexec.StateSkipped {
196+
skippedEvents++
197+
}
198+
}
199+
if skippedEvents != len(repos) {
200+
t.Fatalf("skipped events = %d, want %d", skippedEvents, len(repos))
201+
}
202+
}

‎cmd/rain_workers.go‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,13 @@ func runRainReposParallel(reg *registry.Registry, repos []git.Repository, rainOp
6767
defer workersWG.Done()
6868
for job := range repoChan {
6969
repo := job.repo
70-
if runCtx != nil && runCtx.Err() != nil {
71-
continue
72-
}
7370
repoCtx := runCtx
7471
if coord != nil {
7572
repoCtx = coord.ContextFor(repo.Path)
7673
}
74+
// Parent abort cancels runCtx (and per-repo children). Count every
75+
// not-yet-started job as skipped so the interrupted summary includes
76+
// queued work, not only in-flight repos that already passed this check.
7777
if repoCtx != nil && repoCtx.Err() != nil {
7878
emitRainEvent(progress, rainexec.Event{
7979
RepoPath: repo.Path,

0 commit comments

Comments
 (0)