From 261f41aec1ae7fadabcef269edcd80c90a4ea10d Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 29 Oct 2026 00:07:18 +0100 Subject: [PATCH] A check ask may ask the merge alone, so the checker can name every group member that does not merge in one verdict A group's check named only its first member in conflict; each hidden one cost a check round (issue 1921's kind; no open issue covers it). --- go/buildstep/askrun.go | 4 ++-- go/buildstep/askrun_test.go | 8 +++++++- go/delivery/stepasks.go | 5 +++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/go/buildstep/askrun.go b/go/buildstep/askrun.go index f1ef95b..832751c 100644 --- a/go/buildstep/askrun.go +++ b/go/buildstep/askrun.go @@ -170,8 +170,8 @@ func (s AskSteps) check(ctx context.Context, job delivery.CheckJob) (any, error) } defer s.release(f.Workspace) answer := delivery.CheckAnswer{Fetch: r} - if len(f.Conflicts) > 0 { - return answer, nil // the asker reads the conflict from the fetch's answer: a verdict, not an error + if len(f.Conflicts) > 0 || job.MergeOnly { + return answer, nil // the asker reads the merge or the conflict from the fetch's answer: a verdict, not an error } if s.Test == nil { return nil, Refuse("this build module tests nothing") diff --git a/go/buildstep/askrun_test.go b/go/buildstep/askrun_test.go index 49ea614..5acc53c 100644 --- a/go/buildstep/askrun_test.go +++ b/go/buildstep/askrun_test.go @@ -235,7 +235,7 @@ test {"level":"unit","runner":"workspace","workspace":"/w"}`}, } // A Node check tests each module directory, the one whose tests changed first; a conflict ends the ask with the fetch -// alone, a verdict for the asker. +// alone, a verdict for the asker; so does a merge-only ask of a head that merges. func TestRunAskChecksNodeModulesAndConflicts(t *testing.T) { r := &recorder{fetch: map[string]any{"workspace": "/w", "modules": []string{"a", "b"}, "changed": []string{"b/test/x.test.ts"}}, tests: map[string]bool{"a": true, "b": true}} @@ -252,6 +252,12 @@ func TestRunAskChecksNodeModulesAndConflicts(t *testing.T) { if err != nil || len(r.calls) != 1 || len(out.(delivery.CheckAnswer).Levels) != 0 { t.Fatalf("a conflict: %v %v", err, r.calls) } + // A merge-only ask answers the fetch of a head that merges and runs no level. + r = &recorder{fetch: map[string]any{"workspace": "/w", "merge": "m1"}, tests: map[string]bool{"a": true}} + out, err = RunAsk(context.Background(), r.steps(), ask(delivery.CheckJob{Levels: []string{delivery.LevelUnit}, MergeOnly: true, Fetch: map[string]any{"repository": "novox/x", "commit": runCommit}})) + if err != nil || len(r.calls) != 1 || len(out.(delivery.CheckAnswer).Levels) != 0 || !strings.Contains(string(out.(delivery.CheckAnswer).Fetch), `"m1"`) { + t.Fatalf("merge only: %v %v %v", err, r.calls, out) + } } // Issue 1921: a failure in the packages whose tests changed does not stop the level: the other packages still run, so two diff --git a/go/delivery/stepasks.go b/go/delivery/stepasks.go index fba438c..c95a925 100644 --- a/go/delivery/stepasks.go +++ b/go/delivery/stepasks.go @@ -345,6 +345,11 @@ type CheckJob struct { // has to list them. The build step hands them to its test tool as the argument NodeNamesArg, and the build module // gives them to the tests in NodeNamesEnv. NodeNames []string `json:"node-names,omitempty"` + // MergeOnly says the build module answers the fetch alone, its merge or the files in conflict, and runs no level: the + // checker asks it of a delivery group's members after one member's check failed, so one verdict names every member + // that does not merge into its trunk instead of the first. Levels stay named, so a build module from before it (which + // ignores it) still takes the ask; the checker reads only the fetch of such an answer. + MergeOnly bool `json:"merge-only,omitempty"` } // NodeNamesArg is the test tool's argument that carries a check's node names, and NodeNamesEnv the environment