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).
This commit is contained in:
2026-10-29 00:07:18 +01:00
parent d747c1128e
commit 261f41aec1
3 changed files with 14 additions and 3 deletions
+2 -2
View File
@@ -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")
+7 -1
View File
@@ -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
+5
View File
@@ -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