Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06cdac97e3 | ||
|
|
82aaae846e |
@@ -113,7 +113,8 @@ func (m *Module) fetch(ctx context.Context, args map[string]any) (res any, err e
|
||||
}
|
||||
}
|
||||
}()
|
||||
return m.fetchInto(ctx, req, id, siblings)
|
||||
res, err = m.fetchInto(ctx, req, id, siblings)
|
||||
return res, retakeable(err) // a network failure is a retakeable one (issue 1748)
|
||||
}
|
||||
|
||||
func (m *Module) fetchInto(ctx context.Context, req sdkstep.FetchRequest, id string, siblings []siblingArg) (any, error) {
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
"git.novox.be/novox/mesh-sdk/go/forgekey"
|
||||
)
|
||||
|
||||
@@ -140,7 +141,7 @@ func (m *Module) placePin(ctx context.Context, root string, p pin, failure strin
|
||||
r := m.Run(ctx, []string{"GIT_TERMINAL_PROMPT=0"}, "git", "-c", "credential.helper=", "ls-remote", m.remote(repository), "refs/pull/*/head")
|
||||
if r.Status != 0 || r.Err != "" {
|
||||
// The forge did not answer: retaken, with its own cause, never held as a refusal until the module changes (issue 1748).
|
||||
return "", fmt.Errorf("the pin of %s at commit %s: listing the pull requests of %s failed (a download failure that may be retaken): %s", p.module, p.short, repository, forgekey.Said(r.Err+"\n"+r.Stderr))
|
||||
return "", fmt.Errorf(delivery.Retake+"the pin of %s at commit %s: listing the pull requests of %s failed (a download failure, taken again by the builder): %s", p.module, p.short, repository, forgekey.Said(r.Err+"\n"+r.Stderr))
|
||||
}
|
||||
commit, ref := "", ""
|
||||
for _, l := range strings.Split(r.Stdout, "\n") {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
)
|
||||
|
||||
// networkWords are what a failed lookup, connection or transfer says in Go's, git's and the resolver's words: a failure of
|
||||
// the network or of the forge that passes by itself (issue 1748), not of the source built.
|
||||
var networkWords = []string{
|
||||
"i/o timeout", "no such host", "could not resolve host", "temporary failure in name resolution", "server misbehaving",
|
||||
"connection refused", "connection reset", "tls handshake timeout", "network is unreachable", "unexpected eof", "http2: server sent goaway",
|
||||
}
|
||||
|
||||
// networkFailure says whether a failure of a download or a fetch is the network's: its words are one of networkWords and
|
||||
// it is not go not knowing the revision (unknownRevision, a pin on no head), which waits for another fingerprint.
|
||||
func networkFailure(failure string) bool {
|
||||
if unknownRevision(failure) {
|
||||
return false
|
||||
}
|
||||
low := strings.ToLower(failure)
|
||||
for _, w := range networkWords {
|
||||
if strings.Contains(low, w) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// retakeable opens a network failure of the fetch step with delivery.Retake, so the builder takes the key again after a
|
||||
// backoff (delivery.Retakeable, issue 1748); any other error, one that opens with a prefix already included, is as it was.
|
||||
func retakeable(err error) error {
|
||||
if err == nil || strings.HasPrefix(err.Error(), delivery.Retake) || !networkFailure(err.Error()) {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("%s%w", delivery.Retake, err)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
)
|
||||
|
||||
// 1748/AC2: a download or a fetch that fails on the network ends with an error that opens with the retake prefix; a
|
||||
// compile error, a failing test and an unknown revision (a pin on no head) do not.
|
||||
func TestANetworkFailureOfTheFetchOpensWithTheRetakePrefix(t *testing.T) {
|
||||
for _, c := range []struct {
|
||||
name, failure string
|
||||
retake bool
|
||||
}{
|
||||
{"a lookup that times out", "go mod download in .: git.novox.be/novox/mesh-sdk/go@v1: 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", true},
|
||||
{"a refused connection", "git ls-remote -q origin: dial tcp 10.10.0.1:443: connect: connection refused", true},
|
||||
{"a forge that cannot be resolved", "fatal: unable to access the forge: Could not resolve host: git.novox.be", true},
|
||||
{"an unknown revision", "invalid version: unknown revision abcdef123456", false},
|
||||
{"an unknown revision on a cut network is still one go knows", "unknown revision abcdef123456: i/o timeout", false},
|
||||
{"a compile error", "go build of tool: ./main.go:3:1: undefined: x", false},
|
||||
{"a failing test", "go test ./...: FAIL: TestX", false},
|
||||
} {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
got := retakeable(errors.New(c.failure))
|
||||
if has := strings.HasPrefix(got.Error(), delivery.Retake); has != c.retake {
|
||||
t.Fatalf("retakeable(%q) = %q", c.failure, got)
|
||||
}
|
||||
if c.retake && (!delivery.Retakeable(got.Error()) || !strings.Contains(got.Error(), c.failure)) {
|
||||
t.Errorf("%q does not keep the cause or is not Retakeable", got)
|
||||
}
|
||||
})
|
||||
}
|
||||
if retakeable(nil) != nil {
|
||||
t.Error("retakeable(nil) is an error")
|
||||
}
|
||||
if once := retakeable(errors.New(delivery.Retake + "connection refused")); strings.Count(once.Error(), delivery.Retake) != 1 {
|
||||
t.Errorf("the prefix was added twice: %q", once)
|
||||
}
|
||||
}
|
||||
@@ -113,7 +113,7 @@ func (m *Module) takeVersion(ctx context.Context, root, dir string, tv *TakenVer
|
||||
pins.Unlock()
|
||||
// On no head, and go failed for another cause (the forge or the resolver did not answer): 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))
|
||||
return fmt.Errorf(delivery.Retake+"downloading the asked version %s of %s failed (a download failure, taken again by the builder): %s", tv.Asked, tv.Package, causeLine(failure))
|
||||
}
|
||||
if err == nil {
|
||||
err = m.replaceInModfile(dir, tv.Package, where)
|
||||
|
||||
@@ -92,7 +92,7 @@ func TestAnAskedVersionIsWrittenIntoTheModfileWhateverGoModNames(t *testing.T) {
|
||||
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) {
|
||||
!strings.HasPrefix(st.Reason, delivery.Retake) || delivery.FailedUntilChanged(st.Reason) {
|
||||
t.Errorf("the download failure ended %s: %q", st.State, st.Reason)
|
||||
}
|
||||
return
|
||||
|
||||
@@ -4,7 +4,7 @@ go 1.26.0
|
||||
|
||||
require (
|
||||
git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep v0.0.0
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261102191058-f02f142af128
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104214149-0d97c09c49b4
|
||||
github.com/distribution/distribution/v3 v3.1.2
|
||||
github.com/nats-io/nats-server/v2 v2.11.17
|
||||
github.com/nats-io/nats.go v1.54.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261102191058-f02f142af128 h1:aI1DhZAuqVBXbybSqhLNOGX5rUOrn9T0cHNCDUQF7IQ=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261102191058-f02f142af128/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104214149-0d97c09c49b4 h1:K2niszrlnJ7JMiXI6xg4gG90YCd/tqNLGBvujLInI48=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104214149-0d97c09c49b4/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI=
|
||||
github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
||||
|
||||
Reference in New Issue
Block a user