mesh-build-go: a unit level whose gofmt or vet fails still runs its tests, so one check names every failure

The operator, 2026-11-02: a failed check showed only its first fault, and a group needed a run per fault.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-02 16:32:28 +01:00
parent c52afdf88b
commit 06358f94bd
2 changed files with 11 additions and 11 deletions
@@ -72,7 +72,8 @@ func TestTheUnitLevelRunsGofmtAndVetWithEveryTag(t *testing.T) {
} }
} }
// 1887/D7-go: through the step, the unit level of a tree holding an unformatted file fails, naming the file. // 1887/D7-go: through the step, the unit level of a tree holding an unformatted file fails, naming the file; its tests
// still run, so one check names the lint's failure and every failing test (the operator, 2026-11-02).
func TestAnUnformattedFileFailsTheUnitLevel(t *testing.T) { func TestAnUnformattedFileFailsTheUnitLevel(t *testing.T) {
m, states, ws, calls := workspaceFor(t, "empty") m, states, ws, calls := workspaceFor(t, "empty")
tree := filepath.Join(m.Work, ws, "tree") tree := filepath.Join(m.Work, ws, "tree")
@@ -85,11 +86,13 @@ func TestAnUnformattedFileFailsTheUnitLevel(t *testing.T) {
if res.Passed || len(res.Failed) != 1 || res.Failed[0].Test != "gofmt" || !strings.Contains(res.Failed[0].Output, "x.go") { if res.Passed || len(res.Failed) != 1 || res.Failed[0].Test != "gofmt" || !strings.Contains(res.Failed[0].Output, "x.go") {
t.Fatalf("result = %+v, want the level failed naming x.go", res) t.Fatalf("result = %+v, want the level failed naming x.go", res)
} }
// Review round 2 item 5: before the level's tests, which do not run once gofmt failed. // Review round 2 item 5: before the level's tests, which still run once gofmt failed.
tested := false
for _, c := range *calls { for _, c := range *calls {
if strings.Contains(c.line, " test -json") { tested = tested || strings.Contains(c.line, " test -json")
t.Errorf("the tests ran after gofmt failed: %s", c.line) }
} if !tested {
t.Errorf("the tests did not run after gofmt failed: %v", *calls)
} }
} }
@@ -250,7 +250,8 @@ func (m *Module) runLevel(ctx context.Context, tree string, o levelOpts) (*TestR
} }
if o.level == LevelUnit { if o.level == LevelUnit {
// gofmt and go vet of each directory the level runs come before its tests (ADR 0529 §1; issue 1887 D7-go): a // gofmt and go vet of each directory the level runs come before its tests (ADR 0529 §1; issue 1887 D7-go): a
// directory that fails them fails the level at once, and their time is the result's Lint. // directory that fails them fails the level, named first, and the tests still run, so one check names the lint's
// failures and every failing test (the operator, 2026-11-02); their time is the result's Lint.
linted := m.clock() linted := m.clock()
failed, err := m.lintAll(ctx, run, tree, todo, func(d string) []string { failed, err := m.lintAll(ctx, run, tree, todo, func(d string) []string {
return append(m.goEnvFor(filepath.Join(tree, d)), o.env...) return append(m.goEnvFor(filepath.Join(tree, d)), o.env...)
@@ -259,11 +260,7 @@ func (m *Module) runLevel(ctx context.Context, tree string, o levelOpts) (*TestR
return nil, err return nil, err
} }
res.Lint = m.clock().Sub(linted).Seconds() res.Lint = m.clock().Sub(linted).Seconds()
if len(failed) > 0 { res.Failed = failed
res.Failed = failed
res.judge(o.bounds)
return res, nil
}
began = m.clock() // the level's running time is its tests' began = m.clock() // the level's running time is its tests'
} }
runs := make([]dirRun, len(todo)) runs := make([]dirRun, len(todo))