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
This commit is contained in:
2026-11-02 12:29:56 +01:00
parent c4a6452f21
commit ab610ffed4
3 changed files with 27 additions and 1 deletions
@@ -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)
@@ -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")
}
@@ -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)
}