fix(process): keep runner results ordered

This commit is contained in:
Virgil 2026-04-01 09:53:02 +00:00
parent 1a6a74085e
commit 2d68f89197
2 changed files with 27 additions and 10 deletions

View file

@ -72,16 +72,17 @@ func (r *Runner) RunAll(ctx context.Context, specs []RunSpec) (*RunAllResult, er
// Build dependency graph
specMap := make(map[string]RunSpec)
for _, spec := range specs {
indexMap := make(map[string]int)
for i, spec := range specs {
specMap[spec.Name] = spec
indexMap[spec.Name] = i
}
// Track completion
completed := make(map[string]*RunResult)
var completedMu sync.Mutex
results := make([]RunResult, 0, len(specs))
var resultsMu sync.Mutex
results := make([]RunResult, len(specs))
// Process specs in waves
remaining := make(map[string]RunSpec)
@ -100,13 +101,13 @@ func (r *Runner) RunAll(ctx context.Context, specs []RunSpec) (*RunAllResult, er
if len(ready) == 0 && len(remaining) > 0 {
// Deadlock — circular dependency or missing specs. Mark as failed, not skipped.
for name := range remaining {
results = append(results, RunResult{
for name, spec := range remaining {
results[indexMap[name]] = RunResult{
Name: name,
Spec: remaining[name],
Spec: spec,
ExitCode: 1,
Error: core.E("runner.run_all", "circular dependency or missing dependency", nil),
})
}
}
break
}
@ -147,9 +148,7 @@ func (r *Runner) RunAll(ctx context.Context, specs []RunSpec) (*RunAllResult, er
completed[spec.Name] = &result
completedMu.Unlock()
resultsMu.Lock()
results = append(results, result)
resultsMu.Unlock()
results[indexMap[spec.Name]] = result
}(spec)
}
wg.Wait()

View file

@ -146,6 +146,24 @@ func TestRunner_RunAll_Good(t *testing.T) {
assert.True(t, result.Success())
assert.Equal(t, 4, result.Passed)
})
t.Run("preserves input order", func(t *testing.T) {
runner := newTestRunner(t)
specs := []RunSpec{
{Name: "third", Command: "echo", Args: []string{"3"}, After: []string{"second"}},
{Name: "first", Command: "echo", Args: []string{"1"}},
{Name: "second", Command: "echo", Args: []string{"2"}, After: []string{"first"}},
}
result, err := runner.RunAll(context.Background(), specs)
require.NoError(t, err)
require.Len(t, result.Results, len(specs))
for i, res := range result.Results {
assert.Equal(t, specs[i].Name, res.Name)
}
})
}
func TestRunner_CircularDeps_Bad(t *testing.T) {