fix(process): keep runner results ordered
This commit is contained in:
parent
1a6a74085e
commit
2d68f89197
2 changed files with 27 additions and 10 deletions
19
runner.go
19
runner.go
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue