diff --git a/modules/mesh-build-go/buildstep/askrun.go b/modules/mesh-build-go/buildstep/askrun.go index 6400ec15d..027b3e1ba 100644 --- a/modules/mesh-build-go/buildstep/askrun.go +++ b/modules/mesh-build-go/buildstep/askrun.go @@ -303,7 +303,10 @@ func (s AskSteps) check(ctx context.Context, job sdkstep.CheckJob) (any, error) _, err := s.level(ctx, job, level, f, runner, &la) answer.Levels = append(answer.Levels, la) if err != nil { - return nil, err + // A level that errors after the fetch merged (it does not compile or generate) ends the step failed with its + // answer all the same: its fetch and the levels so far beside the error, which the step's end keeps, so the + // checker previews the merge from it (design 47 G, A-286). + return answer, err } } return answer, nil diff --git a/modules/mesh-build-go/buildstep/askrun_test.go b/modules/mesh-build-go/buildstep/askrun_test.go index d9a93e195..869bc859d 100644 --- a/modules/mesh-build-go/buildstep/askrun_test.go +++ b/modules/mesh-build-go/buildstep/askrun_test.go @@ -285,6 +285,33 @@ func TestRunAskChecksNodeModulesAndConflicts(t *testing.T) { if err != nil || len(r.calls) != 1 || len(out.(sdkstep.CheckAnswer).Levels) != 0 { t.Fatalf("a conflict: %v %v", err, r.calls) } + // A-286: a level that errors after the fetch merged ends the step failed with its answer all the same, its fetch and + // the levels so far beside the error, and the step's end keeps it, so the checker previews the merge from it. + r = &recorder{fetch: map[string]any{"workspace": "/w", "merge": "m1", "modules": []string{"a"}}, tests: map[string]bool{"a": true}} + s = r.steps() + s.Digest = nil + passing := s.Test + s.Test = func(ctx context.Context, args map[string]any) (any, error) { + if args["level"] == sdkstep.LevelIntegration { + return nil, errors.New("does not compile") + } + return passing(ctx, args) + } + errs := ask(sdkstep.CheckJob{Levels: []string{sdkstep.LevelUnit, sdkstep.LevelIntegration}, Fetch: sdkstep.Fetch{Repository: "novox/x", Commit: runCommit}}) + out, err = RunAsk(context.Background(), s, errs) + if a, _ := out.(sdkstep.CheckAnswer); err == nil || a.Fetch.Merge != "m1" || len(a.Levels) != 2 || len(a.Levels[0].Tests) != 1 { + t.Fatalf("an erring level: %v, answer %+v: want the error beside the fetch and both levels", err, out) + } + k := newKeys() + id, err := Start(context.Background(), k.put, "ace", "test", func(ctx context.Context) (any, error) { return RunAsk(ctx, s, errs) }) + if err != nil { + t.Fatal(err) + } + k.waitEnd(t) + var kept sdkstep.CheckAnswer + if end := k.last("ace." + id); end.State != sdkstep.StepFailed || json.Unmarshal(end.Result, &kept) != nil || kept.Fetch.Merge != "m1" { + t.Fatalf("the failed end %+v keeps no answer with its fetch", end) + } } // Issue 1289: the packages whose tests changed run first. Since 2026-11-02 (the operator: "A failed check shows only its