From ab610ffed42f1baaf408633789123447bc8b6a99 Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 2 Nov 2026 01:48:48 +0100 Subject: [PATCH] Read a go download failure as a pin on a pull request head only when go does not know the revision, so a network failure is retaken and says its own cause Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL --- modules/mesh-build-go/cmd/mesh-build-go/pins.go | 2 +- .../mesh-build-go/cmd/mesh-build-go/versions.go | 12 ++++++++++++ .../cmd/mesh-build-go/versions_test.go | 14 ++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/pins.go b/modules/mesh-build-go/cmd/mesh-build-go/pins.go index 63294545..d8b2f05f 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/pins.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/pins.go @@ -106,7 +106,7 @@ func (m *Module) resolvePins(ctx context.Context, root, dir, failure string) (bo } progress := false for _, p := range forgePins(string(raw)) { - if !strings.Contains(failure, p.short) || strings.Contains(done, "replace "+p.module+" =>") { + if !unknownRevision(failure) || !strings.Contains(failure, p.short) || strings.Contains(done, "replace "+p.module+" =>") { continue } where, err := m.placePin(ctx, root, p, failure) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/versions.go b/modules/mesh-build-go/cmd/mesh-build-go/versions.go index a3d42471..d580c04f 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/versions.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/versions.go @@ -103,6 +103,11 @@ func (m *Module) takeVersion(ctx context.Context, root, dir string, tv *TakenVer if r.Status != 0 || r.Err != "" || info.Version == "" || info.Error != "" { // Not a commit Go can fetch: the head of a group's pull request (ADR 0573 ยง4), placed from the forge's heads. failure := strings.TrimSpace(info.Error + "\n" + r.Err + "\n" + r.Stderr) + if !unknownRevision(failure) { + // A download that failed for another cause (the forge or the resolver did not answer) says nothing of the pin: it + // fails with go's own words, and not as a kind the builder holds until the module changes (issue 1748). + return fmt.Errorf("downloading the asked version %s of %s failed (a download failure that may be retaken): %s", tv.Asked, tv.Package, causeLine(failure)) + } repo, sub, _ := strings.Cut(strings.TrimPrefix(tv.Package, forgePrefix), "/") p := pin{module: tv.Package, repo: repo, sub: sub, short: tv.Asked[:12]} pins.Lock() @@ -263,3 +268,10 @@ func comparePre(a, b string) int { } return strings.Compare(a, b) } + +// unknownRevision says whether a go failure is go not knowing the revision (cmd/go's "unknown revision" and the +// "invalid version" it wraps it in): the only failure that means a commit no tag or trunk holds, which may be the head of a +// pull request. Every other failure is the network's or the forge's. +func unknownRevision(failure string) bool { + return strings.Contains(failure, "unknown revision") || strings.Contains(failure, "invalid version") +} diff --git a/modules/mesh-build-go/cmd/mesh-build-go/versions_test.go b/modules/mesh-build-go/cmd/mesh-build-go/versions_test.go index e9fea937..00c82a64 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/versions_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/versions_test.go @@ -24,6 +24,7 @@ func TestAnAskedVersionIsWrittenIntoTheModfileWhateverGoModNames(t *testing.T) { name, asked, answer string failing bool built, said, edit string + failsWith string // a download failure that is not an unknown revision: the step fails with go's own words }{ {name: "a trunk commit newer than go.mod's", asked: trunk, answer: `{"Path":"` + sdk + `","Version":"v0.1.15-0.20261101000000-aaaaaaaaaaaa","Sum":"h1:zip=","GoModSum":"h1:mod="}`, @@ -34,6 +35,12 @@ func TestAnAskedVersionIsWrittenIntoTheModfileWhateverGoModNames(t *testing.T) { {name: "a group's head Go cannot fetch", asked: commitSHA, failing: true, answer: `{"Path":"` + sdk + `","Error":"invalid version: unknown revision ` + pinShort + `"}`, built: commitSHA, said: "placed from the pull request's head"}, + // The wording of go's errors: "unknown revision" is in cmd/go/internal/modfetch/coderepo_test.go; the lookup and + // connection texts are those of issue 1748's report and of the dial errors go prints for an unreachable forge. + {name: "a lookup that times out is no pin", asked: commitSHA, failing: true, failsWith: "i/o timeout", + answer: `{"Path":"` + sdk + `","Error":"git.novox.be/novox/mesh-sdk/go@` + commitSHA + `: dial tcp: lookup git.novox.be on 10.10.0.3:53: read udp 10.10.0.3:42292->10.10.0.3:53: i/o timeout"}`}, + {name: "a refused connection is no pin", asked: commitSHA, failing: true, failsWith: "connection refused", + answer: `{"Path":"` + sdk + `","Error":"git ls-remote -q origin in /tmp/gopath: dial tcp 10.10.0.1:443: connect: connection refused"}`}, } { t.Run(c.name, func(t *testing.T) { h, states := newPinHarness(t, pinnedGoMod, false, pullList) @@ -69,6 +76,13 @@ func TestAnAskedVersionIsWrittenIntoTheModfileWhateverGoModNames(t *testing.T) { t.Fatal(err) } st := states.waitEnd(t) + if c.failsWith != "" { + if st.State != delivery.StepFailed || !strings.Contains(st.Reason, c.failsWith) || strings.Contains(st.Reason, "no pull request head") || + !strings.Contains(st.Reason, "may be retaken") || delivery.FailedUntilChanged(st.Reason) || h.ran("ls-remote") { + t.Errorf("the download failure ended %s: %q (ls-remote ran: %v)", st.State, st.Reason, h.ran("ls-remote")) + } + return + } if st.State != delivery.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) }