Merge feat/r4e-builder into feat/r4e (R4e integration)
The checker's go.mod and go.sum conflicted on the mesh-sdk pin (checker lane 9cb4d59, builder lane e76a5a3): every module touched is pinned to the sdk lane's newest head d1af87a until the final SDK head.
This commit is contained in:
@@ -136,7 +136,7 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, bucket := range []string{delivery.HaveBucket, view.AssignmentsBucket, view.BuildsBucket, delivery.PresenceBucket, delivery.StuckBucket, delivery.CandidatesBucket, delivery.ModulesBucket, delivery.AsksBucket, delivery.AnswersBucket} {
|
||||
for _, bucket := range []string{delivery.HaveBucket, view.AssignmentsBucket, view.BuildsBucket, delivery.PresenceBucket, delivery.StuckBucket, delivery.CandidatesBucket, delivery.ModulesBucket, delivery.AsksBucket, delivery.AnswersBucket, delivery.BuilderBuildsBucket} {
|
||||
go follow(ctx, js, bucket, model, logger)
|
||||
}
|
||||
select {
|
||||
|
||||
@@ -3,7 +3,7 @@ module mesh-delivery-view
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021192148-78364e318bdc
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261022163107-d1af87a83a52
|
||||
github.com/nats-io/nats-server/v2 v2.11.17
|
||||
github.com/nats-io/nats.go v1.54.0
|
||||
)
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261019203925-84a764372337 h1:cZyFnvDiBpnNx8ifSUG9WA61OHsn7PC2ml2s4eD7AkA=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261019203925-84a764372337/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261019223929-58373d65b47a h1:Vjk2Kq+g/Q86N8CCHq3OatJIJ0JSy6Kh980ekGxNLmE=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261019223929-58373d65b47a/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261019230201-5786ba190c69 h1:kvtV/SPsdRVUL/BZ3xxGS6U8YrXy/t7TRBjVrD6VLw8=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261019230201-5786ba190c69/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020060201-88581d0acaef h1:xy3wuGWJpqMAXYdXolocYG6w9xnWqBltVUffoaziIKo=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261020060201-88581d0acaef/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021192148-78364e318bdc h1:ZJScJSnF6LgFl55/VJ9RT/lNroVWun469sXtx0nlVYw=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021192148-78364e318bdc/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261022163107-d1af87a83a52 h1:5k04XjpfYCq6j7rCM6Dy6FfrsBk5iUJlbwGf6WhUOUc=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261022163107-d1af87a83a52/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
|
||||
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
)
|
||||
|
||||
// I5 (issue 1851): from R4e the indexer writes the new form alone, and a module's fingerprint is built by the builder's key
|
||||
// of it; the page shows the indexer's fp2 against that key's state, or the reason it has none.
|
||||
|
||||
const fp2A = "src2:3333333333333333333333333333333333333333333333333333333333333333"
|
||||
|
||||
func builderKey(t *testing.T, module, fp2 string, b delivery.BuilderBuild) Entry {
|
||||
t.Helper()
|
||||
key, err := delivery.BuilderBuildKey(module, fp2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
data, err := delivery.EncodeBuilderBuild(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return Entry{Bucket: delivery.BuilderBuildsBucket, Key: key, Value: data, At: t0}
|
||||
}
|
||||
|
||||
func TestAFingerprintOfTheNewFormIsShownAgainstItsBuilderKey(t *testing.T) { // I5
|
||||
m := New()
|
||||
manifest := strings.Repeat("a", 64)
|
||||
d := "sha256:" + strings.Repeat("2", 64)
|
||||
fill(m,
|
||||
modEntry(t, "a", delivery.Module{FP2: fp2A, Manifest: manifest, Repository: "novox/mesh-delivery", Commit: hA}),
|
||||
builderKey(t, "a", fp2A, delivery.BuilderBuild{State: delivery.BuildDone, By: "shanks.mesh-delivery-builder", Manifest: manifest,
|
||||
Artifacts: []delivery.BuiltArtifact{{Name: "program", Kind: "bundle", Digest: d, Reference: "artifact-store://a/program/blobs/" + d}}}),
|
||||
modEntry(t, "f", delivery.Module{FP2: fp2A, Manifest: manifest, Repository: "novox/mesh-delivery", Commit: hA}),
|
||||
builderKey(t, "f", fp2A, delivery.BuilderBuild{State: delivery.BuildFailed, By: "shanks.mesh-delivery-builder", Manifest: manifest, Error: "not stored: program: 507"}),
|
||||
modEntry(t, "n", delivery.Module{FP2: fp2A, Manifest: manifest, Repository: "novox/mesh-delivery", Commit: hA}),
|
||||
modEntry(t, "r", delivery.Module{None2: "toolchain not yet reported", Repository: "novox/mesh-delivery", Commit: hA}))
|
||||
s := m.Snapshot()
|
||||
if r := fpRow(t, s, "a"); r.State != FPBuilt || r.Indexer != fp2A {
|
||||
t.Errorf("a = %+v, want built with the indexer's fp2", r)
|
||||
}
|
||||
if r := fpRow(t, s, "f"); r.State != FPBuildFailed || !strings.Contains(r.Reason, "not stored") {
|
||||
t.Errorf("f = %+v, want build failed with its error", r)
|
||||
}
|
||||
if r := fpRow(t, s, "n"); r.State != FPNoKey || r.Indexer != fp2A {
|
||||
t.Errorf("n = %+v, want no key", r)
|
||||
}
|
||||
if r := fpRow(t, s, "r"); r.State != FPNone || r.Reason != "toolchain not yet reported" {
|
||||
t.Errorf("r = %+v, want none with the new form's reason", r)
|
||||
}
|
||||
}
|
||||
@@ -146,6 +146,10 @@ func fingerprintText(s Snapshot) [][]string {
|
||||
what = f.Reason
|
||||
case FPNoBuild:
|
||||
what = "indexer " + f.Indexer + "; no successful trunk build recorded a fingerprint"
|
||||
case FPBuildFailed, FPBuilding:
|
||||
what = "indexer " + f.Indexer + "; builder: " + f.Reason
|
||||
case FPNoKey:
|
||||
what = "indexer " + f.Indexer + "; the builder holds no key of it"
|
||||
}
|
||||
out = append(out, []string{f.Module, f.State, what})
|
||||
}
|
||||
|
||||
@@ -101,6 +101,12 @@ const (
|
||||
FPDiffers = "differs"
|
||||
FPNone = "none"
|
||||
FPNoBuild = "no build"
|
||||
// The states of a fingerprint of the new form against the builder's key of it (I5, issue 1851): built (the key is done),
|
||||
// build failed (Reason is its error), building (queued, claimed or building; Reason says what it waits for) and no key.
|
||||
FPBuilt = "built"
|
||||
FPBuildFailed = "build failed"
|
||||
FPBuilding = "building"
|
||||
FPNoKey = "no key"
|
||||
)
|
||||
|
||||
// FingerprintRow compares the indexer's fingerprint of a module at a trunk merge with the source fingerprint its newest
|
||||
@@ -147,6 +153,7 @@ type Model struct {
|
||||
builds map[string]buildEntry // by <module>.build.<id>
|
||||
groups map[string]groupEntry // the indexer's candidates, by group
|
||||
modules map[string]moduleEntry // the indexer's modules, by module
|
||||
keys map[string]keyEntry // the builder's build keys, by <module>.<fingerprint>
|
||||
asks map[string]askRecord // the gate's asks, by key
|
||||
answers map[string]string // by key: the router id of the asking the teller's answer is for ("" when unreadable)
|
||||
newest map[string]string // module -> id
|
||||
@@ -209,6 +216,11 @@ type groupEntry struct {
|
||||
err string
|
||||
}
|
||||
|
||||
type keyEntry struct {
|
||||
value delivery.BuilderBuild
|
||||
err string
|
||||
}
|
||||
|
||||
type moduleEntry struct {
|
||||
value delivery.Module
|
||||
err string
|
||||
@@ -233,7 +245,7 @@ type nodeEntry struct {
|
||||
|
||||
// New is an empty model.
|
||||
func New() *Model {
|
||||
return &Model{assigns: map[string]assignment{}, builds: map[string]buildEntry{}, groups: map[string]groupEntry{}, modules: map[string]moduleEntry{}, asks: map[string]askRecord{}, answers: map[string]string{}, newest: map[string]string{},
|
||||
return &Model{assigns: map[string]assignment{}, builds: map[string]buildEntry{}, groups: map[string]groupEntry{}, modules: map[string]moduleEntry{}, keys: map[string]keyEntry{}, asks: map[string]askRecord{}, answers: map[string]string{}, newest: map[string]string{},
|
||||
haves: map[string]haveEntry{}, nodes: map[string]nodeEntry{},
|
||||
presence: map[string]presenceEntry{}, stuck: map[string]stuckEntry{}}
|
||||
}
|
||||
@@ -321,6 +333,17 @@ func (m *Model) Apply(e Entry) {
|
||||
id, _, _ = strings.Cut(a.Warrant, "@")
|
||||
}
|
||||
m.answers[e.Key] = id
|
||||
case delivery.BuilderBuildsBucket:
|
||||
if e.Deleted {
|
||||
delete(m.keys, e.Key)
|
||||
return
|
||||
}
|
||||
b, err := delivery.DecodeBuilderBuild(e.Value)
|
||||
if err != nil {
|
||||
m.keys[e.Key] = keyEntry{err: err.Error()}
|
||||
return
|
||||
}
|
||||
m.keys[e.Key] = keyEntry{value: b}
|
||||
case BuildsBucket:
|
||||
module, rest, ok := strings.Cut(e.Key, ".")
|
||||
if !ok {
|
||||
@@ -525,6 +548,11 @@ func (m *Model) fingerprintRows() []FingerprintRow {
|
||||
continue
|
||||
}
|
||||
row := FingerprintRow{Module: name, Repository: mod.value.Repository, Commit: mod.value.Commit}
|
||||
if mod.value.FP2 != "" || mod.value.None2 != "" {
|
||||
// The new form (R4e): the indexer's fp2 against the builder's key of it.
|
||||
out = append(out, m.newFormRow(name, row, mod.value))
|
||||
continue
|
||||
}
|
||||
b, hasBuild := newest[name]
|
||||
switch {
|
||||
case mod.value.None != "":
|
||||
@@ -542,6 +570,35 @@ func (m *Model) fingerprintRows() []FingerprintRow {
|
||||
return out
|
||||
}
|
||||
|
||||
// newFormRow is a module's row of the new form: none with its reason, or its fp2 against the state of the builder's key
|
||||
// of it (I5, issue 1851; the build records name no fingerprint of the new form).
|
||||
func (m *Model) newFormRow(name string, row FingerprintRow, v delivery.Module) FingerprintRow {
|
||||
if v.FP2 == "" {
|
||||
row.State, row.Reason = FPNone, v.None2
|
||||
return row
|
||||
}
|
||||
row.Indexer = v.FP2
|
||||
key, err := delivery.BuilderBuildKey(name, v.FP2)
|
||||
if err != nil {
|
||||
row.State, row.Reason = FPNoKey, err.Error()
|
||||
return row
|
||||
}
|
||||
k, ok := m.keys[key]
|
||||
switch {
|
||||
case !ok:
|
||||
row.State = FPNoKey
|
||||
case k.err != "":
|
||||
row.State, row.Reason = FPBuildFailed, "the key cannot be read: "+k.err
|
||||
case k.value.State == delivery.BuildDone:
|
||||
row.State, row.Build = FPBuilt, v.FP2
|
||||
case k.value.State == delivery.BuildFailed:
|
||||
row.State, row.Reason = FPBuildFailed, k.value.Error
|
||||
default:
|
||||
row.State, row.Reason = FPBuilding, strings.TrimSpace(k.value.State+" "+k.value.Waits)
|
||||
}
|
||||
return row
|
||||
}
|
||||
|
||||
// count is the number of items of a carried JSON array or object, and 0 for anything else.
|
||||
func count(raw json.RawMessage) int {
|
||||
var list []json.RawMessage
|
||||
|
||||
Reference in New Issue
Block a user