diff --git a/contracts/go/clients/meshcatalogclient/candidate.go b/contracts/go/clients/meshcatalogclient/candidate.go index 31a5db92..41d60d5a 100644 --- a/contracts/go/clients/meshcatalogclient/candidate.go +++ b/contracts/go/clients/meshcatalogclient/candidate.go @@ -4,6 +4,7 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "regexp" "sort" "strings" @@ -60,3 +61,14 @@ func ParseCandidatesKey(key string) (string, error) { } return group, nil } + +var tryGroupOK = regexp.MustCompile(`^try-[0-9]{1,20}$`) + +// IsTryGroup says a candidates key is the group of a whole try, try-, which is also the try's id: the indexer makes the +// candidate of a try's group from its previews, and the checker judges it by its try, never as a pull request's check. +func IsTryGroup(key string) bool { return tryGroupOK.MatchString(key) } + +// NoneNoPreview is why a candidate's touched module has no fingerprint of the new form yet: its merge preview is not +// computed. The indexer writes it; a reader that waits for a try's candidate takes one that still says it as not yet the +// candidate of the heads previewed. +const NoneNoPreview = "no merge preview is computed" diff --git a/contracts/seats/mesh-delivery-checker/seat.json b/contracts/seats/mesh-delivery-checker/seat.json index 84e2f953..90f99cc3 100644 --- a/contracts/seats/mesh-delivery-checker/seat.json +++ b/contracts/seats/mesh-delivery-checker/seat.json @@ -8,7 +8,7 @@ "verbs": [ { "name": "try", - "description": "Try pushed heads before their pull requests are opened: the checker judges them as it judges a delivery group's pull requests, each member merged onto its trunk, its unit and integration levels through the build modules, then the members' manifests, the module graph and the composition on every placed node, and owes the forge nothing. Name the group's members (each a repository and the exact commit), or one repository and its head for a try of one member. Answers the try's id at once; try-read reads where it stands. The same members at the same commits, in any order, are the answer to a second ask while that try waits or runs; at most 4 wait or run at once, mesh-wide.", + "description": "Try pushed heads before their pull requests are opened: the checker judges them as it judges a delivery group's pull requests, each member merged onto its trunk, its unit and integration levels through the build modules, then the members' manifests, the module graph and the composition on every placed node, and owes the forge nothing. Name the group's members (each a repository and the exact commit), or one repository and its head for a try of one member. Answers the try's id at once; try-read reads where it stands. The same members at the same commits, in any order, are the answer to a second ask while that try waits or runs; at most 4 run on a build node, and 8 wait for one, mesh-wide.", "optional": true, "replaces": [ "sh merge-check.sh", diff --git a/sdk/tryevent/tryevent.go b/modules/mesh-delivery-checker/checkermsg/checkermsg.go similarity index 64% rename from sdk/tryevent/tryevent.go rename to modules/mesh-delivery-checker/checkermsg/checkermsg.go index 31bff7f6..37db5412 100644 --- a/sdk/tryevent/tryevent.go +++ b/modules/mesh-delivery-checker/checkermsg/checkermsg.go @@ -1,13 +1,15 @@ -// Package tryevent is what the checker says on its stream checks when a whole try (a try of a delivery group, not narrowed +// Package checkermsg is the checker's own published layouts (as forgemsg is the forge bridge's): the bodies of its events on the +// stream checks and the answer of its tool checker_tries. It is what the checker says on its stream checks when a whole try (a try of a delivery group, not narrowed // to a level or to some tests) starts and ends (issue 1921), and what the indexer, which hears it, reads: a try has no pull // request, so the indexer writes the candidate of its group from the members at their commits, and deletes it at the end. // The events carry the members, so no part reads the checker's state. -package tryevent +package checkermsg import ( "encoding/json" "fmt" - "regexp" + + "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" ) // The events of the checker's stream checks. @@ -16,17 +18,6 @@ const ( Ended = "try.ended" ) -// IDOK is the shape of a try's id, which is also the name of its group (the key of its candidate). -var IDOK = regexp.MustCompile(`^try-[0-9]{1,20}$`) - -// IsGroup says a candidates key is the group of a try: the one definition the checker and the indexer share. -func IsGroup(key string) bool { return IDOK.MatchString(key) } - -// NoneNoPreview is why a candidate's touched module has no fingerprint of the new form yet: its merge preview is not -// computed. The indexer writes it; the checker, which waits for a try's candidate, takes a candidate that still says it as -// not yet the candidate of the heads previewed. One definition for both. -const NoneNoPreview = "no merge preview is computed" - // Member is one repository of the try: the exact commit and the trunk commit it is merged onto. type Member struct { Repository string `json:"repository"` @@ -47,7 +38,7 @@ func Decode(event string, body []byte) (Event, error) { if err := json.Unmarshal(body, &e); err != nil { return e, err } - if !IDOK.MatchString(e.ID) { + if !meshcatalogclient.IsTryGroup(e.ID) { return e, fmt.Errorf("%q is not a try's id, try-", e.ID) } if event == Started && len(e.Members) == 0 { diff --git a/modules/mesh-delivery-checker/checkermsg/go.mod b/modules/mesh-delivery-checker/checkermsg/go.mod new file mode 100644 index 00000000..4613592a --- /dev/null +++ b/modules/mesh-delivery-checker/checkermsg/go.mod @@ -0,0 +1,5 @@ +module git.novox.be/novox/mesh-delivery/modules/mesh-delivery-checker/checkermsg + +go 1.26.0 + +require git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient v0.0.0-00010101000000-000000000000 diff --git a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker-tools/main.go b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker-tools/main.go index ade6e323..f89671b7 100644 --- a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker-tools/main.go +++ b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker-tools/main.go @@ -114,7 +114,7 @@ func TryTools(tr Trying) []stdio.Tool { "the first. A try owes the forge nothing (no status, no Approve asked) and writes no verdict of a pull request; what its passing levels prove is kept, so a pull request's " + "check of the same heads on the same trunk runs only what the try did not pass. A try narrowed to a level or to some tests judges only those, no manifest and no composition, and keeps nothing of tests. " + "Answers the try's id at once; " + check.TryReadTool + " reads where it stands, " + check.TryEndTool + " ends it by hand. A try of the same commits that waits or runs is the answer to a second ask " + - "(whatever the order of the members); a new try is refused while 4 tries run on a build node or 8 wait for one, mesh-wide. A repository the checker checks no level of (one whose trunk the gate does not name) " + + "(whatever the order of the members); at most 4 run on a build node, and 8 wait for one, mesh-wide. A repository the checker checks no level of (one whose trunk the gate does not name) " + "is refused. A try whose ask no build node took within the step bound ends as error; its ask stays in the build seat's stream and may still run later, judged by nobody (issue 734).", Input: map[string]any{"type": "object", "properties": map[string]any{ "members": map[string]any{"type": "array", "description": "the group: one repository at most once, each at the exact commit asked and the trunk commit it is merged onto", diff --git a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker-tools/main_test.go b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker-tools/main_test.go index 90e3c401..d3cb7e10 100644 --- a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker-tools/main_test.go +++ b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker-tools/main_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "git.novox.be/novox/mesh-delivery/sdk/tryevent" + "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-checker/checkermsg" "mesh-delivery-checker/internal/check" ) @@ -137,6 +137,10 @@ func TestTheTryToolsAskAndReadATry(t *testing.T) { // ADR 0501 §5, the agreed i t.Errorf("the verb try serves no %q, which the tool takes", name) } } + const limit = "at most 4 run on a build node, and 8 wait for one, mesh-wide" + if !strings.Contains(v.Description, limit) || !strings.Contains(verbs[0].Description, limit) { + t.Errorf("the verb and the tool state one limit %q", limit) + } if len(v.Input.Required) != 0 || !strings.Contains(v.Description, "members") { t.Errorf("the verb try requires %v and says %q: want members as an alternative to one repository and head", v.Input.Required, v.Description) } @@ -171,7 +175,7 @@ func TestTheTryToolsAskAndReadATry(t *testing.T) { // ADR 0501 §5, the agreed i } if open := OpenTriesTools(Trying{Tries: store}); len(open) != 1 || open[0].Name != check.TriesTool || !strings.Contains(open[0].Description, "try.started") { t.Errorf("open tries tool = %+v", open) - } else if out, err := open[0].Run(nil); err != nil || len(out.(map[string]any)["tries"].([]tryevent.Open)) != 2 { + } else if out, err := open[0].Run(nil); err != nil || len(out.(map[string]any)["tries"].([]checkermsg.Open)) != 2 { t.Errorf("open tries = %v, %v, want the two tries asked", out, err) } // Issue 734: a try whose ask was lost is ended by hand with why, and its head is asked anew. diff --git a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/main.go b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/main.go index 2125ef8e..3806a96c 100644 --- a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/main.go +++ b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/main.go @@ -30,8 +30,8 @@ import ( "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" + "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-checker/checkermsg" "git.novox.be/novox/mesh-delivery/sdk/buildstep" - "git.novox.be/novox/mesh-delivery/sdk/tryevent" "git.novox.be/novox/mesh-sdk/go/announce" "git.novox.be/novox/mesh-sdk/go/process" "git.novox.be/novox/mesh-sdk/go/seatlist" @@ -254,7 +254,7 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro // The tries (ADR 0501 §5) are judged by the same judge, held by the same deliveries. tryer := &check.Tryer{Tries: kvStore{buckets[check.TriesBucket]}, Bound: checkBound, NotTaken: stepBound, Logf: logger.Printf, // A whole try's start and end are said on the stream checks, for the indexer to write and delete the candidate of its group. - Say: func(ctx context.Context, event string, body tryevent.Event) error { + Say: func(ctx context.Context, event string, body checkermsg.Event) error { data, _ := json.Marshal(body) _, err := js.Publish(ctx, eventSubject(event), data, jetstream.WithRetryAttempts(10), jetstream.WithRetryWait(time.Second)) return err diff --git a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/seatlist_test.go b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/seatlist_test.go index 8ae0bda4..6090e162 100644 --- a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/seatlist_test.go +++ b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/seatlist_test.go @@ -20,7 +20,9 @@ func (b *silentThenAnswering) Ask(string, any) (json.RawMessage, error) { return json.RawMessage(`{"revision":1,"seats":[]}`), nil } -func (b *silentThenAnswering) Subscribe(string, func(string, json.RawMessage) error) error { return nil } +func (b *silentThenAnswering) Subscribe(string, func(string, json.RawMessage) error) error { + return nil +} // A seat that spoke before the checker's consumer existed is read when the hub is heard (ADR 0636 §1). func TestTheSeatListIsReadWhenTheHubIsHeard(t *testing.T) { diff --git a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/try_candidates.go b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/try_candidates.go index 0fbc8448..1e8de96e 100644 --- a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/try_candidates.go +++ b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/try_candidates.go @@ -9,7 +9,6 @@ import ( "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" - "git.novox.be/novox/mesh-delivery/sdk/tryevent" ) // tryCandidates answers the indexer's candidate of a try's group (novox/hq ADR 0593 §7, issue 1921): the candidate the @@ -60,7 +59,7 @@ func (t tryCandidates) TryCandidate(ctx context.Context, group, heads string, bo func waitsOnPreview(c meshcatalog.CandidatesByGroupValue) bool { for _, p := range c.Pulls { for _, m := range p.Fps { - if m.None2 == tryevent.NoneNoPreview { + if m.None2 == meshcatalogclient.NoneNoPreview { return true } } diff --git a/modules/mesh-delivery-checker/go.mod b/modules/mesh-delivery-checker/go.mod index 6ffedb90..86dfd03e 100644 --- a/modules/mesh-delivery-checker/go.mod +++ b/modules/mesh-delivery-checker/go.mod @@ -44,6 +44,10 @@ replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun require git.novox.be/novox/mesh-delivery/sdk v0.0.0-00010101000000-000000000000 +require git.novox.be/novox/mesh-delivery/modules/mesh-delivery-checker/checkermsg v0.0.0-00010101000000-000000000000 + +replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-checker/checkermsg => ./checkermsg + require ( ) diff --git a/modules/mesh-delivery-checker/internal/check/read.go b/modules/mesh-delivery-checker/internal/check/read.go index 1e047da4..3cab1a6c 100644 --- a/modules/mesh-delivery-checker/internal/check/read.go +++ b/modules/mesh-delivery-checker/internal/check/read.go @@ -15,7 +15,6 @@ import ( "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "git.novox.be/novox/mesh-delivery/sdk/buildstep" - "git.novox.be/novox/mesh-delivery/sdk/tryevent" ) // The read tools (novox/hq ADR 0484 clauses 8 and 13, issue 1686): what the checker stored, as stored, with the line of the @@ -170,7 +169,7 @@ func (r Reader) Pull(repository string, number int) (VerdictRead, error) { if err != nil { return VerdictRead{}, err } - keys = slices.DeleteFunc(keys, tryevent.IsGroup) + keys = slices.DeleteFunc(keys, meshcatalogclient.IsTryGroup) sort.Strings(keys) keys, cut := capKeys(keys, "") // The candidates are read in batches, each in parallel and taken in key order, so the read stops at the batch that holds it. @@ -451,7 +450,7 @@ func (r Reader) Status() (Status, error) { if err != nil { return st, err } - keys = slices.DeleteFunc(keys, tryevent.IsGroup) // a try's candidate is judged by its try, never as a check + keys = slices.DeleteFunc(keys, meshcatalogclient.IsTryGroup) // a try's candidate is judged by its try, never as a check sort.Strings(keys) total := len(keys) keys, cut := capKeys(keys, "") diff --git a/modules/mesh-delivery-checker/internal/check/try.go b/modules/mesh-delivery-checker/internal/check/try.go index 07197275..e5abd0f2 100644 --- a/modules/mesh-delivery-checker/internal/check/try.go +++ b/modules/mesh-delivery-checker/internal/check/try.go @@ -14,12 +14,13 @@ import ( "time" "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient" + "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshdeliverycheckerclient" "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshdeliveryclient" "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdeliverychecker" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun" + "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-checker/checkermsg" "git.novox.be/novox/mesh-delivery/sdk/buildstep" - "git.novox.be/novox/mesh-delivery/sdk/tryevent" "git.novox.be/novox/mesh-sdk/go/keys" ) @@ -242,7 +243,7 @@ func DecodeTry(raw []byte) (Try, error) { if err := json.Unmarshal(raw, &t); err != nil { return Try{}, fmt.Errorf("not a try: %w", err) } - if !tryevent.IDOK.MatchString(t.ID) || t.Repository == "" || t.Head == "" || t.Trunk == "" { + if !meshcatalogclient.IsTryGroup(t.ID) || t.Repository == "" || t.Head == "" || t.Trunk == "" { return Try{}, errors.New("not a try: it names no id, repository, head or trunk") } t.Members = t.MembersOf() @@ -421,7 +422,7 @@ func AskTry(store TryStore, trunks map[string]string, a TryAsk, now time.Time) ( // ReadTry is a try's value, as stored. func ReadTry(store TryStore, id string) (json.RawMessage, error) { - if !tryevent.IDOK.MatchString(id) { + if !meshcatalogclient.IsTryGroup(id) { return nil, fmt.Errorf("%q is not a try's id, try-", id) } raw, err := store.Get(id) @@ -443,7 +444,7 @@ type TryEnder interface { // EndTry ends a try that waits or runs as error, saying why and that it was ended by hand (issue 734): its place is // free at once, and the next checker_try of its head asks anew. A try that ended already is refused, naming its end. func EndTry(store TryEnder, id, why string, now time.Time) (Try, error) { - if !tryevent.IDOK.MatchString(id) { + if !meshcatalogclient.IsTryGroup(id) { return Try{}, fmt.Errorf("%q is not a try's id, try-", id) } why = strings.TrimSpace(why) @@ -530,10 +531,10 @@ type Tryer struct { Now func() time.Time Logf func(format string, args ...any) - // Say publishes an event of the checker's stream (tryevent.Started, tryevent.Ended) with its body; nil says nothing. The + // Say publishes an event of the checker's stream (checkermsg.Started, checkermsg.Ended) with its body; nil says nothing. The // indexer, which hears them, writes and deletes the candidate of a whole try's group. // It answers the publish's error, nil only when the stream acknowledged it: an end not acknowledged is said again. - Say func(ctx context.Context, event string, body tryevent.Event) error + Say func(ctx context.Context, event string, body checkermsg.Event) error mu sync.Mutex ending map[string]bool // tries whose end is being said now @@ -645,11 +646,11 @@ func (tr *Tryer) run(ctx context.Context, key string) { } progress := &tryWriter{tr: tr, ctx: ctx, key: key, t: t, rev: rev} if t.Told { - started := tryevent.Event{ID: key} + started := checkermsg.Event{ID: key} for _, m := range t.MembersOf() { - started.Members = append(started.Members, tryevent.Member{Repository: m.Repository, Head: m.Head, Trunk: m.Trunk}) + started.Members = append(started.Members, checkermsg.Member{Repository: m.Repository, Head: m.Head, Trunk: m.Trunk}) } - tr.say(ctx, tryevent.Started, started) + tr.say(ctx, checkermsg.Started, started) } cs := TryCase(key, t, progress.heard) cs.Wait = progress.waiting @@ -736,7 +737,7 @@ func (tr *Tryer) sendEnd(ctx context.Context, key string) { if err != nil || !t.Over() || !t.Told { return } - if tr.say(ctx, tryevent.Ended, tryevent.Event{ID: key, State: t.State}) != nil { + if tr.say(ctx, checkermsg.Ended, checkermsg.Event{ID: key, State: t.State}) != nil { return // not acknowledged: Told stays, and the next Put or Reconsider says the end again } t.Told = false @@ -750,7 +751,7 @@ func (tr *Tryer) sendEnd(ctx context.Context, key string) { } // say publishes a try event; a failure is said in the log (the indexer finds the open tries again at its start). -func (tr *Tryer) say(ctx context.Context, event string, body tryevent.Event) error { +func (tr *Tryer) say(ctx context.Context, event string, body checkermsg.Event) error { if tr.Say == nil { return nil } @@ -764,7 +765,7 @@ func (tr *Tryer) say(ctx context.Context, event string, body tryevent.Event) err // OpenTries are every try that waits or runs now: what checker_tries answers, so a part that missed an event (the indexer at // its start) finds them without reading the checker's state. All the keys are read (an old open try is as open as a new one), in // parallel. -func OpenTries(store TryStore) ([]tryevent.Open, error) { +func OpenTries(store TryStore) ([]checkermsg.Open, error) { keys, err := store.Keys() if err != nil { return nil, fmt.Errorf("the tries cannot be listed: %w", err) @@ -775,7 +776,7 @@ func OpenTries(store TryStore) ([]tryevent.Open, error) { } return keys[i] > keys[j] }) - found := make([]*tryevent.Open, len(keys)) + found := make([]*checkermsg.Open, len(keys)) if err := parallel(len(keys), func(i int) error { raw, err := store.Get(keys[i]) if err != nil || len(raw) == 0 { @@ -785,16 +786,16 @@ func OpenTries(store TryStore) ([]tryevent.Open, error) { if err != nil || t.Over() { return nil } - o := tryevent.Open{ID: t.ID, State: t.State, Whole: (&TryOptions{Level: t.Level, Run: t.Tests}).Whole()} + o := checkermsg.Open{ID: t.ID, State: t.State, Whole: (&TryOptions{Level: t.Level, Run: t.Tests}).Whole()} for _, m := range t.MembersOf() { - o.Members = append(o.Members, tryevent.Member{Repository: m.Repository, Head: m.Head, Trunk: m.Trunk}) + o.Members = append(o.Members, checkermsg.Member{Repository: m.Repository, Head: m.Head, Trunk: m.Trunk}) } found[i] = &o return nil }); err != nil { return nil, err } - var out []tryevent.Open + var out []checkermsg.Open for _, o := range found { if o != nil { out = append(out, *o) diff --git a/modules/mesh-delivery-checker/internal/check/try_test.go b/modules/mesh-delivery-checker/internal/check/try_test.go index 2210aec5..f46e3893 100644 --- a/modules/mesh-delivery-checker/internal/check/try_test.go +++ b/modules/mesh-delivery-checker/internal/check/try_test.go @@ -12,10 +12,11 @@ import ( "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient" "git.novox.be/novox/mesh-contracts/placement/go/seats/meshwants" + "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshdeliverycheckerclient" "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" + "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-checker/checkermsg" "git.novox.be/novox/mesh-delivery/sdk/buildstep" - "git.novox.be/novox/mesh-delivery/sdk/tryevent" ) // memTries is the tries state as the tools see it, over a memKV. @@ -93,7 +94,7 @@ func TestATryIsAskedQueuedOncePerHeadAndAtMostFourAtOnce(t *testing.T) { // ADR if open, err := OpenTries(store); err != nil || len(open) != 2 || !open[0].Whole || len(open[1].Members) != 2 && len(open[0].Members) != 2 { t.Errorf("open tries = %+v, %v, want the two queued", open, err) } - if !tryevent.IsGroup(gid) || tryevent.IsGroup("feat/x") || tryevent.IsGroup("fix/1921-try-1") { + if !meshcatalogclient.IsTryGroup(gid) || meshcatalogclient.IsTryGroup("feat/x") || meshcatalogclient.IsTryGroup("fix/1921-try-1") { t.Errorf("which candidates keys are a try's group: %s is, a branch is not", gid) } onNode := func(i int) Try { @@ -192,7 +193,7 @@ func TestATryIsJudgedAsAGroupsCheckAndOwesTheForgeNothing(t *testing.T) { // ADR var waiting string cands.during = func() { waiting = readTry(t, kv, id).Waiting } // ADR 0639 §5: the stored try says what it waits for var said []string - tr := &Tryer{Tries: written, Judge: b.ex, Say: func(_ context.Context, event string, e tryevent.Event) error { + tr := &Tryer{Tries: written, Judge: b.ex, Say: func(_ context.Context, event string, e checkermsg.Event) error { said = append(said, fmt.Sprintf("%s %s %d %s", event, e.ID, len(e.Members), e.State)) return nil }} @@ -203,18 +204,18 @@ func TestATryIsJudgedAsAGroupsCheckAndOwesTheForgeNothing(t *testing.T) { // ADR if len(said) != 2 || said[0] != "try.started "+id+" 2 " || said[1] != "try.ended "+id+" 0 "+TryPass { t.Errorf("events = %v, want the start with 2 members and the end", said) } - // What the indexer reads: tryevent.Decode accepts the events as said and refuses a body that is no try's. + // What the indexer reads: checkermsg.Decode accepts the events as said and refuses a body that is no try's. for _, row := range []struct { name, event, body string ok bool }{ - {"a start with its members", tryevent.Started, `{"id":"` + id + `","members":[{"repository":"` + repoA + `","head":"` + head1 + `","trunk":"` + trunkA + `"}]}`, true}, - {"an end with its state", tryevent.Ended, `{"id":"` + id + `","state":"pass"}`, true}, - {"an id that is no try's", tryevent.Ended, `{"id":"pull-7","state":"pass"}`, false}, - {"a start with no member", tryevent.Started, `{"id":"` + id + `"}`, false}, - {"a body that is no JSON", tryevent.Ended, `try-7`, false}, + {"a start with its members", checkermsg.Started, `{"id":"` + id + `","members":[{"repository":"` + repoA + `","head":"` + head1 + `","trunk":"` + trunkA + `"}]}`, true}, + {"an end with its state", checkermsg.Ended, `{"id":"` + id + `","state":"pass"}`, true}, + {"an id that is no try's", checkermsg.Ended, `{"id":"pull-7","state":"pass"}`, false}, + {"a start with no member", checkermsg.Started, `{"id":"` + id + `"}`, false}, + {"a body that is no JSON", checkermsg.Ended, `try-7`, false}, } { - if e, err := tryevent.Decode(row.event, []byte(row.body)); (err == nil) != row.ok || (row.ok && e.ID != id) { + if e, err := checkermsg.Decode(row.event, []byte(row.body)); (err == nil) != row.ok || (row.ok && e.ID != id) { t.Errorf("Decode of %s = %+v, %v, want ok=%v", row.name, e, err, row.ok) } } @@ -294,7 +295,7 @@ func TestATryOfOneLevelAndSomeTestsRunsThemAloneAndKeepsNothing(t *testing.T) { t.Fatal(err) } b := newBench(t) - tr := &Tryer{Tries: kv, Judge: b.ex, Say: func(context.Context, string, tryevent.Event) error { + tr := &Tryer{Tries: kv, Judge: b.ex, Say: func(context.Context, string, checkermsg.Event) error { t.Error("a try of one level and some tests said an event: it has no candidate") return nil }} @@ -374,8 +375,8 @@ func TestAFailingTryNamesWhatFailedAndAStepThatCannotRunIsAnError(t *testing.T) } id, _ := AskTry(memTries{kv}, tryTrunks, TryAsk{Repository: repoA, Head: head1}, time.Now()) var ends []string - tr := &Tryer{Tries: kv, Judge: b.ex, Say: func(_ context.Context, event string, e tryevent.Event) error { - if event == tryevent.Ended { + tr := &Tryer{Tries: kv, Judge: b.ex, Say: func(_ context.Context, event string, e checkermsg.Event) error { + if event == checkermsg.Ended { ends = append(ends, e.State) } return nil @@ -431,8 +432,8 @@ func TestATryLeftRunningIsTakenOver(t *testing.T) { wholeBench(b, meshcatalog.CandidatesByGroupValue{}) var ends []string failed := false - tr := &Tryer{Tries: kv, Judge: b.ex, Say: func(_ context.Context, event string, e tryevent.Event) error { - if event == tryevent.Ended { + tr := &Tryer{Tries: kv, Judge: b.ex, Say: func(_ context.Context, event string, e checkermsg.Event) error { + if event == checkermsg.Ended { if row.failFirst && !failed { failed = true return errors.New("the stream did not acknowledge") diff --git a/modules/mesh-delivery-checker/manifest_test.go b/modules/mesh-delivery-checker/manifest_test.go index 88e35e0d..ab9dd7f8 100644 --- a/modules/mesh-delivery-checker/manifest_test.go +++ b/modules/mesh-delivery-checker/manifest_test.go @@ -32,6 +32,8 @@ type artifact struct { From string `json:"from"` Binary string `json:"binary"` Loads []string `json:"loads"` + Paths []string `json:"paths"` + Series string `json:"series"` } type stream struct { @@ -258,8 +260,12 @@ func TestManifestProcess(t *testing.T) { // 1678/AC1 t.Errorf("the process declares a bus: it runs on its own broker credential") } // The settings template is packed as the files archive (novox/hq ADR 0349 §2), or the indexer's judge refuses it. - if len(m.Build.Artifacts) != 3 { - t.Fatalf("artifacts = %+v, want the program, the tools and the files archive", m.Build.Artifacts) + if len(m.Build.Artifacts) != 4 { + t.Fatalf("artifacts = %+v, want the program, the tools, the files archive and the package checkermsg", m.Build.Artifacts) + } + // The checker's own published layouts, as forgemsg is the forge bridge's (ADR 0634 section 2): the indexer requires them by a published version. + if a := m.Build.Artifacts[3]; a.Name != "checkermsg" || a.Kind != "package" || a.Language != "go" || len(a.Paths) != 1 || a.Paths[0] != "checkermsg" || a.Series != "0.1" { + t.Errorf("the package artifact = %+v", a) } if a := m.Build.Artifacts[2]; a.Name != "files" || a.Kind != "archive" || a.From != "files" { t.Errorf("files artifact = %+v, want an archive from files/", a) diff --git a/modules/mesh-delivery-checker/module.json b/modules/mesh-delivery-checker/module.json index 98027af2..bb8440fb 100644 --- a/modules/mesh-delivery-checker/module.json +++ b/modules/mesh-delivery-checker/module.json @@ -184,6 +184,15 @@ "name": "files", "kind": "archive", "from": "files" + }, + { + "name": "checkermsg", + "kind": "package", + "language": "go", + "paths": [ + "checkermsg" + ], + "series": "0.1" } ] } diff --git a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/named.go b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/named.go index d6ab3b9d..f7ea1352 100644 --- a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/named.go +++ b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/named.go @@ -6,7 +6,7 @@ import ( "encoding/hex" "encoding/json" "fmt" - "git.novox.be/novox/mesh-delivery/sdk/tryevent" + "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-checker/checkermsg" "path" "strings" @@ -295,14 +295,14 @@ func openVia(call toolCaller) func(ctx context.Context) ([]forgemsg.OpenPull, er const openTriesTool = "mesh-delivery-checker.checker_tries" // openTriesVia lists the open tries through the checker's tool, never its state (ADR 0596). -func openTriesVia(call toolCaller) func(ctx context.Context) ([]tryevent.Open, error) { - return func(context.Context) ([]tryevent.Open, error) { +func openTriesVia(call toolCaller) func(ctx context.Context) ([]checkermsg.Open, error) { + return func(context.Context) ([]checkermsg.Open, error) { raw, err := call(openTriesTool, map[string]any{}) if err != nil { return nil, err } var o struct { - Tries *[]tryevent.Open `json:"tries"` + Tries *[]checkermsg.Open `json:"tries"` } if err := json.Unmarshal(raw, &o); err != nil || o.Tries == nil { return nil, fmt.Errorf("the answer of %s is not {tries}: %v", openTriesTool, err) diff --git a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/previews.go b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/previews.go index f5fb83aa..a38c80b3 100644 --- a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/previews.go +++ b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/previews.go @@ -11,7 +11,7 @@ import ( "github.com/nats-io/nats.go/jetstream" - "git.novox.be/novox/mesh-delivery/sdk/tryevent" + "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-checker/checkermsg" "mesh-delivery-indexer/internal/index" ) @@ -105,21 +105,21 @@ func tryEventSubject(event string) string { func (w *previewWatch) heardChecks(m delivered) { var event string switch m.Subject() { - case tryEventSubject(tryevent.Started): - event = tryevent.Started - case tryEventSubject(tryevent.Ended): - event = tryevent.Ended + case tryEventSubject(checkermsg.Started): + event = checkermsg.Started + case tryEventSubject(checkermsg.Ended): + event = checkermsg.Ended default: w.Written(m) return } - e, err := tryevent.Decode(event, m.Data()) + e, err := checkermsg.Decode(event, m.Data()) if err != nil { w.logger.Printf("%s: not a try event, dropped: %v", m.Subject(), err) _ = m.Term() return } - if event == tryevent.Started { + if event == checkermsg.Started { var ms []index.TryMember for _, x := range e.Members { ms = append(ms, index.TryMember{Repository: x.Repository, Head: x.Head, Trunk: x.Trunk}) diff --git a/modules/mesh-delivery-indexer/go.mod b/modules/mesh-delivery-indexer/go.mod index 55ba2784..59d43565 100644 --- a/modules/mesh-delivery-indexer/go.mod +++ b/modules/mesh-delivery-indexer/go.mod @@ -39,6 +39,7 @@ require ( replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun => ../mesh-delivery-builder/buildrun require ( + git.novox.be/novox/mesh-delivery/modules/mesh-delivery-checker/checkermsg v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/modules/mesh-delivery-forge-bridge/forgemsg v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/sdk v0.0.0-00010101000000-000000000000 @@ -53,6 +54,7 @@ replace git.novox.be/novox/mesh-delivery/sdk => ../../sdk replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein => ./takein +replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-checker/checkermsg => ../mesh-delivery-checker/checkermsg replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-forge-bridge/forgemsg => ../mesh-delivery-forge-bridge/forgemsg replace git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds => ../mesh-delivery-builder/builds diff --git a/modules/mesh-delivery-indexer/internal/index/candidate_manifests_test.go b/modules/mesh-delivery-indexer/internal/index/candidate_manifests_test.go index afebce2e..3241672b 100644 --- a/modules/mesh-delivery-indexer/internal/index/candidate_manifests_test.go +++ b/modules/mesh-delivery-indexer/internal/index/candidate_manifests_test.go @@ -3,7 +3,6 @@ package index import ( "context" "errors" - "git.novox.be/novox/mesh-delivery/sdk/tryevent" "reflect" "strings" "testing" @@ -98,7 +97,7 @@ func TestTwoPullsGivingOneModuleDifferentManifestsAreRefusedNamingBoth(t *testin // Candidate.check refuses the group too, which is what the refusal stands for. if _, encErr := EncodeCandidate(meshcatalog.CandidatesByGroupValue{V: keys.Version, Group: "feat.x", Heads: before.Heads, Pulls: []meshcatalog.CandidatesByGroupValuePullsItem{before.Pulls[0], { Repository: catalogueRepo, Number: 302, Head: h2, Modules: []string{"avahi"}, - Fps: map[string]meshcatalog.CandidatesByGroupValuePullsItemFpsValue{"avahi": {Manifest: meshcatalogclient.ManifestDigest([]byte(other)), None2: tryevent.NoneNoPreview}}}}}); encErr == nil { + Fps: map[string]meshcatalog.CandidatesByGroupValuePullsItemFpsValue{"avahi": {Manifest: meshcatalogclient.ManifestDigest([]byte(other)), None2: meshcatalogclient.NoneNoPreview}}}}}); encErr == nil { t.Error("the candidate check accepts two manifests for one module") } if ix.Store.(*memStore).writes != writes { diff --git a/modules/mesh-delivery-indexer/internal/index/candidates.go b/modules/mesh-delivery-indexer/internal/index/candidates.go index 5ddd05a1..b387fa10 100644 --- a/modules/mesh-delivery-indexer/internal/index/candidates.go +++ b/modules/mesh-delivery-indexer/internal/index/candidates.go @@ -20,7 +20,7 @@ import ( "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdeliverychecker" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-forge-bridge/forgemsg" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein" - "git.novox.be/novox/mesh-delivery/sdk/tryevent" + "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-checker/checkermsg" "git.novox.be/novox/mesh-sdk/go/keys" ) @@ -179,7 +179,7 @@ type Indexer struct { // SayTakeIn publishes a take-in event (take-in.pending, take-in.taken; ADR 0633 §5); nil says none. SayTakeIn func(ctx context.Context, t takein.TakeIn) error // OpenTries lists the tries that wait or run, from the checker's tool (checker_tries); nil recovers none (trycandidates.go). - OpenTries func(ctx context.Context) ([]tryevent.Open, error) + OpenTries func(ctx context.Context) ([]checkermsg.Open, error) // TryRecovery keeps how the last recovery of the open tries went (trycandidates.go); nil keeps none. TryRecovery Store tryMu sync.Mutex // one try event or recovery at a time (trycandidates.go) @@ -344,7 +344,7 @@ func (ix *Indexer) applyOpen(ctx context.Context, f forgemsg.Forge) error { return fmt.Errorf("listing the candidates: %w", err) } for _, key := range keys { - if tryevent.IsGroup(key) { + if meshcatalogclient.IsTryGroup(key) { continue // a try's candidate is no pull request's: the checker's try owns it (trycandidates.go) } err := write(ctx, ix.Store, key, func(value []byte, found bool) ([]byte, bool, error) { @@ -424,7 +424,7 @@ func write(ctx context.Context, st Store, key string, compute func(value []byte, // next is the group after the message; nil when the group is left with no pull request. // // A pull message that carries manifests (issue 1448) gives each module it touches, in the pull request's Fps, the digest of -// its manifest and why it has no fingerprint of the new form (tryevent.NoneNoPreview), and the candidate its FPSet (issue 1451); a +// its manifest and why it has no fingerprint of the new form (meshcatalogclient.NoneNoPreview), and the candidate its FPSet (issue 1451); a // pull request whose head is held again without its directories keeps the Fps it had. digests are the manifests' digests by // directory; held are the modules the modules bucket holds, which name the module of a changed directory (moduleOfDir). func (ix *Indexer) next(cur *meshcatalog.CandidatesByGroupValue, f forgemsg.Forge, digests map[string]string, held map[string]meshcatalog.ModulesByModuleValue) *meshcatalog.CandidatesByGroupValue { @@ -454,7 +454,7 @@ func (ix *Indexer) next(cur *meshcatalog.CandidatesByGroupValue, f forgemsg.Forg if entry.Fps == nil { entry.Fps = map[string]meshcatalog.CandidatesByGroupValuePullsItemFpsValue{} } - entry.Fps[m] = meshcatalog.CandidatesByGroupValuePullsItemFpsValue{Manifest: digest, None2: tryevent.NoneNoPreview} + entry.Fps[m] = meshcatalog.CandidatesByGroupValuePullsItemFpsValue{Manifest: digest, None2: meshcatalogclient.NoneNoPreview} } } case at >= 0 && pulls[at].Head == f.Head: diff --git a/modules/mesh-delivery-indexer/internal/index/control_records.go b/modules/mesh-delivery-indexer/internal/index/control_records.go index f8feadec..43bdd299 100644 --- a/modules/mesh-delivery-indexer/internal/index/control_records.go +++ b/modules/mesh-delivery-indexer/internal/index/control_records.go @@ -5,7 +5,6 @@ import ( "encoding/json" "errors" "fmt" - "git.novox.be/novox/mesh-delivery/sdk/tryevent" "reflect" "strconv" "strings" @@ -237,7 +236,7 @@ func (ix *Indexer) configCandidatesAfterMerge(ctx context.Context, f forgemsg.Fo } var errs []error for _, g := range groups { - if tryevent.IsGroup(g) { + if meshcatalogclient.IsTryGroup(g) { continue // a try's candidate holds no pull request's config declarations (trycandidates.go) } raw, _, found, err := ix.Store.Get(ctx, g) diff --git a/modules/mesh-delivery-indexer/internal/index/control_records_test.go b/modules/mesh-delivery-indexer/internal/index/control_records_test.go index 2ee807ab..25951d2f 100644 --- a/modules/mesh-delivery-indexer/internal/index/control_records_test.go +++ b/modules/mesh-delivery-indexer/internal/index/control_records_test.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "git.novox.be/novox/mesh-delivery/sdk/tryevent" "reflect" "strings" "testing" @@ -595,7 +594,7 @@ func TestTheControlRecords(t *testing.T) { // A group try's candidate (number 0) holds no pull request's declarations: a merge that touches its module writes none // for it (fails when configCandidatesAfterMerge no longer skips a try's group). tryPull := meshcatalog.CandidatesByGroupValuePullsItem{Repository: catalogueRepo, Head: h1, Modules: []string{"avahi"}, - Fps: map[string]meshcatalog.CandidatesByGroupValuePullsItemFpsValue{"avahi": {Manifest: meshcatalogclient.ManifestDigest([]byte(trunk)), None2: tryevent.NoneNoPreview}}} + Fps: map[string]meshcatalog.CandidatesByGroupValuePullsItemFpsValue{"avahi": {Manifest: meshcatalogclient.ManifestDigest([]byte(trunk)), None2: meshcatalogclient.NoneNoPreview}}} tryCand := meshcatalog.CandidatesByGroupValue{V: keys.Version, Group: "try-5", Pulls: []meshcatalog.CandidatesByGroupValuePullsItem{tryPull}} tryCand.Heads, _ = meshdeliveryclient.HeadsHash([]meshdeliveryclient.Head{{Repository: tryPull.Repository, Head: tryPull.Head}}) tryCand.Fpset = meshcatalogclient.FingerprintSet(tryCand.Pulls) diff --git a/modules/mesh-delivery-indexer/internal/index/pending_tools.go b/modules/mesh-delivery-indexer/internal/index/pending_tools.go index d3eb6b18..189cff8a 100644 --- a/modules/mesh-delivery-indexer/internal/index/pending_tools.go +++ b/modules/mesh-delivery-indexer/internal/index/pending_tools.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" "fmt" - "git.novox.be/novox/mesh-delivery/sdk/tryevent" + "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "strings" "time" @@ -133,7 +133,7 @@ func TryCandidateTools(candidates, recovery Store, ask func(key string, value [] } var out []meshcatalog.CandidatesByGroupValue for _, k := range keys { - if !tryevent.IsGroup(k) { + if !meshcatalogclient.IsTryGroup(k) { continue } v, _, found, err := candidates.Get(ctx, k) @@ -189,7 +189,7 @@ func TryCandidateTools(candidates, recovery Store, ask func(key string, value [] id, _ := args["try"].(string) why, _ := args["why"].(string) id = strings.TrimSpace(id) - if !tryevent.IsGroup(id) || strings.TrimSpace(why) == "" { + if !meshcatalogclient.IsTryGroup(id) || strings.TrimSpace(why) == "" { return nil, fmt.Errorf("name the try (try-) and say why") } data, err := json.Marshal(TakeInAsk{V: 1, TryCandidate: id, Drop: true, Why: strings.TrimSpace(why), By: stdio.CallerOf(args), At: now().UTC()}) diff --git a/modules/mesh-delivery-indexer/internal/index/previews_test.go b/modules/mesh-delivery-indexer/internal/index/previews_test.go index 518cf27f..a270bda5 100644 --- a/modules/mesh-delivery-indexer/internal/index/previews_test.go +++ b/modules/mesh-delivery-indexer/internal/index/previews_test.go @@ -19,7 +19,7 @@ import ( "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdelivery" "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdeliverychecker" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-forge-bridge/forgemsg" - "git.novox.be/novox/mesh-delivery/sdk/tryevent" + "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-checker/checkermsg" "mesh-delivery-indexer/internal/fingerprint" ) @@ -95,7 +95,7 @@ func TestACandidatesModuleGetsTheFingerprintATrunkModuleOfTheSameTreeHas(t *test if err := ix.Apply(context.Background(), avahiPull(t, h1)); err != nil { t.Fatal(err) } - if got := fpOf(t, cands); got.None2 != tryevent.NoneNoPreview { + if got := fpOf(t, cands); got.None2 != meshcatalogclient.NoneNoPreview { t.Fatalf("before the preview: %+v", got) } applyPreview(t, ix, avahiPreview(t, trunkNow, h1)) @@ -190,7 +190,7 @@ func TestAPreviewHeardBeforeItsPullRequestGivesTheFingerprintWhenTheCandidateIsW if err := ix.Apply(context.Background(), avahiPull(t, h2)); err != nil { t.Fatal(err) } - if got := fpOf(t, cands); got.Fp2 != "" || got.None2 != tryevent.NoneNoPreview { + if got := fpOf(t, cands); got.Fp2 != "" || got.None2 != meshcatalogclient.NoneNoPreview { t.Errorf("a new head: %+v, want no preview", got) } // Issue 1921: a whole group try has no pull request, yet the indexer writes its candidate from the checker's try events and @@ -305,14 +305,14 @@ func TestAPreviewHeardBeforeItsPullRequestGivesTheFingerprintWhenTheCandidateIsW } // The start recovered from the checker's tool: an open whole try is written again, one the checker no longer // lists is deleted, and a try narrowed to a level is none. - ix.OpenTries = func(context.Context) ([]tryevent.Open, error) { - return []tryevent.Open{{ID: "try-7", Whole: true, Members: []tryevent.Member{{Repository: catalogueRepo, Head: h1, Trunk: trunkNow}}}, - {ID: "try-8", Whole: false, Members: []tryevent.Member{{Repository: catalogueRepo, Head: h2, Trunk: trunkNow}}}}, nil + ix.OpenTries = func(context.Context) ([]checkermsg.Open, error) { + return []checkermsg.Open{{ID: "try-7", Whole: true, Members: []checkermsg.Member{{Repository: catalogueRepo, Head: h1, Trunk: trunkNow}}}, + {ID: "try-8", Whole: false, Members: []checkermsg.Member{{Repository: catalogueRepo, Head: h2, Trunk: trunkNow}}}}, nil } if err := ix.RecoverTries(ctx); err != nil || len(held()) != 1 { t.Fatalf("recovered: %v, candidates %v, want try-7's alone", err, held()) } - ix.OpenTries = func(context.Context) ([]tryevent.Open, error) { return nil, nil } + ix.OpenTries = func(context.Context) ([]checkermsg.Open, error) { return nil, nil } if err := ix.RecoverTries(ctx); err != nil || len(held()) != 0 { t.Errorf("recovered with no open try: %v, candidates %v, want none", err, held()) } @@ -321,7 +321,7 @@ func TestAPreviewHeardBeforeItsPullRequestGivesTheFingerprintWhenTheCandidateIsW if err := ix.StartTry(ctx, "try-7", members); err != nil || len(held()) != 1 { t.Fatalf("started: %v, candidates %v", err, held()) } - ix.OpenTries = func(context.Context) ([]tryevent.Open, error) { + ix.OpenTries = func(context.Context) ([]checkermsg.Open, error) { return nil, errors.New("checker_tries does not answer") } if err := ix.RecoverTries(ctx); err == nil || len(held()) != 1 { @@ -331,14 +331,14 @@ func TestAPreviewHeardBeforeItsPullRequestGivesTheFingerprintWhenTheCandidateIsW !strings.Contains(out.(map[string]any)["recovery"].(map[string]any)["says"].(string), "checker_tries does not answer") { t.Errorf("%s = %v, %v, want recovery not done with since and why", tools[0].Name, out, err) } - ix.OpenTries = func(context.Context) ([]tryevent.Open, error) { return nil, nil } + ix.OpenTries = func(context.Context) ([]checkermsg.Open, error) { return nil, nil } if err := ix.StartTry(ctx, "try-11", members); err != nil || len(held()) != 1 || held()[0] != "try-11" { t.Fatalf("a try event after a failed recovery: %v, candidates %v, want the recovery run (try-7 not listed, gone) and try-11 written", err, held()) } if out, _ := tools[0].Run(map[string]any{}); out.(map[string]any)["recovery"].(map[string]any)["done"] != true { t.Errorf("recovery still said not done after a success: %v", out) } - ix.OpenTries = func(context.Context) ([]tryevent.Open, error) { return nil, errors.New("down") } + ix.OpenTries = func(context.Context) ([]checkermsg.Open, error) { return nil, errors.New("down") } recoverAsk := func(key string, value []byte) (TakeInAsk, error) { a, err := DecodeTakeIn(value) r := ix.RecoverTriesByHand(ctx, a.By, a.Why) @@ -349,7 +349,7 @@ func TestAPreviewHeardBeforeItsPullRequestGivesTheFingerprintWhenTheCandidateIsW if out, err := byHand[1].Run(map[string]any{"why": "the checker was replaced"}); err != nil || out.(*TakenIn).Stored || !strings.Contains(out.(*TakenIn).Answer, "recovery not done") { t.Errorf("%s with the checker down = %v, %v", byHand[1].Name, out, err) } - ix.OpenTries = func(context.Context) ([]tryevent.Open, error) { return nil, nil } + ix.OpenTries = func(context.Context) ([]checkermsg.Open, error) { return nil, nil } if out, err := byHand[1].Run(map[string]any{"why": "the checker is back"}); err != nil || !out.(*TakenIn).Stored || len(held()) != 0 { t.Errorf("%s = %v, %v, candidates %v, want it recovered (try-11 not listed)", byHand[1].Name, out, err, held()) } @@ -359,9 +359,9 @@ func TestAPreviewHeardBeforeItsPullRequestGivesTheFingerprintWhenTheCandidateIsW // ADR 0638 §3, §4: the consumer exists before the call, so what happens between the call and the hearing is heard after // it. A try the call listed and whose start is then heard gets one candidate; a try started after the list gets one; a // try that ended during the call, listed as open, leaves none once its end is heard. - ix.OpenTries = func(context.Context) ([]tryevent.Open, error) { - return []tryevent.Open{{ID: "try-7", Whole: true, Members: []tryevent.Member{{Repository: catalogueRepo, Head: h1, Trunk: trunkNow}}}, - {ID: "try-9", Whole: true, Members: []tryevent.Member{{Repository: catalogueRepo, Head: h1, Trunk: trunkNow}}}}, nil + ix.OpenTries = func(context.Context) ([]checkermsg.Open, error) { + return []checkermsg.Open{{ID: "try-7", Whole: true, Members: []checkermsg.Member{{Repository: catalogueRepo, Head: h1, Trunk: trunkNow}}}, + {ID: "try-9", Whole: true, Members: []checkermsg.Member{{Repository: catalogueRepo, Head: h1, Trunk: trunkNow}}}}, nil } if err := ix.RecoverTries(ctx); err != nil { t.Fatal(err) @@ -393,7 +393,7 @@ func TestAPreviewHeardBeforeItsPullRequestGivesTheFingerprintWhenTheCandidateIsW // The hand recovery never overlaps a try event: a start heard while the call to the checker is out writes its candidate // before or after the sweep, never between the call and the sweep (which would delete it, the try not being listed). startDone := make(chan error, 1) - ix.OpenTries = func(context.Context) ([]tryevent.Open, error) { + ix.OpenTries = func(context.Context) ([]checkermsg.Open, error) { go func() { startDone <- ix.StartTry(ctx, "try-12", members) }() for i := 0; i < 2000 && len(held()) == 0; i++ { runtime.Gosched() // lets the start write if nothing holds it back diff --git a/modules/mesh-delivery-indexer/internal/index/trycandidates.go b/modules/mesh-delivery-indexer/internal/index/trycandidates.go index 252dd219..db949fc4 100644 --- a/modules/mesh-delivery-indexer/internal/index/trycandidates.go +++ b/modules/mesh-delivery-indexer/internal/index/trycandidates.go @@ -24,7 +24,6 @@ import ( "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdeliverychecker" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-forge-bridge/forgemsg" - "git.novox.be/novox/mesh-delivery/sdk/tryevent" "git.novox.be/novox/mesh-sdk/go/keys" ) @@ -53,7 +52,7 @@ type TryRecovery struct { // TryMember is one repository of a try: its exact commit and the trunk commit it is merged onto. type TryMember struct{ Repository, Head, Trunk string } -// StartTry takes a whole try in, as the checker said it started (tryevent.Started): its members at their commits are kept, and +// StartTry takes a whole try in, as the checker said it started (checkermsg.Started): its members at their commits are kept, and // its candidate is written once every member's preview is held. The checker's state is never read (ADR 0596). func (ix *Indexer) StartTry(ctx context.Context, id string, members []TryMember) error { ix.tryMu.Lock() @@ -70,7 +69,7 @@ func (ix *Indexer) retryRecovery(ctx context.Context) { } func (ix *Indexer) startTry(ctx context.Context, id string, members []TryMember) error { - if !tryevent.IsGroup(id) || len(members) == 0 { + if !meshcatalogclient.IsTryGroup(id) || len(members) == 0 { return fmt.Errorf("%q with %d members is no try to start", id, len(members)) } ix.mu.Lock() @@ -82,7 +81,7 @@ func (ix *Indexer) startTry(ctx context.Context, id string, members []TryMember) return ix.writeTryCandidate(ctx, id) } -// EndTry takes a try out, as the checker said it ended (tryevent.Ended), and deletes its candidate. +// EndTry takes a try out, as the checker said it ended (checkermsg.Ended), and deletes its candidate. func (ix *Indexer) EndTry(ctx context.Context, id string) error { ix.tryMu.Lock() defer ix.tryMu.Unlock() @@ -94,7 +93,7 @@ func (ix *Indexer) endTry(ctx context.Context, id string) error { ix.mu.Lock() delete(ix.tries, id) ix.mu.Unlock() - if !tryevent.IsGroup(id) { + if !meshcatalogclient.IsTryGroup(id) { return nil } return ix.dropTryCandidate(ctx, id) @@ -205,7 +204,7 @@ func (ix *Indexer) recoverTries(ctx context.Context) error { return err } for _, k := range keys { - if tryevent.IsGroup(k) && !live[k] { + if meshcatalogclient.IsTryGroup(k) && !live[k] { if err := ix.endTry(ctx, k); err != nil { return err } @@ -248,7 +247,7 @@ func (ix *Indexer) dropTryCandidate(ctx context.Context, id string) error { func (ix *Indexer) DropTryCandidate(ctx context.Context, id, by, why string) TakenIn { r := TakenIn{Module: id} switch { - case !tryevent.IsGroup(id): + case !meshcatalogclient.IsTryGroup(id): r.Answer = id + " is no try's group, try-: nothing dropped" default: if err := ix.dropTryCandidate(ctx, id); err != nil { @@ -360,7 +359,7 @@ func (ix *Indexer) writeTryCandidate(ctx context.Context, id string) error { pull.Fps = map[string]meshcatalog.CandidatesByGroupValuePullsItemFpsValue{} } pull.Modules = append(pull.Modules, module) - pull.Fps[module] = meshcatalog.CandidatesByGroupValuePullsItemFpsValue{Manifest: digest, None2: tryevent.NoneNoPreview} + pull.Fps[module] = meshcatalog.CandidatesByGroupValuePullsItemFpsValue{Manifest: digest, None2: meshcatalogclient.NoneNoPreview} defs[dir] = raw over[module] = digest }