From 8786bb3ba140b3a2868f191b3de63bba39dad461 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 5 Nov 2026 16:05:34 +0100 Subject: [PATCH 1/6] =?UTF-8?q?mesh-build-go=20runs=20its=20asks=20on=20th?= =?UTF-8?q?e=20Delivery=20SDK's=20neutral=20build=20ask,=20step=20and=20an?= =?UTF-8?q?swer=20forms=20instead=20of=20mesh-sdk's=20go/delivery:=20the?= =?UTF-8?q?=20Puller=20takes=20buildstep.StepAsk=20(the=20read=20bridge=20?= =?UTF-8?q?is=20the=20form's=20own=20AskAs),=20the=20toolchains=20value=20?= =?UTF-8?q?is=20the=20build=20runner's=20own,=20the=20stale-step=20part=20?= =?UTF-8?q?is=20buildrun's,=20keys=20and=20values=20come=20from=20the=20se?= =?UTF-8?q?ats=20and=20clients=20(B5i;=20ADR=200634=20=C2=A71,=20=C2=A76;?= =?UTF-8?q?=20issue=201966)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The part build-step lacks the check job's toolchain and types the check answer's fetch as the fetch arguments; both are kept in askrun_gaps.go until the part has them. Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i --- modules/mesh-build-go/buildstep/askrun.go | 101 ++++++----- .../mesh-build-go/buildstep/askrun_gaps.go | 52 ++++++ .../mesh-build-go/buildstep/askrun_test.go | 104 +++++------ .../mesh-build-go/buildstep/capacity_cpu.go | 8 +- .../buildstep/conformance/conformance_test.go | 11 +- .../buildstep/conformance/leftrunning.go | 44 ++--- .../buildstep/digestshape_test.go | 49 +++-- modules/mesh-build-go/buildstep/generated.go | 2 +- .../mesh-build-go/buildstep/generated_test.go | 12 +- modules/mesh-build-go/buildstep/go.mod | 2 + modules/mesh-build-go/buildstep/guard.go | 10 +- modules/mesh-build-go/buildstep/guard_test.go | 6 +- .../mesh-build-go/buildstep/latepublish.go | 6 +- .../mesh-build-go/buildstep/narrate_test.go | 6 +- modules/mesh-build-go/buildstep/phase.go | 9 +- modules/mesh-build-go/buildstep/pull.go | 79 ++++---- modules/mesh-build-go/buildstep/pull_bus.go | 19 +- modules/mesh-build-go/buildstep/pull_fake.go | 9 +- .../buildstep/pull_integration_test.go | 38 ++-- modules/mesh-build-go/buildstep/pull_seat.go | 4 +- .../mesh-build-go/buildstep/pull_seat_test.go | 8 +- modules/mesh-build-go/buildstep/pull_test.go | 168 +++++++++--------- modules/mesh-build-go/buildstep/refusal.go | 2 +- .../buildstep/seat_tools_test.go | 15 +- modules/mesh-build-go/buildstep/step.go | 34 ++-- modules/mesh-build-go/buildstep/step_test.go | 29 ++- modules/mesh-build-go/buildstep/steptool.go | 6 +- modules/mesh-build-go/buildstep/toolchain.go | 82 +++++++++ .../mesh-build-go/buildstep/toolchain_test.go | 48 +++++ .../cmd/mesh-build-go/archive_test.go | 23 ++- .../mesh-build-go/cmd/mesh-build-go/asks.go | 42 ++--- .../mesh-build-go/asks_integration_test.go | 28 +-- .../cmd/mesh-build-go/asks_test.go | 35 ++-- .../cmd/mesh-build-go/beside_digest_test.go | 5 +- .../mesh-build-go/cmd/mesh-build-go/build.go | 4 +- .../cmd/mesh-build-go/build_test.go | 18 +- .../cmd/mesh-build-go/candidate_test.go | 18 +- .../cmd/mesh-build-go/compose.go | 40 +++-- .../mesh-build-go/compose_integration_test.go | 24 +-- .../cmd/mesh-build-go/compose_test.go | 29 +-- .../mesh-build-go/cmd/mesh-build-go/digest.go | 18 +- .../cmd/mesh-build-go/fetch_test.go | 12 +- .../cmd/mesh-build-go/gopackage.go | 4 +- .../cmd/mesh-build-go/imports.go | 6 +- .../mesh-build-go/installed_toolchain_test.go | 4 +- .../mesh-build-go/integration_level_test.go | 14 +- .../cmd/mesh-build-go/isolate_test.go | 8 +- .../cmd/mesh-build-go/kit_test.go | 3 +- .../mesh-build-go/cmd/mesh-build-go/level.go | 6 +- .../mesh-build-go/cmd/mesh-build-go/main.go | 15 +- .../cmd/mesh-build-go/mirror_test.go | 5 +- .../mesh-build-go/cmd/mesh-build-go/module.go | 8 +- .../cmd/mesh-build-go/module_test.go | 25 +-- .../mesh-build-go/narrow_integration_test.go | 7 +- .../cmd/mesh-build-go/needtools_test.go | 7 +- .../cmd/mesh-build-go/node_toolchains_test.go | 18 +- .../cmd/mesh-build-go/packages_shape_test.go | 5 +- .../mesh-build-go/pins_integration_test.go | 5 +- .../cmd/mesh-build-go/pins_test.go | 18 +- .../mesh-build-go/preview_integration_test.go | 22 +-- .../cmd/mesh-build-go/preview_test.go | 14 +- .../cmd/mesh-build-go/publish_test.go | 25 +-- .../mesh-build-go/cmd/mesh-build-go/read.go | 29 +-- .../cmd/mesh-build-go/read_test.go | 36 ++-- .../cmd/mesh-build-go/room_test.go | 6 +- .../cmd/mesh-build-go/selected_dirs_test.go | 11 +- .../mesh-build-go/store_integration_test.go | 10 +- .../mesh-build-go/cmd/mesh-build-go/test.go | 15 +- .../cmd/mesh-build-go/test_test.go | 20 +-- .../cmd/mesh-build-go/versions.go | 2 +- .../cmd/mesh-build-go/versions_test.go | 9 +- .../cmd/mesh-build-go/xz_test.go | 5 +- modules/mesh-build-go/go.mod | 2 + 73 files changed, 909 insertions(+), 714 deletions(-) create mode 100644 modules/mesh-build-go/buildstep/askrun_gaps.go create mode 100644 modules/mesh-build-go/buildstep/toolchain.go create mode 100644 modules/mesh-build-go/buildstep/toolchain_test.go diff --git a/modules/mesh-build-go/buildstep/askrun.go b/modules/mesh-build-go/buildstep/askrun.go index bd5cd5993..9c73e967c 100644 --- a/modules/mesh-build-go/buildstep/askrun.go +++ b/modules/mesh-build-go/buildstep/askrun.go @@ -4,13 +4,13 @@ import ( "context" "encoding/json" "fmt" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" + trunk "git.novox.be/novox/mesh-delivery/sdk/trunk" "maps" "path" "slices" "sort" "strings" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // **One ask, one whole job** (novox/hq ADR 0525 §3). A build module runs a pulled ask with its own step tools' bodies, @@ -35,21 +35,21 @@ type AskSteps struct { Compare StepFunc // Toolchain is the toolchain the module builds with now; a build ask naming another is declined (Declining). Nil checks nothing // (an image or an archive names none). - Toolchain func(ctx context.Context) (delivery.ToolchainUsed, error) - // Kept looks up a kept verdict by level and digest (the checker's kept bucket, delivery.KeptKey): whether one is + Toolchain func(ctx context.Context) (sdkstep.ToolchainUsed, error) + // Kept looks up a kept verdict by level and digest (the checker's kept bucket, the checker seat's kept key): whether one is // kept and how many tests it counted. Nil takes none. Kept func(ctx context.Context, level, digest string) (tests int, found bool, err error) // Release removes a workspace once the ask's steps on it ended (the module's release tool's body); nil leaves it to // the module's sweep. Release func(workspace string) error Logf func(format string, args ...any) - // Has says whether this node has a need a package's tests declare (delivery.AskNeeds, issue 890); a package needing + // Has says whether this node has a need a package's tests declare (sdkstep.AskNeeds, issue 890); a package needing // what it lacks is not tested here but named in the level's Unmet, for the asker to place. Nil has nothing. Has func(need string) bool } -// RunAsk runs ask's job with steps and answers a delivery.BuildAnswer or a delivery.CheckAnswer. -func RunAsk(ctx context.Context, steps AskSteps, ask delivery.StepAsk) (any, error) { +// RunAsk runs ask's job with steps and answers a sdkstep.BuildAnswer or a CheckAnswer. +func RunAsk(ctx context.Context, steps AskSteps, ask sdkstep.StepAsk) (any, error) { if ask.Build != nil { job := *ask.Build job.Fetch = withPackages(job.Fetch, ask.Packages) @@ -57,7 +57,7 @@ func RunAsk(ctx context.Context, steps AskSteps, ask delivery.StepAsk) (any, err } if ask.Check != nil { job := *ask.Check - job.Fetch = withPackages(job.Fetch, ask.Packages) + job.Fetch = *withPackages(&job.Fetch, ask.Packages) return steps.check(ctx, job) } return nil, Refuse("the ask %s holds no job", ask.ID) @@ -66,13 +66,28 @@ func RunAsk(ctx context.Context, steps AskSteps, ask delivery.StepAsk) (any, err // withPackages is the fetch's arguments with the ask's package versions (novox/hq ADR 0573 §2), which the build module // writes into the workspace it fetches; a copy, so the ask is left as it was. An ask with none, or a copy alone that // fetches nothing, is left as it is. -func withPackages(fetch map[string]any, packages delivery.PackageVersions) map[string]any { +func withPackages(fetch *sdkstep.Fetch, packages sdkstep.PackageVersions) *sdkstep.Fetch { if len(packages) == 0 || fetch == nil { return fetch } - out := maps.Clone(fetch) - out["packages"] = maps.Clone(packages) - return out + out := *fetch + out.Packages = maps.Clone(packages) + return &out +} + +// FetchArgs is a fetch as the fetch tool takes it (sdkstep.FetchRequest's Args and the build module's own, beside): the +// ask's fetch through the one JSON form, without the layout version, which no tool takes. +func FetchArgs(f sdkstep.Fetch) (map[string]any, error) { + b, err := json.Marshal(f) + if err != nil { + return nil, err + } + args := map[string]any{} + if err := json.Unmarshal(b, &args); err != nil { + return nil, err + } + delete(args, "v") + return args, nil } func raw(v any) (json.RawMessage, error) { @@ -91,11 +106,18 @@ type fetched struct { Modules []string `json:"modules"` } -func (s AskSteps) fetch(ctx context.Context, args map[string]any) (json.RawMessage, fetched, error) { +func (s AskSteps) fetch(ctx context.Context, fetch *sdkstep.Fetch) (json.RawMessage, fetched, error) { if s.Fetch == nil { return nil, fetched{}, Refuse("this build module fetches nothing") } - if _, merges := args["base"]; merges { + if fetch == nil { + return nil, fetched{}, Refuse("the ask names no fetch") + } + args, err := FetchArgs(*fetch) + if err != nil { + return nil, fetched{}, err + } + if fetch.Base != "" { Phase(ctx, "fetch and merge") } else { Phase(ctx, "fetch") @@ -118,7 +140,7 @@ func (s AskSteps) fetch(ctx context.Context, args map[string]any) (json.RawMessa // onToolchain is the toolchain this node builds with when the ask names one and this module reports its own, nil when // either is absent. A node on another toolchain than the ask names answers a Declining: it is not on the agreed one and // sits out, for a node that is to take the ask (novox/hq ADR 0584 clause 2). -func (s AskSteps) onToolchain(ctx context.Context, want *delivery.ToolchainUsed) (*delivery.ToolchainUsed, error) { +func (s AskSteps) onToolchain(ctx context.Context, want *sdkstep.ToolchainUsed) (*sdkstep.ToolchainUsed, error) { if want == nil || s.Toolchain == nil { return nil, nil } @@ -134,8 +156,8 @@ func (s AskSteps) onToolchain(ctx context.Context, want *delivery.ToolchainUsed) return &tc, nil } -func (s AskSteps) build(ctx context.Context, job delivery.BuildJob) (any, error) { - answer := delivery.BuildAnswer{} +func (s AskSteps) build(ctx context.Context, job sdkstep.BuildJob) (any, error) { + answer := sdkstep.BuildAnswer{} tc, err := s.onToolchain(ctx, job.Toolchain) if err != nil { return nil, err @@ -149,7 +171,7 @@ func (s AskSteps) build(ctx context.Context, job delivery.BuildJob) (any, error) if err != nil { return nil, err } - if _, candidate := job.Fetch["base"]; candidate { + if job.Fetch.Base != "" { // A candidate is built from its head merged onto the trunk; a head that does not merge leaves the tree at the // trunk, and building that would store the trunk's build under the candidate's fingerprint. if len(got.Conflicts) > 0 { @@ -225,7 +247,7 @@ func (s AskSteps) build(ctx context.Context, job delivery.BuildJob) (any, error) if err := json.Unmarshal(r, &built); err != nil || built.Digest == "" { return nil, fmt.Errorf("the build of %s answered no digest: %s", a.Artifact, r) } - answer.Artifacts = append(answer.Artifacts, delivery.AskBuilt{Artifact: a.Artifact, Digest: built.Digest, Reference: built.Reference}) + answer.Artifacts = append(answer.Artifacts, sdkstep.AskBuilt{Artifact: a.Artifact, Digest: built.Digest, Reference: built.Reference}) } if s.Imports != nil && f.Workspace != "" { out, err := s.Imports(ctx, map[string]any{"workspace": f.Workspace, "module": job.Path}) @@ -242,7 +264,7 @@ func (s AskSteps) build(ctx context.Context, job delivery.BuildJob) (any, error) if err := json.Unmarshal(r, &read); err != nil { return nil, fmt.Errorf("the imports of %s answered what is not a list: %s", job.Module, r) } - if err := delivery.CheckImports(read.Imports); err != nil { + if err := trunk.CheckImports(read.Imports); err != nil { return nil, err } answer.Imports = read.Imports @@ -250,16 +272,16 @@ func (s AskSteps) build(ctx context.Context, job delivery.BuildJob) (any, error) return answer, nil } -func (s AskSteps) check(ctx context.Context, job delivery.CheckJob) (any, error) { - if _, err := s.onToolchain(ctx, job.Toolchain); err != nil { +func (s AskSteps) check(ctx context.Context, job sdkstep.CheckJob) (any, error) { + if _, err := s.onToolchain(ctx, checkToolchain(ctx)); err != nil { return nil, err } - r, f, err := s.fetch(ctx, job.Fetch) + r, f, err := s.fetch(ctx, &job.Fetch) if err != nil { return nil, err } defer s.release(f.Workspace) - answer := delivery.CheckAnswer{Fetch: r} + answer := CheckAnswer{Fetch: r} if len(f.Conflicts) > 0 { return answer, nil // the asker reads the conflict from the fetch's answer: a verdict, not an error } @@ -273,7 +295,7 @@ func (s AskSteps) check(ctx context.Context, job delivery.CheckJob) (any, error) // Every level runs, also after one that did not pass: one check names every failure, not only the first (the operator, // 2026-11-02: "A failed check shows only its first fault"). for _, level := range job.Levels { - la := delivery.LevelAnswer{Level: level} + la := sdkstep.LevelAnswer{Level: level} _, err := s.level(ctx, job, level, f, runner, &la) answer.Levels = append(answer.Levels, la) if err != nil { @@ -284,13 +306,13 @@ func (s AskSteps) check(ctx context.Context, job delivery.CheckJob) (any, error) } // level runs one level of a check ask and says whether it passed. -func (s AskSteps) level(ctx context.Context, job delivery.CheckJob, level string, f fetched, runner string, la *delivery.LevelAnswer) (bool, error) { +func (s AskSteps) level(ctx context.Context, job sdkstep.CheckJob, level string, f fetched, runner string, la *sdkstep.LevelAnswer) (bool, error) { withRunner := func(args map[string]any) map[string]any { if runner != "" { args["runner"] = runner } if len(job.NodeNames) > 0 { - args[delivery.NodeNamesArg] = job.NodeNames // the names check's (ADR 0567 §12) + args[sdkstep.NodeNamesArg] = job.NodeNames // the names check's (ADR 0567 §12) } return args } @@ -390,7 +412,7 @@ func (s AskSteps) release(workspace string) { // is digested for keeping (ADR 0535 §4); when the installed module answers it (it does not take the runner), the level is // planned as any other and the runner is dropped. The level runs whole and takes nothing when the digest names no package // or does not cover the siblings the fetch placed (ADR 0444, L5). -func (s AskSteps) plan(ctx context.Context, job delivery.CheckJob, level string, f fetched, runner string, withRunner func(map[string]any) map[string]any, la *delivery.LevelAnswer) ([]string, bool, bool) { +func (s AskSteps) plan(ctx context.Context, job sdkstep.CheckJob, level string, f fetched, runner string, withRunner func(map[string]any) map[string]any, la *sdkstep.LevelAnswer) ([]string, bool, bool) { if job.Run != "" { return nil, true, true } @@ -406,7 +428,7 @@ func (s AskSteps) plan(ctx context.Context, job delivery.CheckJob, level string, if err != nil { return nil, true, true } - var d delivery.LevelDigest // packages kept as a sorted list, never keyed by a package path (issue 1930) + var d sdkstep.LevelDigest // packages kept as a sorted list, never keyed by a package path (issue 1930) if err := json.Unmarshal(r, &d); err != nil { return nil, true, true } @@ -437,16 +459,16 @@ func (s AskSteps) plan(ctx context.Context, job delivery.CheckJob, level string, s.Logf("the kept verdict of %s at %s cannot be read, so it runs: %v", p, level, err) } if err == nil && found { - la.Kept = append(la.Kept, delivery.KeptTaken{Package: p, Digest: pd.Digest, Tests: tests}) + la.Kept = append(la.Kept, sdkstep.KeptTaken{Package: p, Digest: pd.Digest, Tests: tests}) continue } } - if needs := d.NeedsOf(p); len(delivery.Lacks(needs, s.Has)) > 0 { + if needs := d.NeedsOf(p); len(sdkstep.Lacks(needs, s.Has)) > 0 { // Its tests would only skip here (issue 890): it is left for a node that has what they need. - la.Unmet = append(la.Unmet, delivery.PackageNeeds{Package: p, Needs: needs}) + la.Unmet = append(la.Unmet, sdkstep.PackageNeeds{Package: p, Needs: needs}) if s.Logf != nil { s.Logf("the %s level of %s is left to a node with %s: this node lacks %s", level, p, - strings.Join(needs, ", "), strings.Join(delivery.Lacks(needs, s.Has), ", ")) + strings.Join(needs, ", "), strings.Join(sdkstep.Lacks(needs, s.Has), ", ")) } continue } @@ -456,18 +478,9 @@ func (s AskSteps) plan(ctx context.Context, job delivery.CheckJob, level string, } // besideOf are the siblings a fetch's arguments place, as a digest echoes them: ` `, sorted. -func besideOf(fetch map[string]any) []string { - raw, err := json.Marshal(fetch["beside"]) - if err != nil { - return nil - } - var refs []struct { - Repository string `json:"repository"` - Commit string `json:"commit"` - } - _ = json.Unmarshal(raw, &refs) +func besideOf(fetch sdkstep.Fetch) []string { var out []string - for _, r := range refs { + for _, r := range fetch.Beside { out = append(out, r.Repository+" "+r.Commit) } sort.Strings(out) diff --git a/modules/mesh-build-go/buildstep/askrun_gaps.go b/modules/mesh-build-go/buildstep/askrun_gaps.go new file mode 100644 index 000000000..67f6b3a65 --- /dev/null +++ b/modules/mesh-build-go/buildstep/askrun_gaps.go @@ -0,0 +1,52 @@ +package buildstep + +// Two layouts the part build-step (mesh-delivery-sdk buildstep, as the three node-build seats generate it) lacks, which a +// check ask still carries; both are kept here and nowhere else, so that deleting this file is the whole change once the +// part has them (B5i finding 1 and 2, issue 1966): +// +// - the check job's toolchain (novox/hq ADR 0584 clause 2): the part's CheckJob has no `toolchain`, so a node on +// another toolchain than the checker agreed would take the ask and record a pass it did not run. The Puller reads +// the field from the ask's own bytes and the run takes it from its context. +// - the check answer's fetch: the part types the answer's `fetch` as Fetch (the arguments), but the fetch tool's answer +// (workspace, merge, conflicts, changed, modules) is what the checker reads a conflict from. + +import ( + "context" + "encoding/json" + + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" +) + +type checkToolchainKey struct{} + +// checkToolchainOf reads the toolchain a check ask names, from the ask's bytes; nil when it names none or is no check. +func checkToolchainOf(data []byte) *sdkstep.ToolchainUsed { + var a struct { + Check *struct { + Toolchain *sdkstep.ToolchainUsed `json:"toolchain"` + } `json:"check"` + } + if json.Unmarshal(data, &a) != nil || a.Check == nil { + return nil + } + return a.Check.Toolchain +} + +// WithCheckToolchain is ctx carrying the toolchain the ask in data names for its check. +func WithCheckToolchain(ctx context.Context, data []byte) context.Context { + if tc := checkToolchainOf(data); tc != nil { + return context.WithValue(ctx, checkToolchainKey{}, tc) + } + return ctx +} + +func checkToolchain(ctx context.Context) *sdkstep.ToolchainUsed { + tc, _ := ctx.Value(checkToolchainKey{}).(*sdkstep.ToolchainUsed) + return tc +} + +// CheckAnswer is a check ask's answer with the fetch tool's own answer as it is. +type CheckAnswer struct { + Fetch json.RawMessage `json:"fetch"` + Levels []sdkstep.LevelAnswer `json:"levels,omitempty"` +} diff --git a/modules/mesh-build-go/buildstep/askrun_test.go b/modules/mesh-build-go/buildstep/askrun_test.go index 3b02e1ba4..3cf0985c4 100644 --- a/modules/mesh-build-go/buildstep/askrun_test.go +++ b/modules/mesh-build-go/buildstep/askrun_test.go @@ -10,8 +10,6 @@ import ( "strings" "testing" "time" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) const runCommit = "0123456789abcdef0123456789abcdef01234567" @@ -22,7 +20,7 @@ type recorder struct { fetch map[string]any tests map[string]bool // package or module directory -> passed digests map[string]string - needs []delivery.PackageNeeds + needs []sdkstep.PackageNeeds } func (r *recorder) steps() AskSteps { @@ -58,12 +56,12 @@ func (r *recorder) steps() AskSteps { } } -func ask(job any) delivery.StepAsk { - a := delivery.StepAsk{ID: sdkstep.NewID(), Kind: delivery.AskCheck, Language: delivery.AskGo, Asker: "t", At: time.Now()} +func ask(job any) sdkstep.StepAsk { + a := sdkstep.StepAsk{ID: sdkstep.NewID(), Kind: sdkstep.AskCheck, Language: sdkstep.AskGo, Asker: "t", At: time.Now()} switch j := job.(type) { - case delivery.BuildJob: + case sdkstep.BuildJob: a.Build = &j - case delivery.CheckJob: + case sdkstep.CheckJob: a.Check = &j } return a @@ -84,15 +82,15 @@ func TestRunAskBuilds(t *testing.T) { return map[string]any{"imports": []string{"git.novox.be/novox/mesh-sdk/go/announce", "git.novox.be/novox/mesh-sdk/go/delivery"}}, nil } // Issue 1585: the ask's package versions reach the fetch, and the ask's own fetch arguments stay as they were. - a := ask(delivery.BuildJob{Module: "m", Path: "modules/m", Publish: true, - Fetch: map[string]any{"repository": "novox/x", "commit": runCommit}, - Artifacts: []delivery.AskArtifact{{Artifact: "base", From: "registry/b@sha256:00"}, {Artifact: "bundle"}, {Artifact: "lib", Seat: "go-package-registry", Version: "v0.1.15"}}}) - a.Packages = delivery.PackageVersions{"git.novox.be/novox/mesh-sdk/go": runCommit} + a := ask(sdkstep.BuildJob{Module: "m", Path: "modules/m", Publish: true, + Fetch: &sdkstep.Fetch{Repository: "novox/x", Commit: runCommit}, + Artifacts: []sdkstep.AskArtifact{{Artifact: "base", From: "registry/b@sha256:00"}, {Artifact: "bundle"}, {Artifact: "lib", Seat: "go-package-registry", Version: "v0.1.15"}}}) + a.Packages = sdkstep.PackageVersions{"git.novox.be/novox/mesh-sdk/go": runCommit} out, err := RunAsk(context.Background(), steps, a) if err != nil { t.Fatal(err) } - if _, put := a.Build.Fetch["packages"]; put { + if len(a.Build.Fetch.Packages) != 0 { t.Error("the ask's fetch arguments were changed") } got := strings.Join(r.calls, "\n") @@ -107,7 +105,7 @@ imports {"module":"modules/m","workspace":"/w/1"}` if len(released) != 1 || released[0] != "/w/1" { t.Errorf("released %v, want the one workspace", released) } - answer := out.(delivery.BuildAnswer) + answer := out.(sdkstep.BuildAnswer) if len(answer.Artifacts) != 3 || answer.Artifacts[1].Reference != "artifact-store://bundle" { t.Fatalf("answer %+v", answer) } @@ -120,18 +118,24 @@ imports {"module":"modules/m","workspace":"/w/1"}` func TestRunAskRefusesAnotherToolchain(t *testing.T) { r := &recorder{fetch: map[string]any{"workspace": "/w"}} s := r.steps() - s.Toolchain = func(context.Context) (delivery.ToolchainUsed, error) { - return delivery.ToolchainUsed{Version: "go1.27", Recipe: "3"}, nil + s.Toolchain = func(context.Context) (sdkstep.ToolchainUsed, error) { + return sdkstep.ToolchainUsed{Version: "go1.27", Recipe: "3"}, nil } - _, err := RunAsk(context.Background(), s, ask(delivery.BuildJob{Module: "m", Path: ".", Fetch: map[string]any{"repository": "novox/x", "commit": runCommit}, - Artifacts: []delivery.AskArtifact{{Artifact: "bundle"}}, Toolchain: &delivery.ToolchainUsed{Version: "go1.26", Recipe: "3"}})) + _, err := RunAsk(context.Background(), s, ask(sdkstep.BuildJob{Module: "m", Path: ".", Fetch: &sdkstep.Fetch{Repository: "novox/x", Commit: runCommit}, + Artifacts: []sdkstep.AskArtifact{{Artifact: "bundle"}}, Toolchain: &sdkstep.ToolchainUsed{Version: "go1.26", Recipe: "3"}})) var dec *Declining if !errors.As(err, &dec) || len(dec.Lacks) != 1 || len(r.calls) != 0 { t.Fatalf("err %v, calls %v", err, r.calls) } - // A check ask names the toolchain too (ADR 0584), and a node on another declines it before it fetches. - _, err = RunAsk(context.Background(), s, ask(delivery.CheckJob{Fetch: map[string]any{"repository": "novox/x", "commit": runCommit}, Levels: []string{delivery.LevelUnit}, - Toolchain: &delivery.ToolchainUsed{Version: "go1.26", Recipe: "3"}})) + // A check ask names the toolchain too (ADR 0584), and a node on another declines it before it fetches. The part's + // CheckJob has no field for it, so the ask's own bytes carry it (askrun_gaps.go). + check := ask(sdkstep.CheckJob{Fetch: sdkstep.Fetch{Repository: "novox/x", Commit: runCommit}, Levels: []string{sdkstep.LevelUnit}}) + raw, _ := json.Marshal(check) + var doc map[string]any + _ = json.Unmarshal(raw, &doc) + doc["check"].(map[string]any)["toolchain"] = map[string]any{"version": "go1.26", "recipe": "3"} + raw, _ = json.Marshal(doc) + _, err = RunAsk(WithCheckToolchain(context.Background(), raw), s, check) if !errors.As(err, &dec) || len(r.calls) != 0 { t.Fatalf("a check ask: err %v, calls %v", err, r.calls) } @@ -146,8 +150,8 @@ func TestRunAskChecksTheLevelsOfOneCheck(t *testing.T) { digests: map[string]string{"x/pkg/a": "d-a", "x/pkg/b": "d-b", "x/pkg/k": "d-kept"}, tests: map[string]bool{"x/pkg/a": true, "x/pkg/b": false}, } - out, err := RunAsk(context.Background(), r.steps(), ask(delivery.CheckJob{Levels: []string{delivery.LevelUnit, delivery.LevelIntegration}, Kept: true, - Runner: "workspace", RunnerWhen: "modules/mesh-build-go/", Fetch: map[string]any{"repository": "novox/x", "commit": runCommit, "base": runCommit}})) + out, err := RunAsk(context.Background(), r.steps(), ask(sdkstep.CheckJob{Levels: []string{sdkstep.LevelUnit, sdkstep.LevelIntegration}, Kept: true, + Runner: "workspace", RunnerWhen: "modules/mesh-build-go/", Fetch: sdkstep.Fetch{Repository: "novox/x", Commit: runCommit, Base: runCommit}})) if err != nil { t.Fatal(err) } @@ -162,20 +166,20 @@ test {"level":"integration","packages":["x/pkg/a"],"workspace":"/w"}` if got != want { t.Fatalf("calls:\n%s\nwant:\n%s", got, want) } - a := out.(delivery.CheckAnswer) + a := out.(CheckAnswer) if len(a.Levels) != 2 { t.Fatalf("levels %+v, want both levels", a.Levels) } u := a.Levels[0] - if u.Level != delivery.LevelUnit || len(u.Kept) != 1 || u.Kept[0].Package != "x/pkg/k" || u.Kept[0].Tests != 7 || len(u.Tests) != 2 || u.Digest == nil { + if u.Level != sdkstep.LevelUnit || len(u.Kept) != 1 || u.Kept[0].Package != "x/pkg/k" || u.Kept[0].Tests != 7 || len(u.Tests) != 2 || u.Digest == nil { t.Fatalf("the unit level %+v", u) } // ADR 0567 §12: a check's node names reach the digest and test tools, for the names check (a kept verdict misses when // they change). r.calls = nil - if _, err := RunAsk(context.Background(), r.steps(), ask(delivery.CheckJob{Levels: []string{delivery.LevelUnit}, NodeNames: []string{"anchor"}, - Fetch: map[string]any{"repository": "novox/x", "commit": runCommit}})); err != nil || !strings.Contains(strings.Join(r.calls, "\n"), `digest {"level":"unit","node-names":["anchor"]`) || + if _, err := RunAsk(context.Background(), r.steps(), ask(sdkstep.CheckJob{Levels: []string{sdkstep.LevelUnit}, NodeNames: []string{"anchor"}, + Fetch: sdkstep.Fetch{Repository: "novox/x", Commit: runCommit}})); err != nil || !strings.Contains(strings.Join(r.calls, "\n"), `digest {"level":"unit","node-names":["anchor"]`) || !strings.Contains(strings.Join(r.calls, "\n"), `test {"level":"unit","node-names":["anchor"]`) { t.Fatalf("the node names are not handed to the digest and test tools: %v, %v", r.calls, err) } @@ -184,19 +188,19 @@ test {"level":"integration","packages":["x/pkg/a"],"workspace":"/w"}` // tested on a node that has it. for _, has := range []bool{false, true} { r.calls, r.tests["x/pkg/b"] = nil, true - r.needs = []delivery.PackageNeeds{{Package: "x/pkg/a", Needs: []string{delivery.NeedNodeBuildNode}}} + r.needs = []sdkstep.PackageNeeds{{Package: "x/pkg/a", Needs: []string{sdkstep.NeedNodeBuildNode}}} steps := r.steps() if has { - steps.Has = func(n string) bool { return n == delivery.NeedNodeBuildNode } + steps.Has = func(n string) bool { return n == sdkstep.NeedNodeBuildNode } } - out, err := RunAsk(context.Background(), steps, ask(delivery.CheckJob{Levels: []string{delivery.LevelUnit}, Kept: true, - Fetch: map[string]any{"repository": "novox/x", "commit": runCommit}})) + out, err := RunAsk(context.Background(), steps, ask(sdkstep.CheckJob{Levels: []string{sdkstep.LevelUnit}, Kept: true, + Fetch: sdkstep.Fetch{Repository: "novox/x", Commit: runCommit}})) if err != nil { t.Fatal(err) } - u := out.(delivery.CheckAnswer).Levels[0] + u := out.(CheckAnswer).Levels[0] tested := strings.Contains(strings.Join(r.calls, "\n"), `"x/pkg/a"`) - if tested != has || (len(u.Unmet) == 0) == !has || (!has && (u.Unmet[0].Package != "x/pkg/a" || delivery.UnmetNeeds([]delivery.LevelAnswer{u})[0] != delivery.NeedNodeBuildNode)) { + if tested != has || (len(u.Unmet) == 0) == !has || (!has && (u.Unmet[0].Package != "x/pkg/a" || sdkstep.UnmetNeeds([]sdkstep.LevelAnswer{u})[0] != sdkstep.NeedNodeBuildNode)) { t.Fatalf("has %v: tested x/pkg/a %v, unmet %+v, calls %v", has, tested, u.Unmet, r.calls) } } @@ -206,12 +210,12 @@ test {"level":"integration","packages":["x/pkg/a"],"workspace":"/w"}` r.calls, r.digests = nil, digests steps := r.steps() steps.Has = func(string) bool { return true } - out, err := RunAsk(context.Background(), steps, ask(delivery.CheckJob{Levels: []string{delivery.LevelUnit}, Kept: true, Packages: []string{"x/pkg/a"}, - Fetch: map[string]any{"repository": "novox/x", "commit": runCommit}})) + out, err := RunAsk(context.Background(), steps, ask(sdkstep.CheckJob{Levels: []string{sdkstep.LevelUnit}, Kept: true, Packages: []string{"x/pkg/a"}, + Fetch: sdkstep.Fetch{Repository: "novox/x", Commit: runCommit}})) if err != nil { t.Fatal(err) } - u := out.(delivery.CheckAnswer).Levels[0] + u := out.(CheckAnswer).Levels[0] if last := r.calls[len(r.calls)-1]; !strings.HasSuffix(last, `"packages":["x/pkg/a"],"workspace":"/w"}`) || len(u.Kept) != 0 || len(u.Tests) != 1 { t.Fatalf("digests %v: calls %v, kept %+v: want x/pkg/a alone tested, nothing taken kept", digests != nil, r.calls, u.Kept) } @@ -235,15 +239,15 @@ test {"level":"unit","runner":"workspace","workspace":"/w"}`}, _, _ = digest(ctx, args) return map[string]any{"level": "unit", "packages": r.digests, "judged_by": tc.judged}, nil } - out, err := RunAsk(context.Background(), steps, ask(delivery.CheckJob{Levels: []string{delivery.LevelUnit}, Kept: true, - Runner: "workspace", RunnerWhen: "modules/mesh-build-go/", Fetch: map[string]any{"repository": "novox/x", "commit": runCommit}})) + out, err := RunAsk(context.Background(), steps, ask(sdkstep.CheckJob{Levels: []string{sdkstep.LevelUnit}, Kept: true, + Runner: "workspace", RunnerWhen: "modules/mesh-build-go/", Fetch: sdkstep.Fetch{Repository: "novox/x", Commit: runCommit}})) if err != nil { t.Fatal(err) } if got := strings.Join(r.calls[1:], "\n"); got != tc.want { t.Errorf("judged by %s: calls\n%s\nwant\n%s", tc.judged, got, tc.want) } - l := out.(delivery.CheckAnswer).Levels[0] + l := out.(CheckAnswer).Levels[0] if tc.judged == "installed" && (len(l.Kept) != 1 || l.Judged != "") { t.Errorf("an installed module's level %+v, want the kept verdict taken", l) } @@ -252,12 +256,12 @@ test {"level":"unit","runner":"workspace","workspace":"/w"}`}, } } r := &recorder{fetch: map[string]any{"workspace": "/w"}, digests: map[string]string{"x/pkg/a": "d-kept"}, tests: map[string]bool{}} - out, err := RunAsk(context.Background(), r.steps(), ask(delivery.CheckJob{Levels: []string{delivery.LevelUnit}, Kept: true, - Fetch: map[string]any{"repository": "novox/x", "commit": runCommit, "beside": []any{map[string]any{"repository": "novox/mesh-sdk", "commit": runCommit}}}})) + out, err := RunAsk(context.Background(), r.steps(), ask(sdkstep.CheckJob{Levels: []string{sdkstep.LevelUnit}, Kept: true, + Fetch: sdkstep.Fetch{Repository: "novox/x", Commit: runCommit, Beside: []sdkstep.FetchBeside{{Repository: "novox/mesh-sdk", Commit: runCommit}}}})) if err != nil { t.Fatal(err) } - if l := out.(delivery.CheckAnswer).Levels[0]; len(l.Kept) != 0 || l.Digest != nil { + if l := out.(CheckAnswer).Levels[0]; len(l.Kept) != 0 || l.Digest != nil { t.Fatalf("a digest without the siblings kept %+v", l) } } @@ -269,15 +273,15 @@ func TestRunAskChecksNodeModulesAndConflicts(t *testing.T) { tests: map[string]bool{"a": true, "b": true}} s := r.steps() s.Digest = nil - if _, err := RunAsk(context.Background(), s, ask(delivery.CheckJob{Levels: []string{delivery.LevelUnit}, Fetch: map[string]any{"repository": "novox/x", "commit": runCommit}})); err != nil { + if _, err := RunAsk(context.Background(), s, ask(sdkstep.CheckJob{Levels: []string{sdkstep.LevelUnit}, Fetch: sdkstep.Fetch{Repository: "novox/x", Commit: runCommit}})); err != nil { t.Fatal(err) } if fmt.Sprint(r.calls[1:]) != `[test {"level":"unit","module":"b","workspace":"/w"} test {"level":"unit","module":"a","workspace":"/w"}]` { t.Fatalf("calls %v", r.calls) } r = &recorder{fetch: map[string]any{"workspace": "/w", "conflicts": []string{"go.mod"}}} - out, err := RunAsk(context.Background(), r.steps(), ask(delivery.CheckJob{Levels: []string{delivery.LevelUnit}, Fetch: map[string]any{"repository": "novox/x", "commit": runCommit}})) - if err != nil || len(r.calls) != 1 || len(out.(delivery.CheckAnswer).Levels) != 0 { + out, err := RunAsk(context.Background(), r.steps(), ask(sdkstep.CheckJob{Levels: []string{sdkstep.LevelUnit}, Fetch: sdkstep.Fetch{Repository: "novox/x", Commit: runCommit}})) + if err != nil || len(r.calls) != 1 || len(out.(CheckAnswer).Levels) != 0 { t.Fatalf("a conflict: %v %v", err, r.calls) } } @@ -301,8 +305,8 @@ func TestRunAskRunsEveryPackageAndLevelAfterAFailure(t *testing.T) { if _, ok := row.tests["x/pkg/c"]; ok { r.digests["x/pkg/c"] = "d-c" } - out, err := RunAsk(context.Background(), r.steps(), ask(delivery.CheckJob{Levels: []string{delivery.LevelUnit, delivery.LevelIntegration}, - Fetch: map[string]any{"repository": "novox/x", "commit": runCommit}})) + out, err := RunAsk(context.Background(), r.steps(), ask(sdkstep.CheckJob{Levels: []string{sdkstep.LevelUnit, sdkstep.LevelIntegration}, + Fetch: sdkstep.Fetch{Repository: "novox/x", Commit: runCommit}})) if err != nil { t.Fatal(err) } @@ -317,7 +321,7 @@ func TestRunAskRunsEveryPackageAndLevelAfterAFailure(t *testing.T) { if want := append(slices.Clone(row.want), row.want...); fmt.Sprint(got) != fmt.Sprint(want) { t.Errorf("%s: tested %v, want %v", row.name, got, want) } - if a := out.(delivery.CheckAnswer); len(a.Levels) != 2 || len(a.Levels[0].Tests) != len(row.want) { + if a := out.(CheckAnswer); len(a.Levels) != 2 || len(a.Levels[0].Tests) != len(row.want) { t.Errorf("%s: levels %+v, want both, each with every test result", row.name, a.Levels) } } @@ -326,12 +330,12 @@ func TestRunAskRunsEveryPackageAndLevelAfterAFailure(t *testing.T) { tests: map[string]bool{"a": true, "b": false}} s := r.steps() s.Digest = nil - out, err := RunAsk(context.Background(), s, ask(delivery.CheckJob{Levels: []string{delivery.LevelUnit, delivery.LevelIntegration}, - Fetch: map[string]any{"repository": "novox/x", "commit": runCommit}})) + out, err := RunAsk(context.Background(), s, ask(sdkstep.CheckJob{Levels: []string{sdkstep.LevelUnit, sdkstep.LevelIntegration}, + Fetch: sdkstep.Fetch{Repository: "novox/x", Commit: runCommit}})) if err != nil { t.Fatal(err) } - if a := out.(delivery.CheckAnswer); len(r.calls) != 5 || len(a.Levels) != 2 || len(a.Levels[0].Tests) != 2 { + if a := out.(CheckAnswer); len(r.calls) != 5 || len(a.Levels) != 2 || len(a.Levels[0].Tests) != 2 { t.Fatalf("calls %v, levels %+v: want b then a at each of the two levels", r.calls, a.Levels) } } diff --git a/modules/mesh-build-go/buildstep/capacity_cpu.go b/modules/mesh-build-go/buildstep/capacity_cpu.go index f8f125403..dc4df230e 100644 --- a/modules/mesh-build-go/buildstep/capacity_cpu.go +++ b/modules/mesh-build-go/buildstep/capacity_cpu.go @@ -3,6 +3,7 @@ package buildstep import ( "encoding/json" "fmt" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "math" "os" "runtime" @@ -10,7 +11,6 @@ import ( "strings" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep/buildcpu" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // **A build seat's capacity follows the CPU its node gives builds** (issue 1806's follow-up; issue 1890, 2026-10-26 @@ -30,7 +30,7 @@ const CoresPerStepSetting = "cores-per-step" // check on mesh-build-go takes what it is given (three at once took 965 % of the workstation's 1200 % slice, about 4 cores each, // and ran past the 30-minute step bound), so a Go step is given 6, half again what starved; a Node step (tsc, esbuild, a // test runner: median 15 s) and an image build (buildah, its RUN lines mostly fetches) need 2. -var DefaultCoresPerStep = map[string]float64{delivery.AskGo: 6, delivery.AskNode: 2, delivery.AskImage: 2} +var DefaultCoresPerStep = map[string]float64{sdkstep.AskGo: 6, sdkstep.AskNode: 2, sdkstep.AskImage: 2} // Quota is the build slice's CPU quota as this process's cgroup holds it, in percent of one processor (1200 is 12 // cores), and where it was read: the cgroup's cpu.max (buildcpu.ReadInForce, the tighter of its unit's and its slice's), @@ -54,11 +54,11 @@ func Quota() (percent int, from string) { // one processor, 0 when none is known) and the cores one of its steps needs. Without a quota it is the configured one; // with one, min(configured, floor(quota cores / coresPerStep)), and one at least while the configured one is above // zero. A coresPerStep of zero or less is taken as 1. -func EffectiveCapacity(configured, quotaPercent int, quotaFrom string, coresPerStep float64) delivery.Capacity { +func EffectiveCapacity(configured, quotaPercent int, quotaFrom string, coresPerStep float64) sdkstep.Capacity { if coresPerStep <= 0 || math.IsNaN(coresPerStep) || math.IsInf(coresPerStep, 0) { coresPerStep = 1 } - c := delivery.Capacity{Configured: configured, Effective: configured, QuotaFrom: quotaFrom, CoresPerStep: coresPerStep} + c := sdkstep.Capacity{Configured: configured, Effective: configured, QuotaFrom: quotaFrom, CoresPerStep: coresPerStep} switch { case configured <= 0: c.Effective = 0 diff --git a/modules/mesh-build-go/buildstep/conformance/conformance_test.go b/modules/mesh-build-go/buildstep/conformance/conformance_test.go index 4fd3b8d1a..a70dd2c98 100644 --- a/modules/mesh-build-go/buildstep/conformance/conformance_test.go +++ b/modules/mesh-build-go/buildstep/conformance/conformance_test.go @@ -3,6 +3,7 @@ package conformance import ( "context" "encoding/json" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" "strings" "testing" "time" @@ -25,14 +26,14 @@ func TestTheFailureContract(t *testing.T) { // 1890/AC7: the SDK's start sweep keeps the left-running case, and the kit refuses a sweep that ends nothing or ends // everything. t.Run("the left-running case", func(t *testing.T) { - LeftRunning(t, func(ctx context.Context, scan sdkstep.Scan, node string, before time.Time, logf func(string, ...any)) { - sdkstep.EndStaleAtStart(ctx, scan, node, before, logf) + LeftRunning(t, func(ctx context.Context, scan buildrun.Scan, node string, before time.Time, logf func(string, ...any)) { + buildrun.EndStaleAtStart(ctx, scan, node, before, logf) }) - if p := JudgeLeftRunning(func(context.Context, sdkstep.Scan, string, time.Time, func(string, ...any)) {}); len(p) != 11 { + if p := JudgeLeftRunning(func(context.Context, buildrun.Scan, string, time.Time, func(string, ...any)) {}); len(p) != 11 { t.Errorf("a sweep that ends nothing: %d problems, want 11 (three steps not ended and unsaid, one owner unnamed, two asks not deleted and unsaid):\n%s", len(p), strings.Join(p, "\n")) } - wrongNode := func(ctx context.Context, scan sdkstep.Scan, _ string, before time.Time, logf func(string, ...any)) { - sdkstep.EndStaleAtStart(ctx, scan, "kitother", before, logf) + wrongNode := func(ctx context.Context, scan buildrun.Scan, _ string, before time.Time, logf func(string, ...any)) { + buildrun.EndStaleAtStart(ctx, scan, "kitother", before, logf) } if p := JudgeLeftRunning(wrongNode); len(p) == 0 { t.Error("a sweep of another node's steps is not refused") diff --git a/modules/mesh-build-go/buildstep/conformance/leftrunning.go b/modules/mesh-build-go/buildstep/conformance/leftrunning.go index 1bd8fddee..5e5bfa303 100644 --- a/modules/mesh-build-go/buildstep/conformance/leftrunning.go +++ b/modules/mesh-build-go/buildstep/conformance/leftrunning.go @@ -10,9 +10,9 @@ import ( "testing" "time" - "git.novox.be/novox/mesh-delivery/sdk/buildstep" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // **A step left running by a previous process** (novox/hq issue 1890, note 21): when a delivery replaced mesh-build-go @@ -23,9 +23,9 @@ import ( // catalogue check (mesh-catalog checks/failurekit) refuses a build module whose tests do not call LeftRunning. // Sweep is a build module's own start sweep, as its main runs it once at its start: it ends node's steps in scan that -// no process of the module runs any more (buildstep.EndStaleAtStart, here with the runtime already serving), before +// no process of the module runs any more (buildrun.EndStaleAtStart, here with the runtime already serving), before // being the start of the process, saying each end with logf. -type Sweep func(ctx context.Context, scan buildstep.Scan, node string, before time.Time, logf func(string, ...any)) +type Sweep func(ctx context.Context, scan buildrun.Scan, node string, before time.Time, logf func(string, ...any)) // LeftNode is the node the case's steps are of. const LeftNode = "kitnode" @@ -47,12 +47,12 @@ func leftCases() []leftCase { {id: "mvpwlkzi7e6ca8", tool: "check ask", owner: gone, age: 5 * time.Minute, deleted: true}, // note 21's ghost {id: "mvpwlkzi7e6ca9", tool: "delivery ask", owner: gone, age: -time.Second, deleted: true}, {id: "gonehand1", tool: "build_x_test", owner: gone, age: time.Minute, ended: true}, - {id: "oldhand1", tool: "build_x_fetch", age: time.Hour, ended: true}, // no owner: an older build's - {id: "mvpwlkzi7e6caa", tool: "check ask", age: time.Hour, ended: true}, // no owner, past the bound - {id: "mvpwlkzi7e6cab", tool: "check ask", age: 5 * time.Minute}, // no owner, the stream's still - {id: "mvpwlkzi7e6cac", tool: "check ask", owner: buildstep.Owner, age: time.Minute}, // this process's - {id: "minehand1", tool: "build_x_test", owner: buildstep.Owner, age: -time.Second}, - {id: "donehand1", tool: "build_x_test", owner: gone, age: time.Hour, state: delivery.StepPassed}, + {id: "oldhand1", tool: "build_x_fetch", age: time.Hour, ended: true}, // no owner: an older build's + {id: "mvpwlkzi7e6caa", tool: "check ask", age: time.Hour, ended: true}, // no owner, past the bound + {id: "mvpwlkzi7e6cab", tool: "check ask", age: 5 * time.Minute}, // no owner, the stream's still + {id: "mvpwlkzi7e6cac", tool: "check ask", owner: buildrun.Owner, age: time.Minute}, // this process's + {id: "minehand1", tool: "build_x_test", owner: buildrun.Owner, age: -time.Second}, + {id: "donehand1", tool: "build_x_test", owner: gone, age: time.Hour, state: sdkstep.StepPassed}, {id: "otherhand1", tool: "build_x_test", owner: gone, age: time.Hour, node: "kitother"}, } } @@ -76,10 +76,10 @@ func JudgeLeftRunning(sweep Sweep) []string { node = LeftNode } if state == "" { - state = delivery.StepRunning + state = sdkstep.StepRunning } - key, _ := delivery.StepKey(node, c.id) - raw, err := delivery.EncodeStep(delivery.Step{ID: c.id, Tool: c.tool, Node: node, State: state, Started: before.Add(-c.age).UTC(), Owner: c.owner}) + key, _ := sdkstep.StepKey(node, c.id) + raw, err := sdkstep.EncodeStep(sdkstep.Step{ID: c.id, Tool: c.tool, Node: node, State: state, Started: before.Add(-c.age).UTC(), Owner: c.owner}) if err != nil { return []string{"the kit's step " + c.id + ": " + err.Error()} } @@ -87,9 +87,9 @@ func JudgeLeftRunning(sweep Sweep) []string { } served := make(chan struct{}) close(served) - was := buildstep.StaleServed - buildstep.StaleServed = func() <-chan struct{} { return served } - defer func() { buildstep.StaleServed = was }() + was := buildrun.StaleServed + buildrun.StaleServed = func() <-chan struct{} { return served } + defer func() { buildrun.StaleServed = was }() var mu sync.Mutex var said []string ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -108,7 +108,7 @@ func JudgeLeftRunning(sweep Sweep) []string { if node == "" { node = LeftNode } - key, _ := delivery.StepKey(node, c.id) + key, _ := sdkstep.StepKey(node, c.id) raw := st.get(key) if c.deleted { if raw != nil { @@ -124,17 +124,17 @@ func JudgeLeftRunning(sweep Sweep) []string { problems = append(problems, "left running: the step "+key+" is gone after the sweep, want it kept or ended") continue } - s, err := delivery.DecodeStep(raw) + s, err := sdkstep.DecodeStep(raw) if err != nil { problems = append(problems, key+": "+err.Error()) continue } want := c.state if want == "" { - want = delivery.StepRunning + want = sdkstep.StepRunning } if c.ended { - want = delivery.StepFailed + want = sdkstep.StepFailed } if s.State != want { problems = append(problems, fmt.Sprintf("left running: the step %s (%s, owner %q, %s before the start) is %s after the sweep, want %s", key, c.tool, c.owner, c.age, s.State, want)) @@ -169,8 +169,8 @@ func (s *steps) get(key string) []byte { return s.vals[key] } -func (s *steps) scan() buildstep.Scan { - return buildstep.Scan{ +func (s *steps) scan() buildrun.Scan { + return buildrun.Scan{ Keys: func() ([]string, error) { s.mu.Lock() defer s.mu.Unlock() diff --git a/modules/mesh-build-go/buildstep/digestshape_test.go b/modules/mesh-build-go/buildstep/digestshape_test.go index aa2b757db..3259f19e6 100644 --- a/modules/mesh-build-go/buildstep/digestshape_test.go +++ b/modules/mesh-build-go/buildstep/digestshape_test.go @@ -5,13 +5,12 @@ import ( "encoding/json" "errors" "fmt" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "sort" "strings" "sync" "testing" "time" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // credentialField is the node runtime's rule for a state value (mesh-tools node-tools/internal/bus/state.go, novox/hq @@ -59,11 +58,11 @@ func credentialField(value json.RawMessage) string { // runtimeState is a steps state that refuses a value as the node runtime does, and keeps every value it took. type runtimeState struct { mu sync.Mutex - took map[string][]delivery.Step + took map[string][]sdkstep.Step refused int } -func newRuntimeState() *runtimeState { return &runtimeState{took: map[string][]delivery.Step{}} } +func newRuntimeState() *runtimeState { return &runtimeState{took: map[string][]sdkstep.Step{}} } func (s *runtimeState) put(key string, value any) (uint64, error) { raw, _ := value.(json.RawMessage) @@ -73,7 +72,7 @@ func (s *runtimeState) put(key string, value any) (uint64, error) { s.mu.Unlock() return 0, fmt.Errorf("steps.%s carries a field %q, which names a credential", key, f) } - st, err := delivery.DecodeStep(raw) + st, err := sdkstep.DecodeStep(raw) if err != nil { return 0, err } @@ -83,12 +82,12 @@ func (s *runtimeState) put(key string, value any) (uint64, error) { return uint64(len(s.took[key])), nil } -func (s *runtimeState) last(key string) (delivery.Step, bool) { +func (s *runtimeState) last(key string) (sdkstep.Step, bool) { s.mu.Lock() defer s.mu.Unlock() t := s.took[key] if len(t) == 0 { - return delivery.Step{}, false + return sdkstep.Step{}, false } return t[len(t)-1], true } @@ -109,8 +108,8 @@ func TestADigestOfAPackageNamedTokenIsStoredAsAList(t *testing.T) { digests: map[string]string{"x/internal/token": "d-token", "x/pkg/a": "d-a"}, tests: map[string]bool{"x/internal/token": true, "x/pkg/a": true}, } - out, err := RunAsk(context.Background(), r.steps(), ask(delivery.CheckJob{Levels: []string{delivery.LevelUnit}, - Fetch: map[string]any{"repository": "novox/x", "commit": runCommit}})) + out, err := RunAsk(context.Background(), r.steps(), ask(sdkstep.CheckJob{Levels: []string{sdkstep.LevelUnit}, + Fetch: sdkstep.Fetch{Repository: "novox/x", Commit: runCommit}})) if err != nil { t.Fatal(err) } @@ -119,21 +118,21 @@ func TestADigestOfAPackageNamedTokenIsStoredAsAList(t *testing.T) { t.Fatalf("the rule does not refuse the form before issue 1930 (%s): the test proves nothing", old) } st := newRuntimeState() - if err := finish(st.put, "shanks.a1", delivery.Step{ID: "a1", Tool: "check ask", Node: "shanks", State: delivery.StepRunning, Started: time.Now()}, out, nil, t.Logf); err != nil { + if err := finish(st.put, "shanks.a1", sdkstep.Step{ID: "a1", Tool: "check ask", Node: "shanks", State: sdkstep.StepRunning, Started: time.Now()}, out, nil, t.Logf); err != nil { t.Fatal(err) } s, ok := st.last("shanks.a1") - if !ok || s.State != delivery.StepPassed || st.refused != 0 { + if !ok || s.State != sdkstep.StepPassed || st.refused != 0 { t.Fatalf("the end %+v (written %v, refused %d), want it passed and taken at once", s, ok, st.refused) } - var a delivery.CheckAnswer + var a CheckAnswer if err := json.Unmarshal(s.Result, &a); err != nil { t.Fatal(err) } if len(a.Levels) != 1 || a.Levels[0].Digest == nil { t.Fatalf("levels %+v, want the unit level with its digest", a.Levels) } - want := []delivery.PackageDigest{{Package: "x/internal/token", Digest: "d-token"}, {Package: "x/pkg/a", Digest: "d-a"}} + want := []sdkstep.PackageDigest{{Package: "x/internal/token", Digest: "d-token"}, {Package: "x/pkg/a", Digest: "d-a"}} if got := a.Levels[0].Digest.Packages; fmt.Sprint(got) != fmt.Sprint(want) { t.Errorf("packages %v, want %v", got, want) } @@ -148,9 +147,9 @@ func TestARefusedEndIsSaidAndEndsTheStepFailed(t *testing.T) { fastEnds(t) big := errors.New("the value carries a field \"x/internal/token\", which names a credential") var refused int - var stored []delivery.Step + var stored []sdkstep.Step put := func(key string, value any) (uint64, error) { - st, _ := delivery.DecodeStep(value.(json.RawMessage)) + st, _ := sdkstep.DecodeStep(value.(json.RawMessage)) if len(st.Result) > 0 { refused++ return 0, big @@ -160,7 +159,7 @@ func TestARefusedEndIsSaidAndEndsTheStepFailed(t *testing.T) { } var logged []string logf := func(format string, args ...any) { logged = append(logged, fmt.Sprintf(format, args...)) } - err := finish(put, "shanks.a2", delivery.Step{ID: "a2", Tool: "check ask", Node: "shanks", State: delivery.StepRunning, Started: time.Now()}, map[string]any{"levels": 1}, nil, logf) + err := finish(put, "shanks.a2", sdkstep.Step{ID: "a2", Tool: "check ask", Node: "shanks", State: sdkstep.StepRunning, Started: time.Now()}, map[string]any{"levels": 1}, nil, logf) if err != nil { t.Fatalf("finish answered %v, want the small end written", err) } @@ -168,7 +167,7 @@ func TestARefusedEndIsSaidAndEndsTheStepFailed(t *testing.T) { t.Fatalf("refused %d, stored %d, want %d refusals and one small end", refused, len(stored), EndAttempts) } s := stored[0] - if s.State != delivery.StepFailed || len(s.Result) != 0 || !strings.Contains(s.Reason, "could not be written") || + if s.State != sdkstep.StepFailed || len(s.Result) != 0 || !strings.Contains(s.Reason, "could not be written") || !strings.Contains(s.Reason, big.Error()) || !strings.Contains(s.Reason, "passed") { t.Errorf("the small end %+v, want failed, no result, naming the write's error and that it passed", s) } @@ -176,7 +175,7 @@ func TestARefusedEndIsSaidAndEndsTheStepFailed(t *testing.T) { t.Errorf("logged %q, want the refusal said", logged) } none := func(string, any) (uint64, error) { return 0, errors.New("the bus is gone") } - if err := finish(none, "shanks.a3", delivery.Step{ID: "a3", Tool: "check ask", Node: "shanks", Started: time.Now()}, nil, nil, logf); err == nil || !strings.Contains(err.Error(), "the bus is gone") { + if err := finish(none, "shanks.a3", sdkstep.Step{ID: "a3", Tool: "check ask", Node: "shanks", Started: time.Now()}, nil, nil, logf); err == nil || !strings.Contains(err.Error(), "the bus is gone") { t.Errorf("finish with no write possible answered %v, want the error", err) } } @@ -192,16 +191,16 @@ func TestAnAskWhoseEndCannotBeWrittenIsNotAcked(t *testing.T) { }{{"the small end written", true, true}, {"no end written", false, false}} { t.Run(tc.name, func(t *testing.T) { src := NewFakeAsks() - a := testAsk(delivery.AskCheck) + a := testAsk(sdkstep.AskCheck) _ = src.PublishAsk(a) var mu sync.Mutex - var ends []delivery.Step + var ends []sdkstep.Step put := func(key string, value any) (uint64, error) { - st, err := delivery.DecodeStep(value.(json.RawMessage)) + st, err := sdkstep.DecodeStep(value.(json.RawMessage)) if err != nil { return 0, err } - if st.State != delivery.StepRunning && (len(st.Result) > 0 || !tc.smallOK) { + if st.State != sdkstep.StepRunning && (len(st.Result) > 0 || !tc.smallOK) { return 0, errors.New("refused") } mu.Lock() @@ -209,9 +208,9 @@ func TestAnAskWhoseEndCannotBeWrittenIsNotAcked(t *testing.T) { mu.Unlock() return 1, nil } - p := &Puller{Source: src, Language: delivery.AskGo, Node: "shanks", Put: put, Capacity: func() int { return 1 }, + p := &Puller{Source: src, Language: sdkstep.AskGo, Node: "shanks", Put: put, Capacity: func() int { return 1 }, PullWait: 10 * time.Millisecond, Logf: t.Logf, - Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { return map[string]any{"ran": true}, nil }} + Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { return map[string]any{"ran": true}, nil }} ctx, cancel := context.WithCancel(context.Background()) defer cancel() go p.Pull(ctx) @@ -225,7 +224,7 @@ func TestAnAskWhoseEndCannotBeWrittenIsNotAcked(t *testing.T) { defer mu.Unlock() if tc.smallOK { last := ends[len(ends)-1] - if last.State != delivery.StepFailed || !strings.Contains(last.Reason, "refused") { + if last.State != sdkstep.StepFailed || !strings.Contains(last.Reason, "refused") { t.Errorf("the end %+v, want the small failed end", last) } } diff --git a/modules/mesh-build-go/buildstep/generated.go b/modules/mesh-build-go/buildstep/generated.go index 202bff454..a3121c061 100644 --- a/modules/mesh-build-go/buildstep/generated.go +++ b/modules/mesh-build-go/buildstep/generated.go @@ -6,7 +6,7 @@ package buildstep // it was built with (its version is this package's requirement, so a new generator is a new build module and a new // fingerprint of what it builds) and names each file out of step: one that differs, one missing, one under a generated // root the generator did not write. The test step fails on any; a trunk build's ask answers them in its out-of-step -// (delivery.BuildAnswer.OutOfStep), so the builder's build end raises generated-types-out-of-step even where no test +// (sdkstep.BuildAnswer.OutOfStep), so the builder's build end raises generated-types-out-of-step even where no test // step runs. Each build module compares its own roots: mesh-build-go `go`, mesh-build-node `ts`. import ( diff --git a/modules/mesh-build-go/buildstep/generated_test.go b/modules/mesh-build-go/buildstep/generated_test.go index 6cbce0b76..d4aa6c42b 100644 --- a/modules/mesh-build-go/buildstep/generated_test.go +++ b/modules/mesh-build-go/buildstep/generated_test.go @@ -3,6 +3,7 @@ package buildstep import ( "context" "errors" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "reflect" @@ -11,7 +12,6 @@ import ( "testing" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep/seatgen" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // contracts writes a contracts module of one seat, its generated files as the generator writes them, and answers its @@ -113,16 +113,16 @@ func TestAContractsModulesGeneratedFilesAreComparedWithTheGenerator(t *testing.T } return map[string]any{"digest": "sha256:aa"}, nil }} - job := delivery.BuildJob{Module: "c", Path: filepath.Base(dir), Fetch: map[string]any{"repository": "novox/c"}, - Artifacts: []delivery.AskArtifact{{Artifact: "go"}}} + job := sdkstep.BuildJob{Module: "c", Path: filepath.Base(dir), Fetch: &sdkstep.Fetch{Repository: "novox/c", Commit: "0123456789abcdef0123456789abcdef01234567"}, + Artifacts: []sdkstep.AskArtifact{{Artifact: "go"}}} out, err := RunAsk(context.Background(), steps, ask(job)) - if a, ok := out.(delivery.BuildAnswer); err != nil || !ok || !reflect.DeepEqual(a.OutOfStep, sorted(goFile, "go/extra.go")) || len(a.Artifacts) != 1 { + if a, ok := out.(sdkstep.BuildAnswer); err != nil || !ok || !reflect.DeepEqual(a.OutOfStep, sorted(goFile, "go/extra.go")) || len(a.Artifacts) != 1 { t.Errorf("the build ask's out-of-step: %+v %v", out, err) } - job.Artifacts = append(job.Artifacts, delivery.AskArtifact{Artifact: "go-other"}) + job.Artifacts = append(job.Artifacts, sdkstep.AskArtifact{Artifact: "go-other"}) built = 0 out, err = RunAsk(context.Background(), steps, ask(job)) - if a, ok := out.(delivery.BuildAnswer); err == nil || !ok || len(a.OutOfStep) != 2 { + if a, ok := out.(sdkstep.BuildAnswer); err == nil || !ok || len(a.OutOfStep) != 2 { t.Errorf("a failed build answered no out-of-step: %+v %v", out, err) } } diff --git a/modules/mesh-build-go/buildstep/go.mod b/modules/mesh-build-go/buildstep/go.mod index edd3078cb..580b727c9 100644 --- a/modules/mesh-build-go/buildstep/go.mod +++ b/modules/mesh-build-go/buildstep/go.mod @@ -3,6 +3,8 @@ module git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep go 1.26.0 require ( + git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildnode v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildimage v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/sdk v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/contracts/go/clients/containerimageregistryclient v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/contracts/go/clients/gopackageregistryclient v0.0.0-00010101000000-000000000000 diff --git a/modules/mesh-build-go/buildstep/guard.go b/modules/mesh-build-go/buildstep/guard.go index a9dc49cd4..b39583f44 100644 --- a/modules/mesh-build-go/buildstep/guard.go +++ b/modules/mesh-build-go/buildstep/guard.go @@ -4,15 +4,13 @@ import ( "context" "encoding/json" "fmt" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // Guard is a build module's check that the toolchain installed on its node is the one its recipe builds with // (novox/hq ADR 0469 §1; issue 1473). The same guard serves ADR 0470 §4's postgres major for the integration // level, with its own Probe and Want. type Guard struct { - // Language is the toolchain's key part: go or typescript (delivery.ToolchainKey). + // Language is the toolchain's key part: go or typescript (ToolchainKey). Language string // Want is the toolchain version the recipe builds with, and Recipe the recipe's own version. The indexer // compares both texts as they are written here. @@ -20,7 +18,7 @@ type Guard struct { // Probe reads the installed version (go version, node --version). Probe func(ctx context.Context) (installed string, err error) Node string - // Put is the toolchains state's Put (stdio.State(delivery.ToolchainsState).Put). + // Put is the toolchains state's Put (stdio.State(the seat's toolchains state).Put). Put Put } @@ -33,11 +31,11 @@ func (g Guard) Check(ctx context.Context) error { if err != nil { return &Refusal{Text: fmt.Sprintf("the installed %s version could not be read: %v", g.Language, err), Want: g.Want} } - key, err := delivery.ToolchainKey(g.Node, g.Language) + key, err := ToolchainKey(g.Node, g.Language) if err != nil { return err } - raw, err := delivery.EncodeToolchain(delivery.Toolchain{Language: g.Language, Version: installed, Recipe: g.Recipe, At: now().UTC()}) + raw, err := EncodeToolchain(Toolchain{Language: g.Language, Version: installed, Recipe: g.Recipe, At: now().UTC()}) if err != nil { return err } diff --git a/modules/mesh-build-go/buildstep/guard_test.go b/modules/mesh-build-go/buildstep/guard_test.go index 30514b1bf..2a0c921e3 100644 --- a/modules/mesh-build-go/buildstep/guard_test.go +++ b/modules/mesh-build-go/buildstep/guard_test.go @@ -6,14 +6,12 @@ import ( "errors" "strings" "testing" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) -type toolchainKeys map[string]delivery.Toolchain +type toolchainKeys map[string]Toolchain func (k toolchainKeys) put(key string, value any) (uint64, error) { - tc, err := delivery.DecodeToolchain(value.(json.RawMessage)) + tc, err := DecodeToolchain(value.(json.RawMessage)) if err != nil { return 0, err } diff --git a/modules/mesh-build-go/buildstep/latepublish.go b/modules/mesh-build-go/buildstep/latepublish.go index dbf0aaf77..c81070703 100644 --- a/modules/mesh-build-go/buildstep/latepublish.go +++ b/modules/mesh-build-go/buildstep/latepublish.go @@ -13,6 +13,7 @@ import ( "context" "errors" "fmt" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "io" "log" "slices" @@ -21,11 +22,10 @@ import ( reg "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" "git.novox.be/novox/mesh-delivery/sdk/parts" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // NumberedPattern is the event type a build module consumes for the late publish, as its manifest's `consumes` names it. -const NumberedPattern = delivery.BuilderModule + "." + delivery.VersionNumberedEvent +const NumberedPattern = builds.BuilderModule + "." + builds.VersionNumberedEvent // errNotHere is a held part's Open: its bytes did not stay on the node. var errNotHere = errors.New("the built bytes did not stay on the node; the holder must hold the digest") @@ -35,7 +35,7 @@ var errNotHere = errors.New("the built bytes did not stay on the node; the holde // kind, another seat (an event naming none is the artifact seat's, as the builder wrote it before images), or a version // numbered with no digest. func LatePublish(ctx context.Context, call SeatCall, body []byte, seat string, kinds ...string) (bool, error) { - n, err := delivery.DecodeVersionNumbered(body) + n, err := builds.DecodeVersionNumbered(body) if err != nil { return false, err } diff --git a/modules/mesh-build-go/buildstep/narrate_test.go b/modules/mesh-build-go/buildstep/narrate_test.go index aa679edf1..21078e8ce 100644 --- a/modules/mesh-build-go/buildstep/narrate_test.go +++ b/modules/mesh-build-go/buildstep/narrate_test.go @@ -5,13 +5,13 @@ import ( "encoding/json" "errors" "fmt" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "strings" "sync" "testing" "time" reg "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // CAT-NR1: a build's publish on a seat says asked, waiting on the seat (on every tick of NarrateEvery while the holder @@ -52,9 +52,9 @@ func TestABuildNarratesItsPublishOnASeat(t *testing.T) { var said []string wrote := make(chan struct{}, 16) - step := delivery.Step{ID: "a1", Tool: "build", Node: "ace", State: delivery.StepRunning, Started: clock} + step := sdkstep.Step{ID: "a1", Tool: "build", Node: "ace", State: sdkstep.StepRunning, Started: clock} ph := &phases{key: "ace.a1", step: step, put: func(key string, value any) (uint64, error) { - var s delivery.Step + var s sdkstep.Step _ = json.Unmarshal(value.(json.RawMessage), &s) phasesMu.Lock() said = append(said, s.Phase) diff --git a/modules/mesh-build-go/buildstep/phase.go b/modules/mesh-build-go/buildstep/phase.go index 130178a39..187d4ea3e 100644 --- a/modules/mesh-build-go/buildstep/phase.go +++ b/modules/mesh-build-go/buildstep/phase.go @@ -2,18 +2,17 @@ package buildstep import ( "context" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "strings" "sync" "time" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // **A running ask says its phases** (issue 1890, 2026-10-26 19:09: a mesh-catalog try's step on the workstation ran 30 minutes // and its module's journal held no line naming its ask, so nobody could tell whether it fetched, linted or tested). The // puller hands every ask's run a phase reporter in its context; RunAsk and a module's own step bodies call Phase as they // move (fetch and merge, a level's digest, lint, a level's tests), and each phase is logged with the ask's id and its -// time since the start, and written to the ask's running step key (delivery.Step.Phase), so its asker and the delivery +// time since the start, and written to the ask's running step key (sdkstep.Step.Phase), so its asker and the delivery // view read where it stands from the bus. type phaseKey struct{} @@ -30,7 +29,7 @@ type phases struct { mu sync.Mutex put Put key string - step delivery.Step + step sdkstep.Step ended bool logf func(format string, args ...any) prefix string @@ -59,7 +58,7 @@ func (r *phases) enter(phase string) { } // end stops the writes (the step's end is written after it) and answers the step with its last phase, for the end. -func (r *phases) end() delivery.Step { +func (r *phases) end() sdkstep.Step { r.mu.Lock() defer r.mu.Unlock() r.ended = true diff --git a/modules/mesh-build-go/buildstep/pull.go b/modules/mesh-build-go/buildstep/pull.go index 7647bab54..abbc9386b 100644 --- a/modules/mesh-build-go/buildstep/pull.go +++ b/modules/mesh-build-go/buildstep/pull.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "sort" "strings" @@ -12,7 +13,6 @@ import ( "time" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // **The pull loop the build modules share** (novox/hq ADR 0525 §4-§6, ADR 0536 §4; issue 1887). A build module on a node @@ -55,23 +55,23 @@ var ( // Puller pulls a build seat's asks and runs them. type Puller struct { Source AskSource - Language string // the seat's language: delivery.AskGo, AskNode or AskImage + Language string // the seat's language: sdkstep.AskGo, AskNode or AskImage Node string // the node this holder runs on, the first part of its step keys Put Put // writes the module's steps state // Capacity is how many asks the node runs at once; read before every pull, so a change takes effect at the next // one. 0 pulls nothing. Capacity func() int // Run runs one ask's job; a *Refusal ends its step refused. Its result is the step's result. - Run func(ctx context.Context, ask delivery.StepAsk) (any, error) + Run func(ctx context.Context, ask sdkstep.StepAsk) (any, error) // PullWait and Heartbeat default to DefaultPullWait and DefaultHeartbeat. PullWait time.Duration Heartbeat time.Duration Logf func(format string, args ...any) // Load reads one key of the state the node's pause is kept in (nil and no error when it is absent). When set, Pull - // reads the node's pause key (delivery.PauseKey) before it pulls, and Pause and Resume write it with PausePut, so a + // reads the node's pause key (sdkstep.PauseKey) before it pulls, and Pause and Resume write it with PausePut, so a // pause outlives a restart. Load func(key string) ([]byte, error) - // PausePut writes the node's pause key: the module's pauses state (delivery.PausesState), which has no age, so a + // PausePut writes the node's pause key: the module's pauses state (sdkstep.PausesState), which has no age, so a // pause never ends by itself while the steps state drops its old keys. Put when nil. PausePut Put // WatchConfig, when set, follows the module's config value `capacity` (CapacitySetting) as mesh-config resolves it @@ -94,8 +94,8 @@ type Puller struct { // taken, and the asks go to a node that can run them instead of failing here. The module calls Wake when its answer // changes. Nil is always eligible. Eligible func() string - // Has says whether this node has a need an ask names (delivery.AskNeeds, issue 890). An ask needing what it lacks is - // declined: its step ends refused as declined (delivery.StepDeclined), the message is dropped for its asker to put + // Has says whether this node has a need an ask names (sdkstep.AskNeeds, issue 890). An ask needing what it lacks is + // declined: its step ends refused as declined (sdkstep.StepDeclined), the message is dropped for its asker to put // again, and the worker it came from is not looked at again until the next pull's wait, so a node lacking the need // does not take the asker's next copy at once. Nil has nothing. Has func(need string) bool @@ -129,7 +129,7 @@ type Puller struct { hoursFault string hasHours bool // judged is the capacity said last (log and capacity.), so a change is said once. - judged delivery.Capacity + judged sdkstep.Capacity hasJudged bool capWritten bool capFault string @@ -166,11 +166,11 @@ func (p *Puller) Resume(by string) error { return p.setPaused(false, by) } func (p *Puller) setPaused(paused bool, by string) error { if p.Load != nil { - key, err := delivery.PauseKey(p.Node) + key, err := sdkstep.PauseKey(p.Node) if err != nil { return err } - raw, err := delivery.EncodePause(delivery.Pause{Paused: paused, By: by, At: now()}) + raw, err := sdkstep.EncodePause(sdkstep.Pause{Paused: paused, By: by, At: now()}) if err != nil { return err } @@ -194,7 +194,7 @@ func (p *Puller) restore() error { if p.Load == nil { return nil } - key, err := delivery.PauseKey(p.Node) + key, err := sdkstep.PauseKey(p.Node) if err != nil { return err } @@ -205,7 +205,7 @@ func (p *Puller) restore() error { if raw == nil { return nil } - v, err := delivery.DecodePause(raw) + v, err := sdkstep.DecodePause(raw) if err != nil { return fmt.Errorf("buildstep: the pause of %s: %w", p.Node, err) } @@ -287,7 +287,7 @@ func (p *Puller) CapacityNow() int { // else Capacity), bounded by the node's build slice when CoresPerStep is set (EffectiveCapacity), its quota read now. A // change from what it said last is logged and written to `capacity.` of the pauses state (PausePut), so the // delivery view says it too. -func (p *Puller) CapacityDetail() delivery.Capacity { +func (p *Puller) CapacityDetail() sdkstep.Capacity { p.mu.Lock() watched, has := p.watched, p.hasWatched p.mu.Unlock() @@ -307,9 +307,9 @@ func (p *Puller) CapacityDetail() delivery.Capacity { case p.Capacity != nil: configured = p.Capacity() } - var c delivery.Capacity + var c sdkstep.Capacity if p.CoresPerStep == nil { - c = delivery.Capacity{Configured: configured, Effective: configured, QuotaFrom: "not judged: the module names no cores a step needs", + c = sdkstep.Capacity{Configured: configured, Effective: configured, QuotaFrom: "not judged: the module names no cores a step needs", Why: fmt.Sprintf("its configured capacity %d", configured)} } else { quota := p.Quota @@ -375,7 +375,7 @@ func (p *Puller) untilEdge() (time.Duration, bool) { // sayCapacity logs c when it differs from what was said last, and writes it to the node's capacity key until a write // lands (a failed write is tried again at the next judgement, its error said once). -func (p *Puller) sayCapacity(c delivery.Capacity) { +func (p *Puller) sayCapacity(c sdkstep.Capacity) { p.mu.Lock() same := p.hasJudged && p.judged.Effective == c.Effective && p.judged.Configured == c.Configured && p.judged.ByCPU == c.ByCPU && p.judged.CoresPerStep == c.CoresPerStep && p.judged.QuotaCores == c.QuotaCores && p.judged.OutsideHours == c.OutsideHours && @@ -392,12 +392,12 @@ func (p *Puller) sayCapacity(c delivery.Capacity) { if !write { return } - key, err := delivery.CapacityKey(p.Node) + key, err := sdkstep.CapacityKey(p.Node) if err != nil { return } c.At = now() - raw, err := delivery.EncodeCapacity(c) + raw, err := sdkstep.EncodeCapacity(c) if err == nil { _, err = p.PausePut(key, json.RawMessage(raw)) } @@ -493,7 +493,7 @@ func (p *Puller) next(ctx context.Context, wait time.Duration) (*Pulled, error) p.mu.Lock() declined := p.declined p.mu.Unlock() - for _, kind := range delivery.AskKinds { + for _, kind := range sdkstep.AskKinds { if declined[kind] { continue } @@ -502,24 +502,24 @@ func (p *Puller) next(ctx context.Context, wait time.Duration) (*Pulled, error) return withKind(msg, kind), err } } - msg, err := p.Source.Next(ctx, delivery.AskDelivery, wait) + msg, err := p.Source.Next(ctx, sdkstep.AskDelivery, wait) p.mu.Lock() p.declined = nil p.mu.Unlock() - return withKind(msg, delivery.AskDelivery), err + return withKind(msg, sdkstep.AskDelivery), err } // decline ends the step of an ask this node lacks a need of, refused as declined with what it lacks, and drops the // message: the asker puts the ask again under a new id (issue 890). A message whose decline cannot be written is handed // back, as one whose start cannot be. -func (p *Puller) decline(msg *Pulled, ask delivery.StepAsk, lacks []string) { - step, key, err := begin(p.Put, p.Node, ask.Kind+" ask", ask.ID, sdkstep.AskWhat(askRead(ask))) +func (p *Puller) decline(msg *Pulled, ask sdkstep.StepAsk, lacks []string) { + step, key, err := begin(p.Put, p.Node, ask.Kind+" ask", ask.ID, buildrun.AskWhat(askRead(ask))) if err == nil { why := Refuse("the ask %s needs %s, and %s lacks %s: it is left to a node that has it", ask.ID, strings.Join(ask.Needs, ", "), p.Node, strings.Join(lacks, ", ")) step.Ended = now().UTC() - step.State, step.Reason = delivery.StepRefused, why.Error() - step.Result, err = json.Marshal(delivery.StepDeclined{Declined: true, Needs: ask.Needs, Lacks: lacks}) + step.State, step.Reason = sdkstep.StepRefused, why.Error() + step.Result, err = json.Marshal(sdkstep.StepDeclined{Declined: true, Needs: ask.Needs, Lacks: lacks}) if err == nil { err = writeEnd(p.Put, key, step) } @@ -542,10 +542,10 @@ func (p *Puller) decline(msg *Pulled, ask delivery.StepAsk, lacks []string) { // declineRun ends the step of an ask that began and then found this node should not run it (Declining), as decline does // before it begins: refused as declined, the message dropped for its asker to put again, and the worker it came from left // alone until the next pull's wait. -func (p *Puller) declineRun(msg *Pulled, ask delivery.StepAsk, key string, step delivery.Step, d *Declining) { - result, _ := json.Marshal(delivery.StepDeclined{Declined: true, Needs: ask.Needs, Lacks: d.Lacks}) +func (p *Puller) declineRun(msg *Pulled, ask sdkstep.StepAsk, key string, step sdkstep.Step, d *Declining) { + result, _ := json.Marshal(sdkstep.StepDeclined{Declined: true, Needs: ask.Needs, Lacks: d.Lacks}) step.Ended = now().UTC() - step.State, step.Reason, step.Result = delivery.StepRefused, d.Text, result + step.State, step.Reason, step.Result = sdkstep.StepRefused, d.Text, result if err := writeEnd(p.Put, key, step); err != nil { p.logf("the ask %s cannot be declined on %s, so it is given back: %v", ask.ID, p.Node, err) _ = msg.Nak() @@ -571,7 +571,7 @@ func withKind(msg *Pulled, kind string) *Pulled { // take starts one ask: it decodes it, refuses one that is not of this seat, and runs it as a step under its own id. func (p *Puller) take(ctx context.Context, msg *Pulled) { kind := msg.Kind - ask, err := delivery.DecodeStepAsk(msg.Data) + ask, err := sdkstep.DecodeStepAsk(msg.Data) if err == nil && (ask.Language != p.Language || (kind != "" && ask.Kind != kind)) { err = fmt.Errorf("the ask %s is a %s ask of %s, pulled from the %s %s worker", ask.ID, ask.Kind, ask.Language, p.Language, kind) } @@ -581,17 +581,17 @@ func (p *Puller) take(ctx context.Context, msg *Pulled) { _ = msg.Term() return } - if lacks := delivery.Lacks(ask.Needs, p.Has); len(lacks) > 0 { + if lacks := sdkstep.Lacks(ask.Needs, p.Has); len(lacks) > 0 { p.decline(msg, ask, lacks) return } - step, key, err := begin(p.Put, p.Node, ask.Kind+" ask", ask.ID, sdkstep.AskWhat(askRead(ask))) + step, key, err := begin(p.Put, p.Node, ask.Kind+" ask", ask.ID, buildrun.AskWhat(askRead(ask))) if err != nil { p.logf("the ask %s cannot start on %s: %v", ask.ID, p.Node, err) _ = msg.Nak() return } - if msg.Delivered > delivery.AskRuns { + if msg.Delivered > sdkstep.AskRuns { // Run AskRuns times and never ended: each run took its node down or died with it. It is run no more, and said // (issue 1907): the asker's key fails with why. why := fmt.Errorf("the ask was taken %d times and no run of it ended: each took its build node down or died with it, so it is run no more (poison)", msg.Delivered-1) @@ -615,7 +615,7 @@ func (p *Puller) take(ctx context.Context, msg *Pulled) { go p.run(ctx, msg, ask, key, step) } -func (p *Puller) run(ctx context.Context, msg *Pulled, ask delivery.StepAsk, key string, step delivery.Step) { +func (p *Puller) run(ctx context.Context, msg *Pulled, ask sdkstep.StepAsk, key string, step sdkstep.Step) { defer func() { p.mu.Lock() p.inHand-- @@ -644,7 +644,7 @@ func (p *Puller) run(ctx context.Context, msg *Pulled, ask delivery.StepAsk, key }() ph := &phases{put: p.Put, key: key, step: step, logf: p.Logf, prefix: fmt.Sprintf("the %s ask %s on %s", ask.Kind, ask.ID, p.Node)} result, err := protect(ctx, func(ctx context.Context) (any, error) { - return p.Run(context.WithValue(ctx, phaseKey{}, ph), ask) + return p.Run(WithCheckToolchain(context.WithValue(ctx, phaseKey{}, ph), msg.Data), ask) }) step = ph.end() // its end keeps the phase it ended in close(done) @@ -798,12 +798,9 @@ func (p *Puller) capacityFrom(c stdio.ProvisionChange) (int, string) { return n, "" } -// askRead is the part of an ask that mesh-delivery-sdk's AskWhat reads, taken from the ask's own layout (the part -// build-step's StepAsk is the same JSON). -func askRead(ask delivery.StepAsk) sdkstep.Ask { - var out sdkstep.Ask - if raw, err := json.Marshal(ask); err == nil { - _ = json.Unmarshal(raw, &out) - } +// askRead is the part of an ask that buildrun.AskWhat reads, taken from the ask's own layout by the one conversion the +// neutral form has (sdkstep.AskAs); an ask that does not convert reads as empty and is described by its kind alone. +func askRead(ask sdkstep.StepAsk) sdkstep.Ask { + out, _ := sdkstep.AskAs[sdkstep.Ask](ask) return out } diff --git a/modules/mesh-build-go/buildstep/pull_bus.go b/modules/mesh-build-go/buildstep/pull_bus.go index 99380838e..cbdafc71e 100644 --- a/modules/mesh-build-go/buildstep/pull_bus.go +++ b/modules/mesh-build-go/buildstep/pull_bus.go @@ -3,16 +3,15 @@ package buildstep import ( "context" "fmt" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "sync" "time" "github.com/nats-io/nats.go/jetstream" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // JetStreamAsks is a build seat's workers on the bus: the shared pull consumer of each kind on the seat's stream -// (delivery.AskStream, AskWorker), which the broker makes when the seat is declared; a holder only binds them. +// (sdkstep.AskStream, AskWorker), which the broker makes when the seat is declared; a holder only binds them. type JetStreamAsks struct { JS jetstream.JetStream Language string @@ -27,11 +26,11 @@ func (s *JetStreamAsks) consumer(ctx context.Context, kind string) (jetstream.Co if c, ok := s.cons[kind]; ok { return c, nil } - stream, err := delivery.AskStream(s.Language) + stream, err := sdkstep.AskStream(s.Language) if err != nil { return nil, err } - worker, err := delivery.AskWorker(s.Language, kind) + worker, err := sdkstep.AskWorker(s.Language, kind) if err != nil { return nil, err } @@ -81,18 +80,18 @@ func (s *JetStreamAsks) Next(ctx context.Context, kind string, wait time.Duratio // modules' integration tests start one). On the mesh the broker declares them from the seat, as it declares every // seat's stream (mesh-controller internal/broker SeatStreams); a holder never does. func DeclareAskWorkers(ctx context.Context, js jetstream.JetStream, language string, ackWait time.Duration) error { - stream, err := delivery.AskStream(language) + stream, err := sdkstep.AskStream(language) if err != nil { return err } - seat, _ := delivery.BuildSeat(language) + seat, _ := sdkstep.BuildSeat(language) if _, err := js.CreateOrUpdateStream(ctx, jetstream.StreamConfig{Name: stream, Subjects: []string{"mesh.seat." + seat + ".accept.>"}, Retention: jetstream.WorkQueuePolicy}); err != nil { return fmt.Errorf("the stream %s: %w", stream, err) } - for _, kind := range delivery.AskKinds { - worker, _ := delivery.AskWorker(language, kind) - subject, _ := delivery.AskSubject(language, kind) + for _, kind := range sdkstep.AskKinds { + worker, _ := sdkstep.AskWorker(language, kind) + subject, _ := sdkstep.AskSubject(language, kind) if _, err := js.CreateOrUpdateConsumer(ctx, stream, jetstream.ConsumerConfig{Durable: worker, FilterSubject: subject, AckPolicy: jetstream.AckExplicitPolicy, AckWait: ackWait, MaxDeliver: 5}); err != nil { return fmt.Errorf("the worker %s: %w", worker, err) diff --git a/modules/mesh-build-go/buildstep/pull_fake.go b/modules/mesh-build-go/buildstep/pull_fake.go index 1e10e4afd..3ba5766e8 100644 --- a/modules/mesh-build-go/buildstep/pull_fake.go +++ b/modules/mesh-build-go/buildstep/pull_fake.go @@ -2,10 +2,9 @@ package buildstep import ( "context" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "sync" "time" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // FakeAsks is a test double of a seat's workers for the build modules' unit tests: Publish puts an ask on a kind's @@ -38,8 +37,8 @@ func (f *FakeAsks) Publish(kind string, data []byte) { } // PublishAsk encodes a and puts it on its kind's worker. -func (f *FakeAsks) PublishAsk(a delivery.StepAsk) error { - raw, err := delivery.EncodeStepAsk(a) +func (f *FakeAsks) PublishAsk(a sdkstep.StepAsk) error { + raw, err := sdkstep.EncodeStepAsk(a) if err != nil { return err } @@ -93,7 +92,7 @@ func (f *FakeAsks) Next(ctx context.Context, kind string, wait time.Duration) (* func (f *FakeAsks) pulled(data []byte) *Pulled { id := string(data) - if a, err := delivery.DecodeStepAsk(data); err == nil { + if a, err := sdkstep.DecodeStepAsk(data); err == nil { id = a.ID } fate := func(list *[]string) func() error { diff --git a/modules/mesh-build-go/buildstep/pull_integration_test.go b/modules/mesh-build-go/buildstep/pull_integration_test.go index c210e4bcd..e8425771a 100644 --- a/modules/mesh-build-go/buildstep/pull_integration_test.go +++ b/modules/mesh-build-go/buildstep/pull_integration_test.go @@ -4,6 +4,7 @@ package buildstep import ( "context" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "strings" "sync" "testing" @@ -12,7 +13,6 @@ import ( "github.com/nats-io/nats.go" "github.com/nats-io/nats.go/jetstream" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/testbus" ) @@ -27,19 +27,19 @@ func askBus(t *testing.T, ackWait time.Duration) jetstream.JetStream { if err != nil { t.Fatal(err) } - if err := DeclareAskWorkers(context.Background(), js, delivery.AskGo, ackWait); err != nil { + if err := DeclareAskWorkers(context.Background(), js, sdkstep.AskGo, ackWait); err != nil { t.Fatal(err) } return js } -func publishAsk(t *testing.T, js jetstream.JetStream, a delivery.StepAsk) { +func publishAsk(t *testing.T, js jetstream.JetStream, a sdkstep.StepAsk) { t.Helper() - raw, err := delivery.EncodeStepAsk(a) + raw, err := sdkstep.EncodeStepAsk(a) if err != nil { t.Fatal(err) } - subject, _ := delivery.AskSubject(a.Language, a.Kind) + subject, _ := sdkstep.AskSubject(a.Language, a.Kind) if _, err := js.Publish(context.Background(), subject, raw); err != nil { t.Fatal(err) } @@ -49,7 +49,7 @@ func publishAsk(t *testing.T, js jetstream.JetStream, a delivery.StepAsk) { // with capacity 2 and three asks two run, the third waits in the stream and starts when one ends. func TestPullOrderAndCapacityOnTheBus(t *testing.T) { js := askBus(t, 30*time.Second) - check, first, second := testAsk(delivery.AskCheck), testAsk(delivery.AskDelivery), testAsk(delivery.AskDelivery) + check, first, second := testAsk(sdkstep.AskCheck), testAsk(sdkstep.AskDelivery), testAsk(sdkstep.AskDelivery) publishAsk(t, js, check) publishAsk(t, js, first) publishAsk(t, js, second) @@ -57,9 +57,9 @@ func TestPullOrderAndCapacityOnTheBus(t *testing.T) { var mu sync.Mutex var order []string st := newSteps() - p := &Puller{Source: &JetStreamAsks{JS: js, Language: delivery.AskGo}, Language: delivery.AskGo, Node: "shanks", Put: st.put, + p := &Puller{Source: &JetStreamAsks{JS: js, Language: sdkstep.AskGo}, Language: sdkstep.AskGo, Node: "shanks", Put: st.put, Capacity: func() int { return 2 }, PullWait: 200 * time.Millisecond, - Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { + Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { mu.Lock() order = append(order, a.ID) mu.Unlock() @@ -80,9 +80,9 @@ func TestPullOrderAndCapacityOnTheBus(t *testing.T) { waitFor(t, "the check taken", func() bool { mu.Lock(); defer mu.Unlock(); return len(order) == 3 }) close(release) waitFor(t, "every step ended", func() bool { - for _, a := range []delivery.StepAsk{check, first, second} { - key, _ := delivery.AskStepKey("shanks", a.ID) - if s, ok := st.get(key); !ok || s.State != delivery.StepPassed { + for _, a := range []sdkstep.StepAsk{check, first, second} { + key, _ := sdkstep.AskStepKey("shanks", a.ID) + if s, ok := st.get(key); !ok || s.State != sdkstep.StepPassed { return false } } @@ -102,13 +102,13 @@ func TestPullOrderAndCapacityOnTheBus(t *testing.T) { // whose step key names the reference. func TestPullRedeliversAKilledPullersAsk(t *testing.T) { js := askBus(t, 2*time.Second) - a := testAsk(delivery.AskDelivery) + a := testAsk(sdkstep.AskDelivery) publishAsk(t, js, a) st := newSteps() taken := make(chan struct{}) - dying := &Puller{Source: &JetStreamAsks{JS: js, Language: delivery.AskGo}, Language: delivery.AskGo, Node: "ace", Put: st.put, + dying := &Puller{Source: &JetStreamAsks{JS: js, Language: sdkstep.AskGo}, Language: sdkstep.AskGo, Node: "ace", Put: st.put, Capacity: func() int { return 1 }, PullWait: 200 * time.Millisecond, Heartbeat: time.Hour, - Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { + Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { close(taken) <-ctx.Done() return nil, ctx.Err() @@ -117,18 +117,18 @@ func TestPullRedeliversAKilledPullersAsk(t *testing.T) { go dying.Pull(kill) <-taken killed() - other := &Puller{Source: &JetStreamAsks{JS: js, Language: delivery.AskGo}, Language: delivery.AskGo, Node: "shanks", Put: st.put, + other := &Puller{Source: &JetStreamAsks{JS: js, Language: sdkstep.AskGo}, Language: sdkstep.AskGo, Node: "shanks", Put: st.put, Capacity: func() int { return 1 }, PullWait: 200 * time.Millisecond, - Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { - return delivery.BuildAnswer{Artifacts: []delivery.AskBuilt{{Artifact: "bundle", Digest: "sha256:00", Reference: "artifact-store://x"}}}, nil + Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { + return sdkstep.BuildAnswer{Artifacts: []sdkstep.AskBuilt{{Artifact: "bundle", Digest: "sha256:00", Reference: "artifact-store://x"}}}, nil }} ctx, cancel := context.WithCancel(context.Background()) defer cancel() go other.Pull(ctx) - key, _ := delivery.AskStepKey("shanks", a.ID) + key, _ := sdkstep.AskStepKey("shanks", a.ID) deadline := time.Now().Add(10 * time.Second) for { - if s, ok := st.get(key); ok && s.State == delivery.StepPassed { + if s, ok := st.get(key); ok && s.State == sdkstep.StepPassed { if want := `artifact-store://x`; !contains(string(s.Result), want) { t.Fatalf("the step's result %s names no %s", s.Result, want) } diff --git a/modules/mesh-build-go/buildstep/pull_seat.go b/modules/mesh-build-go/buildstep/pull_seat.go index 1a8680fbb..7c466420b 100644 --- a/modules/mesh-build-go/buildstep/pull_seat.go +++ b/modules/mesh-build-go/buildstep/pull_seat.go @@ -2,10 +2,10 @@ package buildstep import ( "context" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "time" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // SeatAsks is a build seat's workers as a tools bundle reaches them: through its runtime's seat pull and settle @@ -27,7 +27,7 @@ func (s SeatAsks) Next(ctx context.Context, kind string, wait time.Duration) (*P if settle == nil { settle = stdio.SeatSettle } - worker, err := delivery.AskWorker(s.Language, kind) + worker, err := sdkstep.AskWorker(s.Language, kind) if err != nil { return nil, err } diff --git a/modules/mesh-build-go/buildstep/pull_seat_test.go b/modules/mesh-build-go/buildstep/pull_seat_test.go index 7d707822b..aa1c7bdd7 100644 --- a/modules/mesh-build-go/buildstep/pull_seat_test.go +++ b/modules/mesh-build-go/buildstep/pull_seat_test.go @@ -2,18 +2,18 @@ package buildstep import ( "context" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "testing" "time" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // 1887/A11: a bundle's source pulls the kind's worker by its seat's name and settles each ask by the runtime's id. func TestSeatAsksPullsTheKindsWorkerAndSettlesByID(t *testing.T) { var pulled []string var settled []string - src := SeatAsks{Language: delivery.AskGo, + src := SeatAsks{Language: sdkstep.AskGo, Pull: func(worker string, wait time.Duration) (*stdio.Pulled, error) { pulled = append(pulled, worker) if worker != "SEAT_NODE_BUILD_GO_CHECK_worker" { @@ -22,10 +22,10 @@ func TestSeatAsksPullsTheKindsWorkerAndSettlesByID(t *testing.T) { return &stdio.Pulled{ID: "p9", Worker: worker, Body: []byte(`{"v":1}`), Delivered: 2}, nil }, Settle: func(id, fate string) error { settled = append(settled, id+" "+fate); return nil }} - if p, err := src.Next(context.Background(), delivery.AskDelivery, 0); err != nil || p != nil { + if p, err := src.Next(context.Background(), sdkstep.AskDelivery, 0); err != nil || p != nil { t.Fatalf("delivery = %+v, %v", p, err) } - p, err := src.Next(context.Background(), delivery.AskCheck, time.Second) + p, err := src.Next(context.Background(), sdkstep.AskCheck, time.Second) if err != nil || p == nil || string(p.Data) != `{"v":1}` || p.Delivered != 2 { t.Fatalf("check = %+v, %v", p, err) } diff --git a/modules/mesh-build-go/buildstep/pull_test.go b/modules/mesh-build-go/buildstep/pull_test.go index 9258b5d0e..999af3855 100644 --- a/modules/mesh-build-go/buildstep/pull_test.go +++ b/modules/mesh-build-go/buildstep/pull_test.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" @@ -15,20 +16,19 @@ import ( "time" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // steps records a steps state's puts: the last value of each key. type steps struct { mu sync.Mutex - keys map[string]delivery.Step + keys map[string]sdkstep.Step } -func newSteps() *steps { return &steps{keys: map[string]delivery.Step{}} } +func newSteps() *steps { return &steps{keys: map[string]sdkstep.Step{}} } func (s *steps) put(key string, value any) (uint64, error) { raw, _ := value.(json.RawMessage) - st, err := delivery.DecodeStep(raw) + st, err := sdkstep.DecodeStep(raw) if err != nil { return 0, err } @@ -38,28 +38,28 @@ func (s *steps) put(key string, value any) (uint64, error) { return 1, nil } -func (s *steps) get(key string) (delivery.Step, bool) { +func (s *steps) get(key string) (sdkstep.Step, bool) { s.mu.Lock() defer s.mu.Unlock() st, ok := s.keys[key] return st, ok } -func testAsk(kind string) delivery.StepAsk { +func testAsk(kind string) sdkstep.StepAsk { id := sdkstep.NewID() - a := delivery.StepAsk{ID: id, Kind: kind, Language: delivery.AskGo, Asker: "mesh-delivery-builder", At: time.Now()} - fetch := map[string]any{"repository": "novox/x", "commit": "0123456789abcdef0123456789abcdef01234567"} - if kind == delivery.AskDelivery { + a := sdkstep.StepAsk{ID: id, Kind: kind, Language: sdkstep.AskGo, Asker: "mesh-delivery-builder", At: time.Now()} + fetch := sdkstep.Fetch{Repository: "novox/x", Commit: "0123456789abcdef0123456789abcdef01234567"} + if kind == sdkstep.AskDelivery { b := buildJobFixture - b.Fetch = fetch + b.Fetch = &fetch a.Build = &b } else { - a.Check = &delivery.CheckJob{Fetch: fetch, Levels: []string{delivery.LevelUnit}} + a.Check = &sdkstep.CheckJob{Fetch: fetch, Levels: []string{sdkstep.LevelUnit}} } return a } -var buildJobFixture = delivery.BuildJob{Module: "m", Path: ".", Artifacts: []delivery.AskArtifact{{Artifact: "bundle"}}} +var buildJobFixture = sdkstep.BuildJob{Module: "m", Path: ".", Artifacts: []sdkstep.AskArtifact{{Artifact: "bundle"}}} func waitFor(t *testing.T, what string, cond func() bool) { t.Helper() @@ -75,16 +75,16 @@ func waitFor(t *testing.T, what string, cond func() bool) { // 1887/A2a: given a check ask published before a delivery ask and one slot, the delivery ask runs first. func TestPullTakesDeliveryBeforeCheck(t *testing.T) { src, st := NewFakeAsks(), newSteps() - check, recheck, deliver := testAsk(delivery.AskCheck), testAsk(delivery.AskRecheck), testAsk(delivery.AskDelivery) - for _, a := range []delivery.StepAsk{recheck, check, deliver} { + check, recheck, deliver := testAsk(sdkstep.AskCheck), testAsk(sdkstep.AskRecheck), testAsk(sdkstep.AskDelivery) + for _, a := range []sdkstep.StepAsk{recheck, check, deliver} { if err := src.PublishAsk(a); err != nil { t.Fatal(err) } } var mu sync.Mutex var order []string - p := &Puller{Source: src, Language: delivery.AskGo, Node: "shanks", Put: st.put, Capacity: func() int { return 1 }, - PullWait: 10 * time.Millisecond, Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { + p := &Puller{Source: src, Language: sdkstep.AskGo, Node: "shanks", Put: st.put, Capacity: func() int { return 1 }, + PullWait: 10 * time.Millisecond, Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { mu.Lock() order = append(order, a.Kind) mu.Unlock() @@ -96,12 +96,12 @@ func TestPullTakesDeliveryBeforeCheck(t *testing.T) { waitFor(t, "three asks acked", func() bool { a, _, _ := src.Fates(); return len(a) == 3 }) mu.Lock() defer mu.Unlock() - if want := []string{delivery.AskDelivery, delivery.AskCheck, delivery.AskRecheck}; len(order) != 3 || order[0] != want[0] || order[1] != want[1] || order[2] != want[2] { + if want := []string{sdkstep.AskDelivery, sdkstep.AskCheck, sdkstep.AskRecheck}; len(order) != 3 || order[0] != want[0] || order[1] != want[1] || order[2] != want[2] { t.Fatalf("order = %v, want %v", order, want) } - key, _ := delivery.AskStepKey("shanks", deliver.ID) + key, _ := sdkstep.AskStepKey("shanks", deliver.ID) s, ok := st.get(key) - if !ok || s.State != delivery.StepPassed || string(s.Result) != `{"ran":"`+deliver.ID+`"}` { + if !ok || s.State != sdkstep.StepPassed || string(s.Result) != `{"ran":"`+deliver.ID+`"}` { t.Fatalf("the step %s = %+v (%v)", key, s, ok) } } @@ -112,9 +112,9 @@ func TestPullTakesDeliveryBeforeCheck(t *testing.T) { // its ask id, and its end keeps the last phase. func TestPullHoldsAtMostItsCapacity(t *testing.T) { src, st := NewFakeAsks(), newSteps() - asks := []delivery.StepAsk{} + asks := []sdkstep.StepAsk{} for i := 0; i < 3; i++ { - a := testAsk(delivery.AskDelivery) + a := testAsk(sdkstep.AskDelivery) asks = append(asks, a) _ = src.PublishAsk(a) } @@ -124,7 +124,7 @@ func TestPullHoldsAtMostItsCapacity(t *testing.T) { var said []string capacities := map[string][]byte{} quota := 1200 - p := &Puller{Source: src, Language: delivery.AskGo, Node: "shanks", Put: st.put, Capacity: func() int { return 3 }, + p := &Puller{Source: src, Language: sdkstep.AskGo, Node: "shanks", Put: st.put, Capacity: func() int { return 3 }, CoresPerStep: func() float64 { return 6 }, Quota: func() (int, string) { mu.Lock(); defer mu.Unlock(); return quota, "a test's slice" }, PausePut: func(key string, v any) (uint64, error) { @@ -134,7 +134,7 @@ func TestPullHoldsAtMostItsCapacity(t *testing.T) { return 1, nil }, Logf: func(f string, a ...any) { mu.Lock(); said = append(said, fmt.Sprintf(f, a...)); mu.Unlock() }, - PullWait: 10 * time.Millisecond, Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { + PullWait: 10 * time.Millisecond, Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { mu.Lock() started++ mu.Unlock() @@ -147,8 +147,8 @@ func TestPullHoldsAtMostItsCapacity(t *testing.T) { go p.Pull(ctx) waitFor(t, "two in hand", func() bool { return p.InHand() == 2 }) time.Sleep(30 * time.Millisecond) // three pull waits: the third must still wait - if p.InHand() != 2 || src.Waiting(delivery.AskDelivery) != 1 { - t.Fatalf("in hand %d, waiting %d; want 2 and 1", p.InHand(), src.Waiting(delivery.AskDelivery)) + if p.InHand() != 2 || src.Waiting(sdkstep.AskDelivery) != 1 { + t.Fatalf("in hand %d, waiting %d; want 2 and 1", p.InHand(), src.Waiting(sdkstep.AskDelivery)) } c := p.CapacityDetail() if c.Effective != 2 || c.Configured != 3 || c.ByCPU != 2 || c.QuotaCores != 12 || !strings.Contains(c.Why, "bounded by the CPU") { @@ -163,23 +163,23 @@ func TestPullHoldsAtMostItsCapacity(t *testing.T) { } } mu.Unlock() - if got, err := delivery.DecodeCapacity(raw); err != nil || got.Effective != 2 || capLines != 1 { + if got, err := sdkstep.DecodeCapacity(raw); err != nil || got.Effective != 2 || capLines != 1 { t.Fatalf("capacity.shanks = %s (%v), said %d times; want effective 2, said once", raw, err, capLines) } waitFor(t, "a phase on the step key", func() bool { - key, _ := delivery.AskStepKey("shanks", p.Running()[0].ID) + key, _ := sdkstep.AskStepKey("shanks", p.Running()[0].ID) s, _ := st.get(key) - return s.State == delivery.StepRunning && s.Phase == "unit: tests of 3 packages" && !s.PhaseAt.IsZero() && s.Owner == sdkstep.Owner // 1890/AC5 + return s.State == sdkstep.StepRunning && s.Phase == "unit: tests of 3 packages" && !s.PhaseAt.IsZero() && s.Owner == buildrun.Owner // 1890/AC5 }) release <- struct{}{} - waitFor(t, "the third taken", func() bool { return src.Waiting(delivery.AskDelivery) == 0 }) + waitFor(t, "the third taken", func() bool { return src.Waiting(sdkstep.AskDelivery) == 0 }) // Taken from the source comes a moment before its run starts: wait for the start, not only the take. waitFor(t, "the third started", func() bool { mu.Lock(); defer mu.Unlock(); return started == 3 }) close(release) waitFor(t, "all acked", func() bool { a, _, _ := src.Fates(); return len(a) == 3 }) for _, a := range asks { - key, _ := delivery.AskStepKey("shanks", a.ID) - if s, _ := st.get(key); s.State != delivery.StepPassed || s.Phase != "unit: tests of 3 packages" || s.Owner != sdkstep.Owner { + key, _ := sdkstep.AskStepKey("shanks", a.ID) + if s, _ := st.get(key); s.State != sdkstep.StepPassed || s.Phase != "unit: tests of 3 packages" || s.Owner != buildrun.Owner { t.Errorf("the end of %s = %+v, want passed in its last phase", a.ID, s) } } @@ -200,18 +200,18 @@ func TestPullHoldsAtMostItsCapacity(t *testing.T) { // dropped for the asker to put again), and runs on a node that has it. func TestPullDropsWhatIsNoAsk(t *testing.T) { src, st := NewFakeAsks(), newSteps() - src.Publish(delivery.AskDelivery, []byte(`{"v":1}`)) - other := testAsk(delivery.AskDelivery) - other.Language = delivery.AskNode + src.Publish(sdkstep.AskDelivery, []byte(`{"v":1}`)) + other := testAsk(sdkstep.AskDelivery) + other.Language = sdkstep.AskNode _ = src.PublishAsk(other) - placed := testAsk(delivery.AskCheck) - placed.Needs = []string{delivery.NeedNodeBuildNode} + placed := testAsk(sdkstep.AskCheck) + placed.Needs = []string{sdkstep.NeedNodeBuildNode} if err := src.PublishAsk(placed); err != nil { t.Fatal(err) } ran := false - p := &Puller{Source: src, Language: delivery.AskGo, Node: "ace", Put: st.put, Capacity: func() int { return 1 }, - PullWait: 10 * time.Millisecond, Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { ran = true; return nil, nil }} + p := &Puller{Source: src, Language: sdkstep.AskGo, Node: "ace", Put: st.put, Capacity: func() int { return 1 }, + PullWait: 10 * time.Millisecond, Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { ran = true; return nil, nil }} ctx, cancel := context.WithCancel(context.Background()) defer cancel() go p.Pull(ctx) @@ -219,31 +219,31 @@ func TestPullDropsWhatIsNoAsk(t *testing.T) { if ran { t.Fatal("a wrong or a declined ask ran") } - key, _ := delivery.AskStepKey("ace", placed.ID) + key, _ := sdkstep.AskStepKey("ace", placed.ID) s, _ := st.get(key) - if d, ok := delivery.DeclinedOf(s); !ok || len(d.Lacks) != 1 || d.Lacks[0] != delivery.NeedNodeBuildNode || !strings.Contains(s.Reason, "lacks node-build-node") { + if d, ok := sdkstep.DeclinedOf(s); !ok || len(d.Lacks) != 1 || d.Lacks[0] != sdkstep.NeedNodeBuildNode || !strings.Contains(s.Reason, "lacks node-build-node") { t.Fatalf("the declined step = %+v", s) } has, hasSteps := NewFakeAsks(), newSteps() _ = has.PublishAsk(placed) - q := &Puller{Source: has, Language: delivery.AskGo, Node: "g14", Put: hasSteps.put, Capacity: func() int { return 1 }, - PullWait: 10 * time.Millisecond, Has: func(n string) bool { return n == delivery.NeedNodeBuildNode }, - Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { return nil, nil }} + q := &Puller{Source: has, Language: sdkstep.AskGo, Node: "g14", Put: hasSteps.put, Capacity: func() int { return 1 }, + PullWait: 10 * time.Millisecond, Has: func(n string) bool { return n == sdkstep.NeedNodeBuildNode }, + Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { return nil, nil }} go q.Pull(ctx) waitFor(t, "the placed ask acked where its need is met", func() bool { a, _, _ := has.Fates(); return len(a) == 1 }) // A run that finds its node is not on the agreed toolchain declines the ask after it began (ADR 0584 clause 2); a node on it builds. sit, sitSteps := NewFakeAsks(), newSteps() - toolchain := testAsk(delivery.AskDelivery) + toolchain := testAsk(sdkstep.AskDelivery) _ = sit.PublishAsk(toolchain) - s2 := &Puller{Source: sit, Language: delivery.AskGo, Node: "ace", Put: sitSteps.put, Capacity: func() int { return 1 }, PullWait: 10 * time.Millisecond, - Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { + s2 := &Puller{Source: sit, Language: sdkstep.AskGo, Node: "ace", Put: sitSteps.put, Capacity: func() int { return 1 }, PullWait: 10 * time.Millisecond, + Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { return nil, &Declining{Text: "the ask is for 26.13.0 and this node builds with 26.12.1", Lacks: []string{"the agreed toolchain 26.13.0 (recipe 3)"}} }} go s2.Pull(ctx) waitFor(t, "the ask termed on the node that sits out", func() bool { _, tm, _ := sit.Fates(); return len(tm) == 1 }) - sk, _ := delivery.AskStepKey("ace", toolchain.ID) + sk, _ := sdkstep.AskStepKey("ace", toolchain.ID) ss, _ := sitSteps.get(sk) - if d, ok := delivery.DeclinedOf(ss); !ok || len(d.Lacks) != 1 || !strings.Contains(ss.Reason, "26.12.1") { + if d, ok := sdkstep.DeclinedOf(ss); !ok || len(d.Lacks) != 1 || !strings.Contains(ss.Reason, "26.12.1") { t.Fatalf("the sitting-out step = %+v", ss) } } @@ -278,17 +278,17 @@ func (k *kv) load(key string) ([]byte, error) { func TestPullAtCapacityZeroTakesNothing(t *testing.T) { t.Run("settings file", func(t *testing.T) { src, st := NewFakeAsks(), &kv{} - _ = src.PublishAsk(testAsk(delivery.AskDelivery)) + _ = src.PublishAsk(testAsk(sdkstep.AskDelivery)) var mu sync.Mutex capacity := 0 - p := &Puller{Source: src, Language: delivery.AskGo, Node: "novox", Put: st.put, PullWait: 10 * time.Millisecond, + p := &Puller{Source: src, Language: sdkstep.AskGo, Node: "novox", Put: st.put, PullWait: 10 * time.Millisecond, Capacity: func() int { mu.Lock(); defer mu.Unlock(); return capacity }, - Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { return nil, nil }} + Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { return nil, nil }} ctx, cancel := context.WithCancel(context.Background()) defer cancel() go p.Pull(ctx) time.Sleep(50 * time.Millisecond) - if src.Waiting(delivery.AskDelivery) != 1 { + if src.Waiting(sdkstep.AskDelivery) != 1 { t.Fatal("a node at capacity 0 took an ask") } mu.Lock() @@ -299,18 +299,18 @@ func TestPullAtCapacityZeroTakesNothing(t *testing.T) { }) t.Run("config watch wakes", func(t *testing.T) { src, st := NewFakeAsks(), newSteps() - _ = src.PublishAsk(testAsk(delivery.AskDelivery)) + _ = src.PublishAsk(testAsk(sdkstep.AskDelivery)) w := &configWatch{value: "0"} - p := &Puller{Source: src, Language: delivery.AskGo, Node: "g14", Put: st.put, PullWait: 10 * time.Millisecond, + p := &Puller{Source: src, Language: sdkstep.AskGo, Node: "g14", Put: st.put, PullWait: 10 * time.Millisecond, Capacity: func() int { return 0 }, // the settings file, not refilled yet WatchConfig: w.watch, - Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { return nil, nil }} + Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { return nil, nil }} ctx, cancel := context.WithCancel(context.Background()) defer cancel() go p.Pull(ctx) waitFor(t, "the watch of the capacity", func() bool { w.mu.Lock(); defer w.mu.Unlock(); return w.handle != nil }) time.Sleep(30 * time.Millisecond) - if src.Waiting(delivery.AskDelivery) != 1 { + if src.Waiting(sdkstep.AskDelivery) != 1 { t.Fatal("a node at capacity 0 took an ask") } if w.asked != sdkstep.CapacitySetting { @@ -323,7 +323,7 @@ func TestPullAtCapacityZeroTakesNothing(t *testing.T) { // 2026-10-28: a replaced builder held the old "shanks=2,..." in its settings file, its config follow timed out, and // the puller parked at 0 with nothing to wake it when the node-engine refilled the file. src, st := NewFakeAsks(), newSteps() - _ = src.PublishAsk(testAsk(delivery.AskDelivery)) + _ = src.PublishAsk(testAsk(sdkstep.AskDelivery)) file := filepath.Join(t.TempDir(), "settings.json") if err := os.WriteFile(file, []byte(`{"capacity":"shanks=2,ace=2"}`), 0o600); err != nil { t.Fatal(err) @@ -347,14 +347,14 @@ func TestPullAtCapacityZeroTakesNothing(t *testing.T) { parked.Add(1) } } - p := &Puller{Source: src, Language: delivery.AskGo, Node: "shanks", Put: st.put, PullWait: 10 * time.Millisecond, + p := &Puller{Source: src, Language: sdkstep.AskGo, Node: "shanks", Put: st.put, PullWait: 10 * time.Millisecond, SettingsFile: file, WatchConfig: watch, Logf: logf, watching: func() { armed <- struct{}{} }, - Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { return nil, nil }} + Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { return nil, nil }} ctx, cancel := context.WithCancel(context.Background()) defer cancel() go p.Pull(ctx) waitFor(t, "the parked puller to say why", func() bool { why, fault := p.CapacityNote(); return fault && why != "" }) - if src.Waiting(delivery.AskDelivery) != 1 { + if src.Waiting(sdkstep.AskDelivery) != 1 { t.Fatal("a node whose capacity cannot be read took an ask") } <-armed // the file watch is in place @@ -377,7 +377,7 @@ func TestPullAtCapacityZeroTakesNothing(t *testing.T) { } <-armed // armed again waitFor(t, "the puller parked with no settings file", func() bool { return parks() > before }) - _ = src.PublishAsk(testAsk(delivery.AskDelivery)) + _ = src.PublishAsk(testAsk(sdkstep.AskDelivery)) if err := os.WriteFile(file, []byte(`{"capacity":2}`), 0o600); err != nil { t.Fatal(err) } @@ -397,9 +397,9 @@ func TestPullAtCapacityZeroTakesNothing(t *testing.T) { }, true}, } { t.Run(c.name, func(t *testing.T) { - p := &Puller{Source: NewFakeAsks(), Language: delivery.AskGo, Node: "g14", Put: newSteps().put, + p := &Puller{Source: NewFakeAsks(), Language: sdkstep.AskGo, Node: "g14", Put: newSteps().put, Capacity: func() int { return 1 }, WatchConfig: c.watch, - Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { return nil, nil }} + Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { return nil, nil }} p.watchCapacity() if p.room() != c.room { t.Fatalf("room = %v, want %v", p.room(), c.room) @@ -412,30 +412,30 @@ func TestPullAtCapacityZeroTakesNothing(t *testing.T) { // stays paused until resumed. func TestPullPauseOutlivesARestart(t *testing.T) { src, st, steps := NewFakeAsks(), &kv{}, &kv{} - run := func(ctx context.Context, a delivery.StepAsk) (any, error) { return nil, nil } - p := &Puller{Source: src, Language: delivery.AskGo, Node: "shanks", Put: steps.put, PausePut: st.put, Load: st.load, + run := func(ctx context.Context, a sdkstep.StepAsk) (any, error) { return nil, nil } + p := &Puller{Source: src, Language: sdkstep.AskGo, Node: "shanks", Put: steps.put, PausePut: st.put, Load: st.load, PullWait: 10 * time.Millisecond, Capacity: func() int { return 2 }, Run: run} if err := p.Pause("the operator"); err != nil { t.Fatal(err) } - key, _ := delivery.PauseKey("shanks") + key, _ := sdkstep.PauseKey("shanks") raw, _ := st.load(key) - if v, err := delivery.DecodePause(raw); err != nil || !v.Paused || v.By != "the operator" { + if v, err := sdkstep.DecodePause(raw); err != nil || !v.Paused || v.By != "the operator" { t.Fatalf("the pause key holds %s (%v)", raw, err) } if raw, _ := steps.load(key); raw != nil { t.Fatalf("the pause was written in the steps state, whose keys age out: %s", raw) } // The restart: a new puller on the same state. - again := &Puller{Source: src, Language: delivery.AskGo, Node: "shanks", Put: steps.put, PausePut: st.put, Load: st.load, + again := &Puller{Source: src, Language: sdkstep.AskGo, Node: "shanks", Put: steps.put, PausePut: st.put, Load: st.load, PullWait: 10 * time.Millisecond, Capacity: func() int { return 2 }, Run: run} - _ = src.PublishAsk(testAsk(delivery.AskDelivery)) + _ = src.PublishAsk(testAsk(sdkstep.AskDelivery)) ctx, cancel := context.WithCancel(context.Background()) defer cancel() go again.Pull(ctx) time.Sleep(50 * time.Millisecond) - if !again.Paused() || src.Waiting(delivery.AskDelivery) != 1 { - t.Fatalf("restarted: paused %v, waiting %d; want paused and 1", again.Paused(), src.Waiting(delivery.AskDelivery)) + if !again.Paused() || src.Waiting(sdkstep.AskDelivery) != 1 { + t.Fatalf("restarted: paused %v, waiting %d; want paused and 1", again.Paused(), src.Waiting(sdkstep.AskDelivery)) } if err := again.Resume("the operator"); err != nil { t.Fatal(err) @@ -445,7 +445,7 @@ func TestPullPauseOutlivesARestart(t *testing.T) { t.Run("a pause that cannot be read is said and pulled as not paused", func(t *testing.T) { src := NewFakeAsks() var said atomic.Value - p := &Puller{Source: src, Language: delivery.AskGo, Node: "shanks", Put: steps.put, PausePut: st.put, + p := &Puller{Source: src, Language: sdkstep.AskGo, Node: "shanks", Put: steps.put, PausePut: st.put, Load: func(string) ([]byte, error) { return nil, errors.New("no runtime yet") }, PullWait: 10 * time.Millisecond, Capacity: func() int { return 2 }, Run: run, Logf: func(f string, a ...any) { @@ -453,7 +453,7 @@ func TestPullPauseOutlivesARestart(t *testing.T) { said.Store(m) } }} - _ = src.PublishAsk(testAsk(delivery.AskDelivery)) + _ = src.PublishAsk(testAsk(sdkstep.AskDelivery)) ctx, cancel := context.WithCancel(context.Background()) defer cancel() go p.Pull(ctx) @@ -468,12 +468,12 @@ func TestPullPauseOutlivesARestart(t *testing.T) { // acknowledges its ask, so the stream gives it to another node. func TestPullHeartbeatAndStop(t *testing.T) { src, st := NewFakeAsks(), newSteps() - a := testAsk(delivery.AskDelivery) + a := testAsk(sdkstep.AskDelivery) _ = src.PublishAsk(a) running := make(chan struct{}) - p := &Puller{Source: src, Language: delivery.AskGo, Node: "shanks", Put: st.put, Capacity: func() int { return 1 }, + p := &Puller{Source: src, Language: sdkstep.AskGo, Node: "shanks", Put: st.put, Capacity: func() int { return 1 }, PullWait: 10 * time.Millisecond, Heartbeat: 5 * time.Millisecond, - Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { + Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { close(running) <-ctx.Done() return nil, ctx.Err() @@ -490,8 +490,8 @@ func TestPullHeartbeatAndStop(t *testing.T) { if len(acked)+len(termed)+len(naked) != 0 { t.Fatalf("a stopped holder gave its ask a fate: acked %v termed %v naked %v", acked, termed, naked) } - key, _ := delivery.AskStepKey("shanks", a.ID) - if s, ok := st.get(key); !ok || s.State != delivery.StepRunning { + key, _ := sdkstep.AskStepKey("shanks", a.ID) + if s, ok := st.get(key); !ok || s.State != sdkstep.StepRunning { t.Fatalf("the step %s = %+v, want left running", key, s) } } @@ -500,19 +500,19 @@ func TestPullHeartbeatAndStop(t *testing.T) { // asker's key fails, and it is ended on the stream, not offered to another node. func TestAPoisonedAskIsSaidAndRunNoMore(t *testing.T) { src, st := NewFakeAsks(), newSteps() - src.Delivered = delivery.AskRuns + 1 - a := testAsk(delivery.AskDelivery) + src.Delivered = sdkstep.AskRuns + 1 + a := testAsk(sdkstep.AskDelivery) _ = src.PublishAsk(a) ran := false - p := &Puller{Source: src, Language: delivery.AskGo, Node: "shanks", Put: st.put, Capacity: func() int { return 1 }, - PullWait: 10 * time.Millisecond, Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { ran = true; return nil, nil }} + p := &Puller{Source: src, Language: sdkstep.AskGo, Node: "shanks", Put: st.put, Capacity: func() int { return 1 }, + PullWait: 10 * time.Millisecond, Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { ran = true; return nil, nil }} ctx, cancel := context.WithCancel(context.Background()) defer cancel() go p.Pull(ctx) waitFor(t, "the ask termed", func() bool { _, tm, _ := src.Fates(); return len(tm) == 1 }) - key, _ := delivery.AskStepKey("shanks", a.ID) + key, _ := sdkstep.AskStepKey("shanks", a.ID) s, ok := st.get(key) - if ran || !ok || s.State != delivery.StepFailed || !strings.Contains(s.Reason, "taken 3 times") || !strings.Contains(s.Reason, "poison") { + if ran || !ok || s.State != sdkstep.StepFailed || !strings.Contains(s.Reason, "taken 3 times") || !strings.Contains(s.Reason, "poison") { t.Fatalf("ran %v, step %+v", ran, s) } if acked, _, naked := src.Fates(); len(acked)+len(naked) != 0 { diff --git a/modules/mesh-build-go/buildstep/refusal.go b/modules/mesh-build-go/buildstep/refusal.go index 9e4fa738e..909b2e6ea 100644 --- a/modules/mesh-build-go/buildstep/refusal.go +++ b/modules/mesh-build-go/buildstep/refusal.go @@ -17,7 +17,7 @@ func (r *Refusal) Error() string { return r.Text } // Refuse is a Refusal with its text formatted. func Refuse(format string, args ...any) *Refusal { return &Refusal{Text: fmt.Sprintf(format, args...)} } -// Declining is a step a node does not run because another node should: it ends refused as declined (delivery.StepDeclined), +// Declining is a step a node does not run because another node should: it ends refused as declined (sdkstep.StepDeclined), // the ask's message is dropped, and the asker puts the ask again under a new id (issue 890). A build ask naming a // toolchain other than this node's is one (novox/hq ADR 0584 clause 2): a node that is not in the toolchain majority // sits out and never fails a build. diff --git a/modules/mesh-build-go/buildstep/seat_tools_test.go b/modules/mesh-build-go/buildstep/seat_tools_test.go index 471ec3d4f..ab87f8ad6 100644 --- a/modules/mesh-build-go/buildstep/seat_tools_test.go +++ b/modules/mesh-build-go/buildstep/seat_tools_test.go @@ -2,10 +2,9 @@ package buildstep import ( "context" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "testing" "time" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // 1887/A9a, ADR 0525 §10: a build seat's verbs are .current, .pause and .resume; current names the ask running, @@ -13,8 +12,8 @@ import ( func TestSeatToolsCurrentPauseResume(t *testing.T) { src, st := NewFakeAsks(), newSteps() release := make(chan struct{}) - p := &Puller{Source: src, Language: delivery.AskGo, Node: "shanks", Put: st.put, Capacity: func() int { return 1 }, - PullWait: 10 * time.Millisecond, Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { <-release; return nil, nil }} + p := &Puller{Source: src, Language: sdkstep.AskGo, Node: "shanks", Put: st.put, Capacity: func() int { return 1 }, + PullWait: 10 * time.Millisecond, Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { <-release; return nil, nil }} tools := map[string]func(map[string]any) (any, error){} for _, tool := range SeatTools("node-build-go", "Go", p) { tools[tool.Name] = tool.Run @@ -24,7 +23,7 @@ func TestSeatToolsCurrentPauseResume(t *testing.T) { t.Fatalf("no %s", name) } } - a := testAsk(delivery.AskDelivery) + a := testAsk(sdkstep.AskDelivery) _ = src.PublishAsk(a) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -40,13 +39,13 @@ func TestSeatToolsCurrentPauseResume(t *testing.T) { t.Fatalf("pause = %v, %v", out, err) } close(release) - _ = src.PublishAsk(testAsk(delivery.AskDelivery)) + _ = src.PublishAsk(testAsk(sdkstep.AskDelivery)) time.Sleep(50 * time.Millisecond) - if src.Waiting(delivery.AskDelivery) != 1 { + if src.Waiting(sdkstep.AskDelivery) != 1 { t.Fatal("a paused node took an ask") } if _, err := tools["node-build-go.resume"](nil); err != nil { t.Fatal(err) } - waitFor(t, "the ask taken after the resume", func() bool { return src.Waiting(delivery.AskDelivery) == 0 }) + waitFor(t, "the ask taken after the resume", func() bool { return src.Waiting(sdkstep.AskDelivery) == 0 }) } diff --git a/modules/mesh-build-go/buildstep/step.go b/modules/mesh-build-go/buildstep/step.go index 39f85bebf..7062030d5 100644 --- a/modules/mesh-build-go/buildstep/step.go +++ b/modules/mesh-build-go/buildstep/step.go @@ -9,14 +9,14 @@ import ( "encoding/json" "errors" "fmt" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" "log" "time" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" ) -// Put writes one key of a state: stdio.State(delivery.StepsState).Put's shape (go/state.go). +// Put writes one key of a state: the steps state.Put's shape (go/state.go). type Put func(key string, value any) (uint64, error) // EndAttempts and EndRetry bound how a step's end is written: a write that fails is tried again, since the end @@ -43,20 +43,20 @@ func Start(ctx context.Context, put Put, node, tool string, run func(ctx context } // begin writes the step running under id, owned by this process (Owner). -func begin(put Put, node, tool, id, what string) (delivery.Step, string, error) { - step := delivery.Step{ID: id, Tool: tool, Node: node, State: delivery.StepRunning, Started: now().UTC(), What: what, Owner: sdkstep.Owner} - key, err := delivery.StepKey(node, step.ID) +func begin(put Put, node, tool, id, what string) (sdkstep.Step, string, error) { + step := sdkstep.Step{ID: id, Tool: tool, Node: node, State: sdkstep.StepRunning, Started: now().UTC(), What: what, Owner: buildrun.Owner} + key, err := sdkstep.StepKey(node, step.ID) if err != nil { - return delivery.Step{}, "", err + return sdkstep.Step{}, "", err } if err := write(put, key, step); err != nil { - return delivery.Step{}, "", fmt.Errorf("buildstep: writing the running step %s: %w", key, err) + return sdkstep.Step{}, "", fmt.Errorf("buildstep: writing the running step %s: %w", key, err) } return step, key, nil } // end runs run and writes the step's end. -func end(ctx context.Context, put Put, key string, step delivery.Step, run func(ctx context.Context) (any, error)) { +func end(ctx context.Context, put Put, key string, step sdkstep.Step, run func(ctx context.Context) (any, error)) { result, err := protect(ctx, run) _ = finish(put, key, step, result, err, log.Printf) // finish says a refused end itself } @@ -66,23 +66,23 @@ func end(ctx context.Context, put Put, key string, step delivery.Step, run func( // refusal is logged and a small failed end without the result is written instead, naming the write's error, so the // step's reader learns it is over and why. finish answers an error only when no end could be written at all, and then // the step's ask is not acknowledged as done. -func finish(put Put, key string, step delivery.Step, result any, err error, logf func(format string, args ...any)) error { +func finish(put Put, key string, step sdkstep.Step, result any, err error, logf func(format string, args ...any)) error { step.Ended = now().UTC() switch ref := (*Refusal)(nil); { case err == nil: - step.State = delivery.StepPassed + step.State = sdkstep.StepPassed if result != nil { raw, merr := json.Marshal(result) if merr != nil { - step.State, step.Reason = delivery.StepFailed, "the result is not JSON: "+merr.Error() + step.State, step.Reason = sdkstep.StepFailed, "the result is not JSON: "+merr.Error() } else { step.Result = raw } } case errors.As(err, &ref): - step.State, step.Reason = delivery.StepRefused, err.Error() + step.State, step.Reason = sdkstep.StepRefused, err.Error() default: - step.State, step.Reason = delivery.StepFailed, err.Error() + step.State, step.Reason = sdkstep.StepFailed, err.Error() // A failed step may answer what it found on the way (a build's out-of-step files): kept on its end. if result != nil { if raw, merr := json.Marshal(result); merr == nil { @@ -102,7 +102,7 @@ func finish(put Put, key string, step delivery.Step, result any, err error, logf if step.Reason != "" { why = fmt.Sprintf("the step ended %s (%s), and its end could not be written: %v", ended, step.Reason, werr) } - step.State, step.Reason, step.Result = delivery.StepFailed, why, nil + step.State, step.Reason, step.Result = sdkstep.StepFailed, why, nil if ferr := writeEnd(put, key, step); ferr != nil { if logf != nil { logf("the failed end of the step %s could not be written either: %v", key, ferr) @@ -113,7 +113,7 @@ func finish(put Put, key string, step delivery.Step, result any, err error, logf } // writeEnd writes the step's end, trying EndAttempts times. -func writeEnd(put Put, key string, step delivery.Step) error { +func writeEnd(put Put, key string, step sdkstep.Step) error { for attempt := 1; ; attempt++ { werr := write(put, key, step) if werr == nil || attempt >= EndAttempts { @@ -133,8 +133,8 @@ func protect(ctx context.Context, run func(ctx context.Context) (any, error)) (r return run(ctx) } -func write(put Put, key string, step delivery.Step) error { - raw, err := delivery.EncodeStep(step) +func write(put Put, key string, step sdkstep.Step) error { + raw, err := sdkstep.EncodeStep(step) if err != nil { return err } diff --git a/modules/mesh-build-go/buildstep/step_test.go b/modules/mesh-build-go/buildstep/step_test.go index 3e011788e..fe7b0f8f2 100644 --- a/modules/mesh-build-go/buildstep/step_test.go +++ b/modules/mesh-build-go/buildstep/step_test.go @@ -4,25 +4,24 @@ import ( "context" "encoding/json" "errors" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "sync" "testing" "time" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // keys is a steps state in memory: every value put, in order, per key, and a signal for each end. type keys struct { mu sync.Mutex - puts map[string][]delivery.Step + puts map[string][]sdkstep.Step ended chan string } -func newKeys() *keys { return &keys{puts: map[string][]delivery.Step{}, ended: make(chan string, 16)} } +func newKeys() *keys { return &keys{puts: map[string][]sdkstep.Step{}, ended: make(chan string, 16)} } func (k *keys) put(key string, value any) (uint64, error) { - step, err := delivery.DecodeStep(value.(json.RawMessage)) + step, err := sdkstep.DecodeStep(value.(json.RawMessage)) if err != nil { return 0, err } @@ -30,13 +29,13 @@ func (k *keys) put(key string, value any) (uint64, error) { k.puts[key] = append(k.puts[key], step) n := uint64(len(k.puts[key])) k.mu.Unlock() - if step.State != delivery.StepRunning { + if step.State != sdkstep.StepRunning { k.ended <- key } return n, nil } -func (k *keys) last(key string) delivery.Step { +func (k *keys) last(key string) sdkstep.Step { k.mu.Lock() defer k.mu.Unlock() s := k.puts[key] @@ -72,8 +71,8 @@ func TestStartAnswersAtOnceWithTheStepRunning(t *testing.T) { } s := k.last("ace." + id) // 1890/AC5: the running key names this process as its owner. - if s.State != delivery.StepRunning || s.Tool != "fetch" || s.Node != "ace" || s.ID != id || s.Started.IsZero() || s.Owner != sdkstep.Owner || sdkstep.Owner == "" { - t.Errorf("step = %+v, want owner %q", s, sdkstep.Owner) + if s.State != sdkstep.StepRunning || s.Tool != "fetch" || s.Node != "ace" || s.ID != id || s.Started.IsZero() || s.Owner != buildrun.Owner || buildrun.Owner == "" { + t.Errorf("step = %+v, want owner %q", s, buildrun.Owner) } } @@ -86,11 +85,11 @@ func TestStepEndsPassedFailedOrRefusedOnItsKey(t *testing.T) { reason string result string }{ - {"result", func(context.Context) (any, error) { return map[string]string{"sha": "abc"}, nil }, delivery.StepPassed, "", `{"sha":"abc"}`}, - {"error", func(context.Context) (any, error) { return nil, errors.New("exit 2") }, delivery.StepFailed, "exit 2", ""}, + {"result", func(context.Context) (any, error) { return map[string]string{"sha": "abc"}, nil }, sdkstep.StepPassed, "", `{"sha":"abc"}`}, + {"error", func(context.Context) (any, error) { return nil, errors.New("exit 2") }, sdkstep.StepFailed, "exit 2", ""}, {"refusal", func(context.Context) (any, error) { return nil, &Refusal{Text: "go 1.27.1 installed, the recipe builds with go 1.27.0", Want: "1.27.0", Have: "1.27.1"} - }, delivery.StepRefused, "go 1.27.1 installed, the recipe builds with go 1.27.0", ""}, + }, sdkstep.StepRefused, "go 1.27.1 installed, the recipe builds with go 1.27.0", ""}, } { t.Run(c.name, func(t *testing.T) { k := newKeys() @@ -102,7 +101,7 @@ func TestStepEndsPassedFailedOrRefusedOnItsKey(t *testing.T) { t.Fatalf("ended key %q", got) } s := k.last("ace." + id) - if s.State != c.state || s.Reason != c.reason || string(s.Result) != c.result || s.Ended.IsZero() || s.Owner != sdkstep.Owner { + if s.State != c.state || s.Reason != c.reason || string(s.Result) != c.result || s.Ended.IsZero() || s.Owner != buildrun.Owner { t.Errorf("step = %+v", s) } }) @@ -115,7 +114,7 @@ func TestAPanicEndsTheStepFailed(t *testing.T) { id, _ := Start(context.Background(), k.put, "ace", "build", func(context.Context) (any, error) { panic("boom") }) k.waitEnd(t) s := k.last("ace." + id) - if s.State != delivery.StepFailed || s.Reason != "the step panicked: boom" { + if s.State != sdkstep.StepFailed || s.Reason != "the step panicked: boom" { t.Errorf("step = %+v", s) } } @@ -134,7 +133,7 @@ func TestTwoIDsInOneMillisecondDiffer(t *testing.T) { t.Fatalf("id %q handed out twice", id) } seen[id] = true - if _, err := delivery.StepKey("ace", id); err != nil { + if _, err := sdkstep.StepKey("ace", id); err != nil { t.Errorf("id %q: %v", id, err) } } diff --git a/modules/mesh-build-go/buildstep/steptool.go b/modules/mesh-build-go/buildstep/steptool.go index 078fe1ed2..92e8eef02 100644 --- a/modules/mesh-build-go/buildstep/steptool.go +++ b/modules/mesh-build-go/buildstep/steptool.go @@ -1,14 +1,14 @@ package buildstep import ( - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" stdio "git.novox.be/novox/mesh-sdk/go" ) // StepEndTool is the module's step-end tool, named name (build_go_step_end): it ends one step left running, with a // reason, refusing one this process started. p may be nil. -func StepEndTool(name string, node string, scan sdkstep.Scan, p *Puller) stdio.Tool { +func StepEndTool(name string, node string, scan buildrun.Scan, p *Puller) stdio.Tool { return stdio.Tool{Name: name, Description: "End one step of this machine that is stuck in state running (for instance left by a restart of the module) " + "as failed, with the reason given; its asker then sees it over, so ending an ask still in its stream fails its asker. " + @@ -31,6 +31,6 @@ func StepEndTool(name string, node string, scan sdkstep.Scan, p *Puller) stdio.T return false } } - return sdkstep.EndOne(scan, node, id, why, live) + return buildrun.EndOne(scan, node, id, why, live) }} } diff --git a/modules/mesh-build-go/buildstep/toolchain.go b/modules/mesh-build-go/buildstep/toolchain.go new file mode 100644 index 000000000..2abe0860b --- /dev/null +++ b/modules/mesh-build-go/buildstep/toolchain.go @@ -0,0 +1,82 @@ +package buildstep + +import ( + "bytes" + "encoding/json" + "fmt" + "strings" + "time" +) + +// ToolchainVersion is the layout version of a toolchains value. +const ToolchainVersion = 1 + +// Toolchain is the value of a build module's state toolchains under the key .: the version of the +// language's toolchain installed on the node, the build module's recipe version, and when the module saw them. It is +// the layout every node-build seat gives that state (the seats' generated Toolchain); the three build modules share +// this form because their runner does (design 26 *Where a seat's code goes*, a module's own package). A test holds it +// to each seat's decoder. +type Toolchain struct { + V int `json:"v,omitempty"` + Language string `json:"language"` + Version string `json:"version"` + Recipe string `json:"recipe"` + At time.Time `json:"at,omitzero"` +} + +func checkToolchainLanguage(language string) error { + switch language { + case "go", "typescript": + return nil + } + return fmt.Errorf("buildstep: the toolchain language %q is not go or typescript", language) +} + +// ToolchainKey is the key of a node's toolchain of one language: .. It refuses an empty node, a node +// with a dot and a language other than go or typescript. +func ToolchainKey(node, language string) (string, error) { + if node == "" || strings.ContainsAny(node, ". ") { + return "", fmt.Errorf("buildstep: %q is not a node name", node) + } + if err := checkToolchainLanguage(language); err != nil { + return "", err + } + return node + "." + language, nil +} + +func (t Toolchain) check() error { + if err := checkToolchainLanguage(t.Language); err != nil { + return err + } + if t.Version == "" || t.Recipe == "" { + return fmt.Errorf("buildstep: a %s toolchain needs its version and its recipe", t.Language) + } + return nil +} + +// EncodeToolchain is t as JSON; it refuses a language other than go or typescript and an empty version or recipe. +func EncodeToolchain(t Toolchain) ([]byte, error) { + if err := t.check(); err != nil { + return nil, err + } + t.V = ToolchainVersion + return json.Marshal(t) +} + +// DecodeToolchain reads a toolchains value, refusing an unknown field, another layout version and what +// EncodeToolchain refuses. +func DecodeToolchain(data []byte) (Toolchain, error) { + var t Toolchain + dec := json.NewDecoder(bytes.NewReader(data)) + dec.DisallowUnknownFields() + if err := dec.Decode(&t); err != nil { + return Toolchain{}, fmt.Errorf("buildstep: a toolchain does not read: %w", err) + } + if t.V != ToolchainVersion { + return Toolchain{}, fmt.Errorf("buildstep: a toolchain of version %d, this reads %d", t.V, ToolchainVersion) + } + if err := t.check(); err != nil { + return Toolchain{}, err + } + return t, nil +} diff --git a/modules/mesh-build-go/buildstep/toolchain_test.go b/modules/mesh-build-go/buildstep/toolchain_test.go new file mode 100644 index 000000000..3361f6068 --- /dev/null +++ b/modules/mesh-build-go/buildstep/toolchain_test.go @@ -0,0 +1,48 @@ +package buildstep + +import ( + "strings" + "testing" + "time" + + nodebuildgo "git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildgo" + nodebuildimage "git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildimage" + nodebuildnode "git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildnode" +) + +// The toolchains value and key are the layout all three node-build seats generate: each seat's strict decoder reads +// what the shared runner writes, and each seat's key function agrees with ToolchainKey. +func TestTheToolchainsValueAndKeyAreTheSeatsLayout(t *testing.T) { + raw, err := EncodeToolchain(Toolchain{Language: "go", Version: "go1.27.1", Recipe: "3", At: time.Date(2026, 11, 5, 10, 0, 0, 0, time.UTC)}) + if err != nil { + t.Fatal(err) + } + if _, err := nodebuildgo.DecodeToolchainsByNodeLanguageValue(raw); err != nil { + t.Errorf("node-build-go does not read the value: %v", err) + } + if _, err := nodebuildimage.DecodeToolchainsByNodeLanguageValue(raw); err != nil { + t.Errorf("node-build-image does not read the value: %v", err) + } + if _, err := nodebuildnode.DecodeToolchainsByNodeLanguageValue(raw); err != nil { + t.Errorf("node-build-node does not read the value: %v", err) + } + back, err := DecodeToolchain(raw) + if err != nil || back.Version != "go1.27.1" || back.At.IsZero() { + t.Errorf("the value reads back as %+v, %v", back, err) + } + key, err := ToolchainKey("ace", "typescript") + if err != nil || key != nodebuildnode.ToolchainsByNodeLanguageKey("ace", "typescript") || key != nodebuildgo.ToolchainsByNodeLanguageKey("ace", "typescript") { + t.Errorf("key %q, %v", key, err) + } + for _, bad := range [][2]string{{"", "go"}, {"a.b", "go"}, {"ace", "rust"}} { + if _, err := ToolchainKey(bad[0], bad[1]); err == nil { + t.Errorf("the key of %v was made", bad) + } + } + if _, err := EncodeToolchain(Toolchain{Language: "go", Version: "go1.27"}); err == nil { + t.Error("a toolchain without its recipe was written") + } + if _, err := DecodeToolchain([]byte(`{"v":1,"language":"go","version":"x","recipe":"1","extra":1}`)); err == nil || !strings.Contains(err.Error(), "extra") { + t.Errorf("a field the layout lacks was read: %v", err) + } +} diff --git a/modules/mesh-build-go/cmd/mesh-build-go/archive_test.go b/modules/mesh-build-go/cmd/mesh-build-go/archive_test.go index 0b0930fc7..ab1296673 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/archive_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/archive_test.go @@ -6,6 +6,7 @@ import ( "context" "crypto/sha256" "encoding/hex" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "io" "net" "net/http" @@ -15,8 +16,6 @@ import ( "runtime" "strings" "testing" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // Issue 1589: the build step packs an archive artifact (novox/hq ADR 0478 §1), as the build agent packs it @@ -146,7 +145,7 @@ func pinnedModule(t *testing.T, path, sha, extra string) (*Module, *keptStates) func TestAnArchiveOfADirectoryHasTheBuildAgentsDigest(t *testing.T) { m, states, calls := archiveModule(t, "") res, st := runBuild(t, m, states, "files") - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } sameAsBuildAgent(t, res, buildAgentDirectoryStream, buildAgentDirectoryDigest) @@ -177,7 +176,7 @@ func TestAnArchiveFromOutsideTheModuleOrMissingFailsTheStep(t *testing.T) { "nothing": "nothing", } { m, states, _ := archiveModule(t, `{"module":"demo","version":"1","build":{"artifacts":[{"name":"files","kind":"archive","from":"`+from+`"}]}}`) - if _, st := runBuild(t, m, states, "files"); st.State != delivery.StepFailed || !strings.Contains(st.Reason, want) { + if _, st := runBuild(t, m, states, "files"); st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, want) { t.Errorf("from %q: %s %q", from, st.State, st.Reason) } } @@ -193,7 +192,7 @@ func pinned(url, sha, extra string) string { func TestAPinnedArchiveIsUnpackedWithinAndHasTheBuildAgentsDigest(t *testing.T) { m, states := pinnedModule(t, "/release.tar.gz", releaseSHA256, `,"within":"release/app"`) res, st := runBuild(t, m, states, "files") - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("%s %q", st.State, st.Reason) } sameAsBuildAgent(t, res, buildAgentWithinStream, buildAgentWithinDigest) @@ -202,7 +201,7 @@ func TestAPinnedArchiveIsUnpackedWithinAndHasTheBuildAgentsDigest(t *testing.T) func TestAPinnedFileKeptWholeHasTheBuildAgentsDigest(t *testing.T) { m, states := pinnedModule(t, "/release.tar.gz", releaseSHA256, `,"file":"tool.bin"`) res, st := runBuild(t, m, states, "files") - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("%s %q", st.State, st.Reason) } sameAsBuildAgent(t, res, buildAgentFileStream, buildAgentFileDigest) @@ -213,7 +212,7 @@ func TestAPinnedFileOfAnotherDigestIsRefused(t *testing.T) { wrong := strings.Repeat("ab", 32) m, states := pinnedModule(t, "/release.tar.gz", wrong, `,"within":"release/app"`) _, st := runBuild(t, m, states, "files") - if st.State != delivery.StepFailed || !strings.Contains(st.Reason, "sha256:"+wrong) || !strings.Contains(st.Reason, "sha256:"+releaseSHA256) { + if st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, "sha256:"+wrong) || !strings.Contains(st.Reason, "sha256:"+releaseSHA256) { t.Errorf("the step ended %s: %q", st.State, st.Reason) } if entries, _ := os.ReadDir(filepath.Join(m.Work, "ws1", "artifacts")); len(entries) != 0 { @@ -223,7 +222,7 @@ func TestAPinnedFileOfAnotherDigestIsRefused(t *testing.T) { func TestAPinnedFileTheServerRefusesFailsTheStep(t *testing.T) { m, states := pinnedModule(t, "/gone", releaseSHA256, `,"file":"x"`) - if _, st := runBuild(t, m, states, "files"); st.State != delivery.StepFailed || !strings.Contains(st.Reason, "404") { + if _, st := runBuild(t, m, states, "files"); st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, "404") { t.Errorf("the step ended %s: %q", st.State, st.Reason) } } @@ -231,7 +230,7 @@ func TestAPinnedFileTheServerRefusesFailsTheStep(t *testing.T) { // Entries outside `within` are refused, as the build agent refuses them. func TestAPinnedArchiveWithEntriesOutsideWithinIsRefused(t *testing.T) { m, states := pinnedModule(t, "/release.tar.gz", releaseSHA256, `,"within":"release/other"`) - if _, st := runBuild(t, m, states, "files"); st.State != delivery.StepFailed || !strings.Contains(st.Reason, "release/other") { + if _, st := runBuild(t, m, states, "files"); st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, "release/other") { t.Errorf("the step ended %s: %q", st.State, st.Reason) } } @@ -239,7 +238,7 @@ func TestAPinnedArchiveWithEntriesOutsideWithinIsRefused(t *testing.T) { // Other kinds are still refused by name. func TestAnImageArtifactIsStillRefusedByName(t *testing.T) { m, states, _ := archiveModule(t, `{"module":"demo","version":"1","build":{"artifacts":[{"name":"files","kind":"image","from":"files"}]}}`) - if _, st := runBuild(t, m, states, "files"); st.State != delivery.StepFailed || !strings.Contains(st.Reason, "image") { + if _, st := runBuild(t, m, states, "files"); st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, "image") { t.Errorf("the step ended %s: %q", st.State, st.Reason) } } @@ -259,7 +258,7 @@ func TestAnArchiveBehindASymlinkedParentIsRefused(t *testing.T) { t.Fatal(err) } _, st := runBuild(t, m, states, "files") - if st.State != delivery.StepFailed || !strings.Contains(st.Reason, "outside") || !strings.Contains(st.Reason, outside) { + if st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, "outside") || !strings.Contains(st.Reason, outside) { t.Errorf("the step ended %s: %q", st.State, st.Reason) } if entries, _ := os.ReadDir(filepath.Join(m.Work, "ws1", "artifacts")); len(entries) != 0 { @@ -288,7 +287,7 @@ func TestAnArchiveOfALinkedModuleDirectoryIsRefused(t *testing.T) { } } st := states.waitEnd(t) - if st.State != delivery.StepFailed || !strings.Contains(st.Reason, "outside") || !strings.Contains(st.Reason, outside) { + if st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, "outside") || !strings.Contains(st.Reason, outside) { t.Errorf("the step ended %s: %q", st.State, st.Reason) } if entries, _ := os.ReadDir(filepath.Join(m.Work, "ws1", "artifacts")); len(entries) != 0 { diff --git a/modules/mesh-build-go/cmd/mesh-build-go/asks.go b/modules/mesh-build-go/cmd/mesh-build-go/asks.go index f71a1ba1f..175eb687c 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/asks.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/asks.go @@ -4,13 +4,15 @@ import ( "context" "encoding/json" "fmt" + checkerseat "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdeliverychecker" + seat "git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildgo" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" "path/filepath" "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // **The module pulls its seat's asks** (novox/hq ADR 0525 §2-§6, ADR 0536 §4; issue 1887 A3go). It holds the seat @@ -24,7 +26,10 @@ const Seat = "node-build-go" // KeptState is the checker's kept verdicts, which a check ask takes for the packages whose digest has one (issue // 1887's design limit 1). -const KeptState = delivery.CheckerModule + ".kept" +const KeptState = checkerModule + "." + checkerseat.StateKept + +// checkerModule is the module that holds the seat mesh-delivery-checker, whose kept state a check ask reads. +const checkerModule = "mesh-delivery-checker" // askSteps are the module's step bodies for an ask, each holding its workspace while it runs, as a tool's does. func (m *Module) askSteps(steps []StepTool) buildstep.AskSteps { @@ -40,12 +45,12 @@ func (m *Module) askSteps(steps []StepTool) buildstep.AskSteps { Fetch: byName["build_go_fetch"], Build: byName["build_go_build"], Digest: byName["build_go_digest"], Test: byName["build_go_test"], Imports: byName[ImportsTool], Compare: buildstep.CompareStep(buildstep.GeneratedRootGo, func(ws string) string { return filepath.Join(m.Work, ws, "tree") }), - Toolchain: func(ctx context.Context) (delivery.ToolchainUsed, error) { + Toolchain: func(ctx context.Context) (sdkstep.ToolchainUsed, error) { installed, err := m.Probe(ctx) if err != nil { - return delivery.ToolchainUsed{}, err + return sdkstep.ToolchainUsed{}, err } - return delivery.ToolchainUsed{Version: installed, Recipe: m.Recipe.Version()}, nil + return sdkstep.ToolchainUsed{Version: installed, Recipe: m.Recipe.Version()}, nil }, Kept: m.KeptLookup, Has: m.Has, @@ -65,25 +70,22 @@ func (m *Module) keptValue(key string) (json.RawMessage, error) { // KeptLookup is whether the checker kept a verdict for the level and digest, and how many tests it counted. func (m *Module) KeptLookup(ctx context.Context, level, digest string) (int, bool, error) { - key, err := delivery.KeptKey(level, digest) - if err != nil { - return 0, false, err - } + key := checkerseat.KeptByLevelDigestKey(level, digest) raw, err := m.keptValue(key) if err != nil || raw == nil { return 0, false, err } - v, err := delivery.DecodeKept(raw) + v, err := checkerseat.DecodeKeptByLevelDigestValue(raw) if err != nil { return 0, false, fmt.Errorf("%s holds what is not a kept verdict: %w", key, err) } - return v.Tests, true, nil + return int(v.Tests), true, nil } // Puller is the module's pull of its seat's asks, on source (the runtime's seat pull when nil). func (m *Module) Puller(steps []StepTool, source buildstep.AskSource) *buildstep.Puller { if source == nil { - source = buildstep.SeatAsks{Language: delivery.AskGo} + source = buildstep.SeatAsks{Language: sdkstep.AskGo} } capacity := m.Capacity // The capacity's own change wakes the puller (issue 1887): the runtime's watch of the config value as mesh-config @@ -101,7 +103,7 @@ func (m *Module) Puller(steps []StepTool, source buildstep.AskSource) *buildstep capacity = buildstep.NodeCapacity(m.Settings, m.Node, m.Say) settings = m.Settings watch = buildstep.WatchConfigServed - cores = buildstep.NodeCoresPerStep(m.Settings, buildstep.DefaultCoresPerStep[delivery.AskGo], m.Say) + cores = buildstep.NodeCoresPerStep(m.Settings, buildstep.DefaultCoresPerStep[sdkstep.AskGo], m.Say) } ask := m.askSteps(steps) var load func(string) ([]byte, error) @@ -111,9 +113,9 @@ func (m *Module) Puller(steps []StepTool, source buildstep.AskSource) *buildstep return raw, err } } - return &buildstep.Puller{Source: source, Language: delivery.AskGo, Node: m.Node, Put: m.Steps, PausePut: m.Pauses, Load: load, + return &buildstep.Puller{Source: source, Language: sdkstep.AskGo, Node: m.Node, Put: m.Steps, PausePut: m.Pauses, Load: load, Capacity: capacity, SettingsFile: settings, WatchConfig: watch, CoresPerStep: cores, BuildHours: hours, Logf: m.Say, Has: m.Has, - Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { + Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { if err := m.Check(ctx); err != nil { return nil, err } @@ -136,13 +138,13 @@ func (m *Module) SeatTools(p *buildstep.Puller) []stdio.Tool { const StepEndTool = "build_go_step_end" // endLeftRunning is the module's start sweep (issue 1890): it ends the steps of its node that a previous process left -// running (sdkstep.EndStaleAtStart; every step names its owner). main runs it once at the start, and the module's test +// running (buildrun.EndStaleAtStart; every step names its owner). main runs it once at the start, and the module's test // runs it through the conformance kit's left-running case. -func (m *Module) endLeftRunning(ctx context.Context, scan sdkstep.Scan, booted time.Time, logf func(string, ...any)) { - sdkstep.EndStaleAtStart(ctx, scan, m.Node, booted, logf) +func (m *Module) endLeftRunning(ctx context.Context, scan buildrun.Scan, booted time.Time, logf func(string, ...any)) { + buildrun.EndStaleAtStart(ctx, scan, m.Node, booted, logf) } // stepScan is the module's steps state as buildstep reads it. -func (m *Module) stepScan() sdkstep.Scan { - return sdkstep.ScanOf(stdio.State(delivery.StepsState)) +func (m *Module) stepScan() buildrun.Scan { + return buildrun.ScanOf(stdio.State(seat.StateSteps)) } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/asks_integration_test.go b/modules/mesh-build-go/cmd/mesh-build-go/asks_integration_test.go index e3541c016..724d5f464 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/asks_integration_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/asks_integration_test.go @@ -4,6 +4,7 @@ package main import ( "context" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "sync" "testing" "time" @@ -12,7 +13,6 @@ import ( "github.com/nats-io/nats.go/jetstream" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/testbus" ) @@ -42,17 +42,17 @@ func TestTheModuleTakesADeliveryAskBeforeAnEarlierCheck(t *testing.T) { } ctx, stop := context.WithCancel(context.Background()) defer stop() - if err := buildstep.DeclareAskWorkers(ctx, js, delivery.AskGo, 30*time.Second); err != nil { + if err := buildstep.DeclareAskWorkers(ctx, js, sdkstep.AskGo, 30*time.Second); err != nil { t.Fatal(err) } t.Cleanup(func() { _ = js.DeleteStream(context.Background(), "SEAT_NODE_BUILD_GO") }) check := deliveryAsk() - check.Kind = delivery.AskCheck - check.Build.Fetch["commit"] = checkCommit + check.Kind = sdkstep.AskCheck + check.Build.Fetch.Commit = checkCommit first := deliveryAsk() - for _, a := range []delivery.StepAsk{check, first} { - raw, _ := delivery.EncodeStepAsk(a) - subject, _ := delivery.AskSubject(a.Language, a.Kind) + for _, a := range []sdkstep.StepAsk{check, first} { + raw, _ := sdkstep.EncodeStepAsk(a) + subject, _ := sdkstep.AskSubject(a.Language, a.Kind) if _, err := js.Publish(ctx, subject, raw); err != nil { t.Fatal(err) } @@ -74,19 +74,19 @@ func TestTheModuleTakesADeliveryAskBeforeAnEarlierCheck(t *testing.T) { } } } - p := m.Puller(steps, &buildstep.JetStreamAsks{JS: js, Language: delivery.AskGo}) + p := m.Puller(steps, &buildstep.JetStreamAsks{JS: js, Language: sdkstep.AskGo}) p.PullWait = 200 * time.Millisecond go p.Pull(ctx) - var ran map[string][]delivery.Step + var ran map[string][]sdkstep.Step for deadline := time.Now().Add(10 * time.Second); ; time.Sleep(10 * time.Millisecond) { - ran = map[string][]delivery.Step{} + ran = map[string][]sdkstep.Step{} ended := 0 states.mu.Lock() - for _, a := range []delivery.StepAsk{first, check} { - key, _ := delivery.AskStepKey("ace", a.ID) - v := append([]delivery.Step(nil), states.steps[key]...) + for _, a := range []sdkstep.StepAsk{first, check} { + key, _ := sdkstep.AskStepKey("ace", a.ID) + v := append([]sdkstep.Step(nil), states.steps[key]...) ran[a.ID] = v - if len(v) > 0 && v[len(v)-1].State != delivery.StepRunning { + if len(v) > 0 && v[len(v)-1].State != sdkstep.StepRunning { ended++ } } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/asks_test.go b/modules/mesh-build-go/cmd/mesh-build-go/asks_test.go index f1e0517b3..90c0ec0c9 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/asks_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/asks_test.go @@ -13,7 +13,6 @@ import ( "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" ) const askCommit = "0123456789abcdef0123456789abcdef01234567" @@ -34,11 +33,11 @@ func fakeSteps(calls *[]string) []StepTool { } } -func deliveryAsk() delivery.StepAsk { - return delivery.StepAsk{ID: sdkstep.NewID(), Kind: delivery.AskDelivery, Language: delivery.AskGo, Asker: "mesh-delivery-builder", - At: time.Now(), Build: &delivery.BuildJob{Module: "mesh-delivery-view", Path: "modules/mesh-delivery-view", Publish: true, - Fetch: map[string]any{"repository": "novox/mesh-delivery", "commit": askCommit}, - Artifacts: []delivery.AskArtifact{{Artifact: "program"}}}} +func deliveryAsk() sdkstep.StepAsk { + return sdkstep.StepAsk{ID: sdkstep.NewID(), Kind: sdkstep.AskDelivery, Language: sdkstep.AskGo, Asker: "mesh-delivery-builder", + At: time.Now(), Build: &sdkstep.BuildJob{Module: "mesh-delivery-view", Path: "modules/mesh-delivery-view", Publish: true, + Fetch: &sdkstep.Fetch{Repository: "novox/mesh-delivery", Commit: askCommit}, + Artifacts: []sdkstep.AskArtifact{{Artifact: "program"}}}} } // 1887/A3go: an ask pulled runs build_go_build after build_go_fetch, and the step key . names the @@ -58,13 +57,13 @@ func TestAPulledAskRunsTheBuildAndItsKeyNamesTheReference(t *testing.T) { ctx, stop := context.WithCancel(context.Background()) defer stop() go p.Pull(ctx) - key, _ := delivery.AskStepKey("ace", a.ID) - var step delivery.Step + key, _ := sdkstep.AskStepKey("ace", a.ID) + var step sdkstep.Step for deadline := time.Now().Add(30 * time.Second); ; time.Sleep(5 * time.Millisecond) { states.mu.Lock() v := states.steps[key] states.mu.Unlock() - if len(v) > 0 && v[len(v)-1].State != delivery.StepRunning { + if len(v) > 0 && v[len(v)-1].State != sdkstep.StepRunning { step = v[len(v)-1] break } @@ -72,7 +71,7 @@ func TestAPulledAskRunsTheBuildAndItsKeyNamesTheReference(t *testing.T) { t.Fatalf("the ask's step %s never ended: %v", key, v) } } - if step.State != delivery.StepPassed || !strings.Contains(string(step.Result), "artifact-store://mesh-build-go/tools@sha256:aa") { + if step.State != sdkstep.StepPassed || !strings.Contains(string(step.Result), "artifact-store://mesh-build-go/tools@sha256:aa") { t.Fatalf("the step = %+v", step) } if strings.Join(calls, ",") != "build_go_fetch,build_go_build" { @@ -98,8 +97,8 @@ func TestAtCapacityZeroNothingIsPulledAndTheToolsAnswer(t *testing.T) { defer stop() go p.Pull(ctx) time.Sleep(50 * time.Millisecond) - if src.Waiting(delivery.AskDelivery) != 1 || len(calls) != 0 { - t.Fatalf("a node at capacity 0 pulled: waiting %d, calls %v", src.Waiting(delivery.AskDelivery), calls) + if src.Waiting(sdkstep.AskDelivery) != 1 || len(calls) != 0 { + t.Fatalf("a node at capacity 0 pulled: waiting %d, calls %v", src.Waiting(sdkstep.AskDelivery), calls) } for _, tool := range m.Tools(steps) { if tool.Name == "build_go_fetch" { @@ -134,10 +133,10 @@ func TestManifestClaimsTheGoBuildSeatAndReadsItsCapacity(t *testing.T) { } _ = json.Unmarshal(raw, &doc) // Issue 1806's follow-up: the cores a step needs is a setting of its own, in the settings file, with the SDK's default. - if cores := string(doc.Config[buildstep.CoresPerStepSetting].Default); cores != fmt.Sprint(buildstep.DefaultCoresPerStep[delivery.AskGo]) { - t.Errorf("the cores-per-step default = %s, want %g", cores, buildstep.DefaultCoresPerStep[delivery.AskGo]) + if cores := string(doc.Config[buildstep.CoresPerStepSetting].Default); cores != fmt.Sprint(buildstep.DefaultCoresPerStep[sdkstep.AskGo]) { + t.Errorf("the cores-per-step default = %s, want %g", cores, buildstep.DefaultCoresPerStep[sdkstep.AskGo]) } - if got := buildstep.NodeCoresPerStep(moduleDir+"/files/settings.json", 0, nil)(); got != buildstep.DefaultCoresPerStep[delivery.AskGo] { + if got := buildstep.NodeCoresPerStep(moduleDir+"/files/settings.json", 0, nil)(); got != buildstep.DefaultCoresPerStep[sdkstep.AskGo] { t.Errorf("the settings template holds cores-per-step %g", got) } // And the build hours (the operator, 2026-10-26): a setting of their own, empty by default (any hour), in the template. @@ -198,13 +197,13 @@ func TestACheckAsksDigestIsTheToolsAnswerInTheCall(t *testing.T) { } } ask := m.askSteps(steps) - a := delivery.StepAsk{ID: sdkstep.NewID(), Kind: delivery.AskCheck, Language: delivery.AskGo, Asker: "mesh-delivery-checker", - At: time.Now(), Check: &delivery.CheckJob{Fetch: map[string]any{"repository": "novox/x", "commit": askCommit}, Levels: []string{delivery.LevelUnit}}} + a := sdkstep.StepAsk{ID: sdkstep.NewID(), Kind: sdkstep.AskCheck, Language: sdkstep.AskGo, Asker: "mesh-delivery-checker", + At: time.Now(), Check: &sdkstep.CheckJob{Fetch: sdkstep.Fetch{Repository: "novox/x", Commit: askCommit}, Levels: []string{sdkstep.LevelUnit}}} out, err := buildstep.RunAsk(context.Background(), ask, a) if err != nil { t.Fatal(err) } - if l := out.(delivery.CheckAnswer).Levels; len(l) != 1 || l[0].Digest.Map()["x/a"] != "d1" { + if l := out.(buildstep.CheckAnswer).Levels; len(l) != 1 || l[0].Digest.Map()["x/a"] != "d1" { t.Fatalf("levels = %+v, want the digest's packages", l) } } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/beside_digest_test.go b/modules/mesh-build-go/cmd/mesh-build-go/beside_digest_test.go index f59242f7c..b3c90d921 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/beside_digest_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/beside_digest_test.go @@ -2,13 +2,12 @@ package main import ( "encoding/json" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "slices" "strings" "testing" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // writeSiblings records the siblings the fetch placed, as the fetch does. @@ -93,7 +92,7 @@ func TestTheFetchRecordsTheSiblingsItPlaced(t *testing.T) { st := states.waitEnd(t) var res FetchResult json.Unmarshal(st.Result, &res) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } raw, err := os.ReadFile(filepath.Join(m.Work, res.Workspace, besideRecord)) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/build.go b/modules/mesh-build-go/cmd/mesh-build-go/build.go index 11ba13286..512634d42 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/build.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/build.go @@ -9,13 +9,13 @@ package main import ( "context" "fmt" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "os" "path/filepath" "strings" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // The Go recipe of the build agent (toolchain.go, the entry of language go): static, trimmed of its own paths and of @@ -177,7 +177,7 @@ func (m *Module) packInto(ctx context.Context, workspace, module, name, artifact return BuildResult{}, fmt.Errorf("packing %s: %w", artifact, err) } if err := m.publishArchive(ctx, name, artifact, kind, digest, archive); err != nil { - return BuildResult{}, fmt.Errorf("%s%s: %v", delivery.NotStored, artifact, err) + return BuildResult{}, fmt.Errorf("%s%s: %v", builds.NotStored, artifact, err) } return BuildResult{Artifact: artifact, Digest: digest, Size: len(archive), Reference: catalogue.SeatReference(ArtifactSeat, name, artifact, digest)}, nil } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/build_test.go b/modules/mesh-build-go/cmd/mesh-build-go/build_test.go index 2583dfc48..c92812b35 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/build_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/build_test.go @@ -7,6 +7,7 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "io" "os" "path/filepath" @@ -14,7 +15,6 @@ import ( "strings" "testing" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" ) @@ -56,7 +56,7 @@ func buildModule(t *testing.T, manifest, content string) (*Module, *keptStates, return m, states, calls } -func runBuild(t *testing.T, m *Module, states *keptStates, artifact string) (BuildResult, delivery.Step) { +func runBuild(t *testing.T, m *Module, states *keptStates, artifact string) (BuildResult, sdkstep.Step) { t.Helper() for _, tool := range m.Tools(m.StepTools()) { if tool.Name == "build_go_build" { @@ -67,7 +67,7 @@ func runBuild(t *testing.T, m *Module, states *keptStates, artifact string) (Bui } st := states.waitEnd(t) var res BuildResult - if st.State == delivery.StepPassed { + if st.State == sdkstep.StepPassed { if err := json.Unmarshal(st.Result, &res); err != nil { t.Fatal(err) } @@ -106,7 +106,7 @@ func goEntry(t *testing.T) (compile []string, linker []string, stamp string) { func TestTheBuildCommandCarriesTodaysFlagsAndEnvironment(t *testing.T) { m, states, calls := buildModule(t, manifestWith(goBundle), "binary") res, st := runBuild(t, m, states, "tools") - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } compile, linker, stamp := goEntry(t) @@ -177,12 +177,12 @@ func TestAnArtifactOfAnotherLanguageFailsTheStepNamingIt(t *testing.T) { } { m, states, calls := buildModule(t, manifestWith(artifact), "x") _, st := runBuild(t, m, states, "tools") - if st.State != delivery.StepFailed || !strings.Contains(st.Reason, "tools") || !strings.Contains(st.Reason, want) || len(*calls) != 0 { + if st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, "tools") || !strings.Contains(st.Reason, want) || len(*calls) != 0 { t.Errorf("%s: the step ended %s: %q after %d commands", artifact, st.State, st.Reason, len(*calls)) } } m, states, _ := buildModule(t, manifestWith(goBundle), "x") - if _, st := runBuild(t, m, states, "nope"); st.State != delivery.StepFailed || !strings.Contains(st.Reason, `"nope"`) || !strings.Contains(st.Reason, "tools") { + if _, st := runBuild(t, m, states, "nope"); st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, `"nope"`) || !strings.Contains(st.Reason, "tools") { t.Errorf("an unknown artifact: %s %q", st.State, st.Reason) } } @@ -209,7 +209,7 @@ func TestAModuleDirectoryOutsideTheWorkspaceIsRefused(t *testing.T) { tool.Run(map[string]any{"workspace": "ws1", "module": "../../..", "artifact": "tools"}) } } - if st := states.waitEnd(t); st.State != delivery.StepFailed || len(*calls) != 0 { + if st := states.waitEnd(t); st.State != sdkstep.StepFailed || len(*calls) != 0 { t.Errorf("the step ended %s after %d commands", st.State, len(*calls)) } } @@ -230,7 +230,7 @@ func TestABuildOutputDirectoryLinkedOutsideTheModuleIsRefused(t *testing.T) { t.Fatal(err) } _, st := runBuild(t, m, states, "tools") - if st.State != delivery.StepFailed || !strings.Contains(st.Reason, "outside") || !strings.Contains(st.Reason, outside) || len(*calls) != 0 { + if st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, "outside") || !strings.Contains(st.Reason, outside) || len(*calls) != 0 { t.Errorf("the step ended %s: %q after %d commands", st.State, st.Reason, len(*calls)) } if body, err := os.ReadFile(kept); err != nil || string(body) != "mine" { @@ -248,7 +248,7 @@ func TestAManifestFallingBackToAPredefinedKeyBuilds(t *testing.T) { } m, states, _ := buildModule(t, string(raw), "binary") res, st := runBuild(t, m, states, "tools") - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } if res.Artifact != "tools" || res.Binary != "claude-code" || !strings.HasPrefix(res.Digest, "sha256:") { diff --git a/modules/mesh-build-go/cmd/mesh-build-go/candidate_test.go b/modules/mesh-build-go/cmd/mesh-build-go/candidate_test.go index cf12dadd2..640e4142b 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/candidate_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/candidate_test.go @@ -3,13 +3,13 @@ package main import ( "context" "encoding/json" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "slices" "strings" "testing" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" ) @@ -88,14 +88,14 @@ func newCandidateRig(t *testing.T) *candidateRig { return cr } -func (cr *candidateRig) test(t *testing.T, args map[string]any) (TestResult, delivery.Step) { +func (cr *candidateRig) test(t *testing.T, args map[string]any) (TestResult, sdkstep.Step) { t.Helper() if _, err := stepTool(t, cr.m, "build_go_test")(args); err != nil { t.Fatal(err) } st := cr.states.waitEnd(t) var res TestResult - if st.State == delivery.StepPassed { + if st.State == sdkstep.StepPassed { if err := json.Unmarshal(st.Result, &res); err != nil { t.Fatalf("result %s: %v", st.Result, err) } @@ -119,7 +119,7 @@ func TestTheDigestAndTestToolsAnnounceTheRunner(t *testing.T) { // 1898 K1, ADR func TestTheUnitLevelUnderTheWorkspaceRunnerRunsTheCandidateShutOff(t *testing.T) { // 1898 K1, K2 (AC4's unit part) cr := newCandidateRig(t) res, st := cr.test(t, map[string]any{"workspace": "ws1", "level": LevelUnit, "runner": RunnerWorkspace, "packages": []any{"./..."}}) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } if res.Tests != 42 || res.Why != "mark" || res.JudgedBy != "candidate "+candidateSHA { @@ -146,7 +146,7 @@ func TestTheUnitLevelUnderTheWorkspaceRunnerRunsTheCandidateShutOff(t *testing.T func TestTheIntegrationLevelUnderTheWorkspaceRunnerRunsTheCandidate(t *testing.T) { // 1898 K2 cr := newCandidateRig(t) res, st := cr.test(t, map[string]any{"workspace": "ws1", "level": LevelIntegration, "runner": RunnerWorkspace}) - if st.State != delivery.StepPassed || res.JudgedBy != "candidate "+candidateSHA { + if st.State != sdkstep.StepPassed || res.JudgedBy != "candidate "+candidateSHA { t.Fatalf("the step ended %s (%s): %+v", st.State, st.Reason, res) } if len(cr.specs) != 1 || cr.specs[0].Step != stepIntegration || cr.specs[0].Bound != IntegrationRun || cr.specs[0].Setup != IntegrationSetup { @@ -177,7 +177,7 @@ func TestACandidateThatDoesNotCompileFailsTheStepWithTheCompilersFirstErrorAndRu cr := newCandidateRig(t) cr.compile = forgekey.Ran{Status: 1, Stderr: "# meshbuildgo/cmd/mesh-build-go\ncmd/mesh-build-go/digest.go:12:2: undefined: x\ncmd/mesh-build-go/digest.go:13:2: undefined: y\n"} _, st := cr.test(t, map[string]any{"workspace": "ws1", "level": LevelUnit, "runner": RunnerWorkspace}) - if st.State == delivery.StepPassed || !strings.Contains(st.Reason, "does not compile: cmd/mesh-build-go/digest.go:12:2: undefined: x") || strings.Contains(st.Reason, "undefined: y") { + if st.State == sdkstep.StepPassed || !strings.Contains(st.Reason, "does not compile: cmd/mesh-build-go/digest.go:12:2: undefined: x") || strings.Contains(st.Reason, "undefined: y") { t.Fatalf("the step ended %s: %q, want it failed naming the first compile error", st.State, st.Reason) } if len(cr.specs) != 0 { @@ -202,7 +202,7 @@ func TestTheInstalledProgramSaysItJudged(t *testing.T) { // 1898 K1, ADR 0535 § args["runner"] = runner } res, st := runUnitWith(t, m, states, args) - if st.State != delivery.StepPassed || res.JudgedBy != RunnerInstalled { + if st.State != sdkstep.StepPassed || res.JudgedBy != RunnerInstalled { t.Errorf("runner %v: the step ended %s, judged by %q, want installed", runner, st.State, res.JudgedBy) } } @@ -246,14 +246,14 @@ func TestTheShutOffProcessRunsTheStepItIsAsked(t *testing.T) { // 1898 K2: the c } } -func runUnitWith(t *testing.T, m *Module, states *keptStates, args map[string]any) (TestResult, delivery.Step) { +func runUnitWith(t *testing.T, m *Module, states *keptStates, args map[string]any) (TestResult, sdkstep.Step) { t.Helper() if _, err := stepTool(t, m, "build_go_test")(args); err != nil { t.Fatal(err) } st := states.waitEnd(t) var res TestResult - if st.State == delivery.StepPassed { + if st.State == sdkstep.StepPassed { if err := json.Unmarshal(st.Result, &res); err != nil { t.Fatalf("result %s: %v", st.Result, err) } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/compose.go b/modules/mesh-build-go/cmd/mesh-build-go/compose.go index 20c1fa557..3a8155c3d 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/compose.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/compose.go @@ -7,9 +7,9 @@ package main // engine cannot judge its own next code. The module fetches the commit // (its fetch step: the forge key and the network, none of the change's code), builds the composer package in the Go // module the ask names, in a run step shut off with nothing fetched, and keeps the program under its key -// (delivery.ComposerKey), so each commit is built once on a node. It fills the request's manifests from the delivery +// (sdkstep.ComposerKey), so each commit is built once on a node. It fills the request's manifests from the delivery // indexer's manifests state, by digest, and runs the program shut off: no network, none of the account, the request a -// file of a workspace of its own. The answer is the composer's verdict whole (delivery.ComposeAnswer); the module +// file of a workspace of its own. The answer is the composer's verdict whole (sdkstep.ComposeAnswer); the module // judges nothing of it. import ( @@ -17,6 +17,7 @@ import ( "encoding/json" "errors" "fmt" + catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "io" "os" "path/filepath" @@ -29,14 +30,16 @@ import ( sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-delivery/sdk/composer" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/views" ) // ManifestsTool is the delivery indexer's read tool of its manifests by digest, which a compose ask's request names (the // module invokes it, module.json invokes). A manifest by its digest never changes and a compose ask is rare, so the // module asks for the one key it needs when it needs it, and keeps no picture of the indexer's whole state (ADR 0615). -const ManifestsTool = delivery.IndexerModule + ".indexer_read_manifests" +// indexerModule is the module that holds the seat mesh-catalog, whose manifests state a compose ask reads. +const indexerModule = "mesh-delivery-indexer" + +const ManifestsTool = indexerModule + ".indexer_read_manifests" // composerLocks hold one mutex per composer key, so a composer two asks need at once is built once. var composerLocks sync.Map @@ -47,15 +50,14 @@ func (m *Module) composerPath(key string) string { } // compose runs a compose ask: the composer of its commit, built once, over its request with the manifests filled. -func (m *Module) compose(ctx context.Context, fetch buildstep.StepFunc, a delivery.StepAsk) (any, error) { +func (m *Module) compose(ctx context.Context, fetch buildstep.StepFunc, a sdkstep.StepAsk) (any, error) { job := *a.Compose - repository, _ := job.Fetch["repository"].(string) - commit, _ := job.Fetch["commit"].(string) + repository, commit := job.Fetch.Repository, job.Fetch.Commit installed, err := m.Probe(ctx) if err != nil { return nil, err } - key := delivery.ComposerKey(repository, commit, job.Dir, job.Package, delivery.ToolchainUsed{Version: installed, Recipe: m.Recipe.Version()}) + key := sdkstep.ComposerKey(repository, commit, job.Dir, job.Package, sdkstep.ToolchainUsed{Version: installed, Recipe: m.Recipe.Version()}) exe, built, err := m.composerOf(ctx, fetch, job, key) if err != nil { return nil, err @@ -71,7 +73,7 @@ func (m *Module) compose(ctx context.Context, fetch buildstep.StepFunc, a delive if err != nil { return nil, err } - return delivery.ComposeAnswer{Built: built, Key: key, Verdict: verdict}, nil + return sdkstep.ComposeAnswer{Built: built, Key: key, Verdict: verdict}, nil } // askManifest asks the indexer's read tool for one manifest by its key: nil when it keeps none. A call the indexer does not @@ -81,7 +83,7 @@ func askManifest(key string) (json.RawMessage, error) { } func askManifestVia(ask func(string, any) (json.RawMessage, error), findings views.FindingWriter, now func() time.Time, key string) (json.RawMessage, error) { - st := views.Status{Owner: delivery.IndexerModule, Tool: ManifestsTool, State: "manifests", Asked: now().UTC()} + st := views.Status{Owner: indexerModule, Tool: ManifestsTool, State: "manifests", Asked: now().UTC()} raw, err := ask(ManifestsTool, map[string]any{"key": key}) if err != nil { st.Error = err.Error() @@ -107,7 +109,7 @@ func (m *Module) manifestOf(digest string) ([]byte, error) { if m.ReadManifest == nil { return nil, errors.New("this module reads no manifests state") } - key, err := delivery.ManifestsKey(digest) + key, err := catalogclient.ManifestsKey(digest) if err != nil { return nil, err } @@ -118,15 +120,15 @@ func (m *Module) manifestOf(digest string) ([]byte, error) { if raw == nil { return nil, fmt.Errorf("the indexer keeps no manifest of digest %s", digest) } - man, err := delivery.DecodeManifest(raw) + man, err := catalogclient.DecodeManifest(raw) if err != nil { return nil, err } - return []byte(man.JSON), nil + return []byte(man.Manifest), nil } // composerOf is the composer kept under key, or, when none is, the one built now from the fetched commit (built true). -func (m *Module) composerOf(ctx context.Context, fetch buildstep.StepFunc, job delivery.ComposeJob, key string) (string, bool, error) { +func (m *Module) composerOf(ctx context.Context, fetch buildstep.StepFunc, job sdkstep.ComposeJob, key string) (string, bool, error) { exe := m.composerPath(key) mu, _ := composerLocks.LoadOrStore(exe, &sync.Mutex{}) mu.(*sync.Mutex).Lock() @@ -137,7 +139,11 @@ func (m *Module) composerOf(ctx context.Context, fetch buildstep.StepFunc, job d if fetch == nil { return "", false, buildstep.Refuse("this build module fetches nothing") } - out, err := fetch(ctx, job.Fetch) + args, err := buildstep.FetchArgs(job.Fetch) + if err != nil { + return "", false, err + } + out, err := fetch(ctx, args) if err != nil { return "", false, err } @@ -156,7 +162,7 @@ func (m *Module) composerOf(ctx context.Context, fetch buildstep.StepFunc, job d defer done() dir := filepath.Join(m.Work, f.Workspace, "tree", job.Dir) if _, err := os.Stat(filepath.Join(dir, "go.mod")); err != nil { - return "", false, fmt.Errorf("%s at %s holds no go.mod in %s, so no composer can be built there", job.Fetch["repository"], job.Fetch["commit"], job.Dir) + return "", false, fmt.Errorf("%s at %s holds no go.mod in %s, so no composer can be built there", job.Fetch.Repository, job.Fetch.Commit, job.Dir) } into := filepath.Join(m.Work, f.Workspace, "composer", "mesh-compose") if err := os.MkdirAll(filepath.Dir(into), 0o700); err != nil { @@ -171,7 +177,7 @@ func (m *Module) composerOf(ctx context.Context, fetch buildstep.StepFunc, job d if r.Status != 0 || r.Err != "" { // The words Go says when the module holds no such package (a mesh-sdk from before the composer) are kept whole, // so the asker tells that apart from a fault. - return "", false, fmt.Errorf("the composer %s does not build at %s: %s", job.Package, job.Fetch["commit"], compileError(r.Err+"\n"+r.Stderr+"\n"+r.Stdout)) + return "", false, fmt.Errorf("the composer %s does not build at %s: %s", job.Package, job.Fetch.Commit, compileError(r.Err+"\n"+r.Stderr+"\n"+r.Stdout)) } if err := copyExecutable(into, exe); err != nil { return "", false, fmt.Errorf("the composer could not be kept: %w", err) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/compose_integration_test.go b/modules/mesh-build-go/cmd/mesh-build-go/compose_integration_test.go index 5ef7f6c09..72b6b442a 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/compose_integration_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/compose_integration_test.go @@ -5,6 +5,7 @@ package main import ( "context" "encoding/json" + catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "io/fs" "os" "os/exec" @@ -19,7 +20,6 @@ import ( "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-delivery/sdk/composer" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" "git.novox.be/novox/mesh-sdk/go/testbus" ) @@ -111,7 +111,7 @@ func TestAComposeAskIsBuiltOnceAndAnsweredOnTheBus(t *testing.T) { } ctx, stop := context.WithCancel(context.Background()) defer stop() - if err := buildstep.DeclareAskWorkers(ctx, js, delivery.AskGo, 2*time.Minute); err != nil { + if err := buildstep.DeclareAskWorkers(ctx, js, sdkstep.AskGo, 2*time.Minute); err != nil { t.Fatal(err) } t.Cleanup(func() { _ = js.DeleteStream(context.Background(), "SEAT_NODE_BUILD_GO") }) @@ -158,39 +158,39 @@ func TestAComposeAskIsBuiltOnceAndAnsweredOnTheBus(t *testing.T) { } } } - p := m.Puller(steps, &buildstep.JetStreamAsks{JS: js, Language: delivery.AskGo}) + p := m.Puller(steps, &buildstep.JetStreamAsks{JS: js, Language: sdkstep.AskGo}) p.PullWait = 200 * time.Millisecond go p.Pull(ctx) - ask := func() delivery.Step { + ask := func() sdkstep.Step { a := composeAskOf(t, digests[0]) - a.Compose.Fetch["repository"], a.Compose.Dir, a.Compose.Package = "novox/mesh-host", delivery.RootPath, "github.com/novox/mesh-host/cmd/mesh-compose" - raw, err := delivery.EncodeStepAsk(a) + a.Compose.Fetch.Repository, a.Compose.Dir, a.Compose.Package = "novox/mesh-host", catalogclient.RootPath, "github.com/novox/mesh-host/cmd/mesh-compose" + raw, err := sdkstep.EncodeStepAsk(a) if err != nil { t.Fatal(err) } - subject, _ := delivery.AskSubject(delivery.AskGo, delivery.AskCheck) + subject, _ := sdkstep.AskSubject(sdkstep.AskGo, sdkstep.AskCheck) if _, err := js.Publish(ctx, subject, raw); err != nil { t.Fatal(err) } - key, _ := delivery.AskStepKey("ace", a.ID) + key, _ := sdkstep.AskStepKey("ace", a.ID) for deadline := time.Now().Add(90 * time.Second); time.Now().Before(deadline); time.Sleep(50 * time.Millisecond) { states.mu.Lock() v := states.steps[key] states.mu.Unlock() - if len(v) > 0 && v[len(v)-1].State != delivery.StepRunning { + if len(v) > 0 && v[len(v)-1].State != sdkstep.StepRunning { return v[len(v)-1] } } t.Fatalf("the compose ask %s never ended", a.ID) - return delivery.Step{} + return sdkstep.Step{} } for n, wantBuilt := range []bool{true, false} { step := ask() - if step.State != delivery.StepPassed { + if step.State != sdkstep.StepPassed { t.Fatalf("ask %d: %s: %s", n+1, step.State, step.Reason) } - var ans delivery.ComposeAnswer + var ans sdkstep.ComposeAnswer var v composer.Verdict if err := json.Unmarshal(step.Result, &ans); err != nil { t.Fatal(err) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/compose_test.go b/modules/mesh-build-go/cmd/mesh-build-go/compose_test.go index 0f9d6dece..3f01603ec 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/compose_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/compose_test.go @@ -4,6 +4,8 @@ import ( "context" "encoding/json" "errors" + catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" + meshcat "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" "os" "path/filepath" "slices" @@ -13,7 +15,6 @@ import ( sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-delivery/sdk/composer" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" "git.novox.be/novox/mesh-sdk/go/views" ) @@ -29,9 +30,9 @@ func indexerHolds(t *testing.T, bodies ...string) (func(string) (json.RawMessage t.Helper() kept, digests := map[string]json.RawMessage{}, []string{} for _, b := range bodies { - d := delivery.ManifestDigest([]byte(b)) - key, _ := delivery.ManifestsKey(d) - raw, err := delivery.EncodeManifest(delivery.Manifest{Module: "demo", JSON: b}) + d := catalogclient.ManifestDigest([]byte(b)) + key, _ := catalogclient.ManifestsKey(d) + raw, err := catalogclient.EncodeManifest(meshcat.ManifestsByDigestValue{Module: "demo", Manifest: b}) if err != nil { t.Fatal(err) } @@ -40,12 +41,12 @@ func indexerHolds(t *testing.T, bodies ...string) (func(string) (json.RawMessage return func(key string) (json.RawMessage, error) { return kept[key], nil }, digests } -func composeAskOf(t *testing.T, digest string) delivery.StepAsk { +func composeAskOf(t *testing.T, digest string) sdkstep.StepAsk { t.Helper() req, _ := json.Marshal(composer.Request{V: composer.Version, Cases: []composer.Case{{Name: "change", Manifests: map[string]composer.Manifest{"demo": {Digest: digest}}}}}) - return delivery.StepAsk{ID: sdkstep.NewID(), Kind: delivery.AskCheck, Language: delivery.AskGo, Asker: "mesh-delivery-assigner", - At: time.Now(), Compose: &delivery.ComposeJob{Fetch: map[string]any{"repository": "novox/mesh-sdk", "commit": composeCommit}, + return sdkstep.StepAsk{ID: sdkstep.NewID(), Kind: sdkstep.AskCheck, Language: sdkstep.AskGo, Asker: "mesh-delivery-assigner", + At: time.Now(), Compose: &sdkstep.ComposeJob{Fetch: sdkstep.Fetch{Repository: "novox/mesh-sdk", Commit: composeCommit}, Dir: "go", Package: composer.Package, Request: req}} } @@ -66,7 +67,7 @@ func TestAKeptComposerIsRunWithTheManifestsFilled(t *testing.T) { read, digests := indexerHolds(t, `{"module":"demo","version":"1"}`) m.ReadManifest = read a := composeAskOf(t, digests[0]) - key := delivery.ComposerKey("novox/mesh-sdk", composeCommit, "go", composer.Package, delivery.ToolchainUsed{Version: "go1.26.0", Recipe: m.Recipe.Version()}) + key := sdkstep.ComposerKey("novox/mesh-sdk", composeCommit, "go", composer.Package, sdkstep.ToolchainUsed{Version: "go1.26.0", Recipe: m.Recipe.Version()}) exe := m.composerPath(key) if err := os.MkdirAll(filepath.Dir(exe), 0o700); err != nil { t.Fatal(err) @@ -84,7 +85,7 @@ func TestAKeptComposerIsRunWithTheManifestsFilled(t *testing.T) { if err != nil { t.Fatal(err) } - ans := out.(delivery.ComposeAnswer) + ans := out.(sdkstep.ComposeAnswer) var v composer.Verdict if err := json.Unmarshal(ans.Verdict, &v); err != nil { t.Fatal(err) @@ -103,7 +104,7 @@ func TestAComposeAskFailsLoudly(t *testing.T) { m := composeModule(t) m.ReadManifest, _ = indexerHolds(t) a := composeAskOf(t, "feedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed") - key := delivery.ComposerKey("novox/mesh-sdk", composeCommit, "go", composer.Package, delivery.ToolchainUsed{Version: "go1.26.0", Recipe: m.Recipe.Version()}) + key := sdkstep.ComposerKey("novox/mesh-sdk", composeCommit, "go", composer.Package, sdkstep.ToolchainUsed{Version: "go1.26.0", Recipe: m.Recipe.Version()}) os.MkdirAll(filepath.Dir(m.composerPath(key)), 0o700) os.WriteFile(m.composerPath(key), []byte("#!/bin/sh\nexit 0\n"), 0o700) if _, err := m.compose(context.Background(), nil, a); err == nil || !strings.Contains(err.Error(), "feedfeed") { @@ -127,7 +128,7 @@ func TestAComposeAskFailsLoudly(t *testing.T) { // 1622, ADR 0615: the module asks the delivery indexer's read tool for the manifests a compose ask names by digest, and // reads none of the indexer's state. func TestTheModuleReadsTheIndexersManifests(t *testing.T) { - if m := readManifest(t); !slices.Contains(m.Invokes, ManifestsTool) || slices.Contains(m.Reads, delivery.IndexerModule+".manifests") { + if m := readManifest(t); !slices.Contains(m.Invokes, ManifestsTool) || slices.Contains(m.Reads, indexerModule+".manifests") { t.Errorf("invokes = %v, reads = %v: it asks %s", m.Invokes, m.Reads, ManifestsTool) } } @@ -161,7 +162,7 @@ func TestAComposeAskBuildsTheNodeEnginesComposerAtItsRoot(t *testing.T) { read, digests := indexerHolds(t, `{"module":"demo","version":"1"}`) m.ReadManifest = read a := composeAskOf(t, digests[0]) - a.Compose.Fetch["repository"], a.Compose.Dir, a.Compose.Package = "novox/mesh-host", delivery.RootPath, nodeEngineComposer + a.Compose.Fetch.Repository, a.Compose.Dir, a.Compose.Package = "novox/mesh-host", catalogclient.RootPath, nodeEngineComposer tree := "" var built []string real := m.Run @@ -191,8 +192,8 @@ func TestAComposeAskBuildsTheNodeEnginesComposerAtItsRoot(t *testing.T) { if err != nil { t.Fatal(err) } - ans := out.(delivery.ComposeAnswer) - key := delivery.ComposerKey("novox/mesh-host", composeCommit, delivery.RootPath, nodeEngineComposer, delivery.ToolchainUsed{Version: "go1.26.0", Recipe: m.Recipe.Version()}) + ans := out.(sdkstep.ComposeAnswer) + key := sdkstep.ComposerKey("novox/mesh-host", composeCommit, catalogclient.RootPath, nodeEngineComposer, sdkstep.ToolchainUsed{Version: "go1.26.0", Recipe: m.Recipe.Version()}) var v composer.Verdict if err := json.Unmarshal(ans.Verdict, &v); err != nil { t.Fatal(err) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/digest.go b/modules/mesh-build-go/cmd/mesh-build-go/digest.go index 2a8310b3d..961457a3c 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/digest.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/digest.go @@ -13,6 +13,8 @@ import ( "encoding/json" "errors" "fmt" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" + trunk "git.novox.be/novox/mesh-delivery/sdk/trunk" "io" "io/fs" "os" @@ -21,8 +23,6 @@ import ( "sort" "strconv" "strings" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // DigestVersion is the form of the digest's text: changed whenever what the digest hashes changes in kind. @@ -56,7 +56,7 @@ const namesVariable = "MESH_NODE_NAMES" const ReadsOutsideMarker = "reads-outside" // NeedsMarker is the name of a file in a package's directory that names, one per line, what its integration tests need -// of the node they run on (issue 890; mesh-sdk delivery.AskNeeds): `node-build-node` for tests that read the Node build +// of the node they run on (issue 890; mesh-delivery-sdk buildstep.AskNeeds): `node-build-node` for tests that read the Node build // module's installed toolchain. The digest reports it (DigestResult.Needs); a check ask leaves such a package untested on // a node that lacks it, and the checker asks it again of a node that has it. A marker beside the tests, as // ReadsOutsideMarker is, and not a manifest field: it is a property of the package's tests, read only where they are @@ -149,7 +149,7 @@ type DigestResult struct { neverKept map[string]string hashedFiles map[string]string // Needs are the packages whose tests at this level need something of the node, as their NeedsMarker names it. - Needs []delivery.PackageNeeds `json:"needs,omitempty"` + Needs []sdkstep.PackageNeeds `json:"needs,omitempty"` // JudgedBy is the program that ran the digest (ADR 0535 §5): "installed", or "candidate " under the // runner workspace. JudgedBy string `json:"judged_by,omitempty"` @@ -168,8 +168,8 @@ func (m *Module) digestTool() StepTool { "workspace": map[string]any{"type": "string", "description": "the workspace id build_go_fetch answered"}, "level": map[string]any{"type": "string", "enum": []string{LevelUnit, LevelIntegration}, "description": "the level"}, "runner": runnerProperty, - delivery.NodeNamesArg: map[string]any{"type": "array", "items": map[string]any{"type": "string"}, - "description": "optional, the names of the mesh's nodes: a package whose tests read " + delivery.NodeNamesEnv + " has them in its digest"}, + sdkstep.NodeNamesArg: map[string]any{"type": "array", "items": map[string]any{"type": "string"}, + "description": "optional, the names of the mesh's nodes: a package whose tests read " + sdkstep.NodeNamesEnv + " has them in its digest"}, }, "required": []string{"workspace", "level"}, }, @@ -184,7 +184,7 @@ func (m *Module) digest(ctx context.Context, args map[string]any) (any, error) { if err != nil { return nil, err } - names, err := nodeNamesArg(args[delivery.NodeNamesArg]) + names, err := nodeNamesArg(args[sdkstep.NodeNamesArg]) if err != nil { return nil, err } @@ -344,7 +344,7 @@ func digestModule(res *DigestResult, pkgs map[string]*goPackage, tree string, he return fmt.Errorf("%s: its %s: %w", path, NeedsMarker, err) } if len(n) > 0 { - res.Needs = append(res.Needs, delivery.PackageNeeds{Package: path, Needs: n}) + res.Needs = append(res.Needs, sdkstep.PackageNeeds{Package: path, Needs: n}) } } declared, why, err := declaredReads(tree, root, res.hashed()) @@ -401,7 +401,7 @@ func packageDigest(root, testMain *goPackage, pkgs map[string]*goPackage, tree s // A module outside the tree counts by its version and checksum; a package of the mesh's own forge by the content of // its files, as a local replacement does, so a new version of a mesh package whose reached files are the same keeps // every verdict kept for them (ADR 0593 §5, ADR 0444 §3). - if !mod.Main && mod.Version != "" && !strings.HasPrefix(mod.Path, delivery.ForgeModulePrefix) { + if !mod.Main && mod.Version != "" && !strings.HasPrefix(mod.Path, trunk.ForgeModulePrefix) { lines = append(lines, "module "+mod.Path+"@"+mod.Version+" "+mod.Sum) continue } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/fetch_test.go b/modules/mesh-build-go/cmd/mesh-build-go/fetch_test.go index ac3c25a2c..9f4ae2d1b 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/fetch_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/fetch_test.go @@ -3,6 +3,7 @@ package main import ( "context" "encoding/json" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" @@ -10,7 +11,6 @@ import ( "testing" "time" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" ) @@ -112,7 +112,7 @@ func TestFetchAsksGitForTheSshRemoteAndDownloadsEachModule(t *testing.T) { t.Fatal(err) } st := states.waitEnd(t) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } lines := strings.Join(f.lines(), "\n") @@ -222,7 +222,7 @@ func TestAVerifyThatFailsEndsTheStepNamingTheDirectoryAndTheLine(t *testing.T) { t.Fatal(err) } st := states.waitEnd(t) - if st.State != delivery.StepFailed { + if st.State != sdkstep.StepFailed { t.Fatalf("the step ended %s, want failed", st.State) } if !strings.Contains(st.Reason, "tools") || !strings.Contains(st.Reason, "example.org/x v1.0.0: dir has been modified") || strings.Contains(st.Reason, "second line") { @@ -251,7 +251,7 @@ func TestTheCallAnswersAStepIdBeforeTheFetchEnds(t *testing.T) { states.mu.Lock() running := states.steps["ace."+id] states.mu.Unlock() - if len(running) != 1 || running[0].State != delivery.StepRunning { + if len(running) != 1 || running[0].State != sdkstep.StepRunning { t.Errorf("the key holds %+v, want one running step", running) } close(f.gate) @@ -267,7 +267,7 @@ func TestTheCallAnswersAStepIdBeforeTheFetchEnds(t *testing.T) { last := states.steps["ace."+id][len(states.steps["ace."+id])-1] states.mu.Unlock() var res FetchResult - if last.State != delivery.StepPassed || json.Unmarshal(last.Result, &res) != nil || res.Workspace == "" { + if last.State != sdkstep.StepPassed || json.Unmarshal(last.Result, &res) != nil || res.Workspace == "" { t.Errorf("the key ends %+v", last) } } @@ -278,7 +278,7 @@ func TestARepositoryThatIsNotOwnerSlashNameIsRefusedBeforeAnythingRuns(t *testin m, states := fetchModule(t, f) fetchTool(t, m)(map[string]any{"repository": repo, "commit": commitSHA}) st := states.waitEnd(t) - if st.State != delivery.StepFailed || len(f.lines()) != 0 { + if st.State != sdkstep.StepFailed || len(f.lines()) != 0 { t.Errorf("%q: the step ended %s after %d commands", repo, st.State, len(f.lines())) } } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/gopackage.go b/modules/mesh-build-go/cmd/mesh-build-go/gopackage.go index 6201fe299..fb60b04fa 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/gopackage.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/gopackage.go @@ -13,6 +13,7 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "io" "os" "path/filepath" @@ -23,7 +24,6 @@ import ( modzip "golang.org/x/mod/zip" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // GoPackageSeat is the registry seat a Go package is published on. @@ -82,7 +82,7 @@ func (m *Module) buildGoPackage(ctx context.Context, workspace, dir string, art return res, nil } if err := m.publishOn(ctx, seat, path, "package", version, digest, transferName(path, version, digest), body); err != nil { - return BuildResult{}, fmt.Errorf("%s%s: %v", delivery.NotStored, art.Name, err) + return BuildResult{}, fmt.Errorf("%s%s: %v", builds.NotStored, art.Name, err) } res.Reference = path + "@" + version return res, nil diff --git a/modules/mesh-build-go/cmd/mesh-build-go/imports.go b/modules/mesh-build-go/cmd/mesh-build-go/imports.go index a0995d101..a19a61d84 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/imports.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/imports.go @@ -9,13 +9,13 @@ package main import ( "context" "fmt" + trunk "git.novox.be/novox/mesh-delivery/sdk/trunk" "os" "path/filepath" "slices" "strings" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" ) @@ -94,14 +94,14 @@ func ModuleImports(ctx context.Context, run forgekey.Runner, env []string, dir s out = append(out, p) } slices.Sort(out) - if err := delivery.CheckImports(out); err != nil { + if err := trunk.CheckImports(out); err != nil { return ImportsResult{}, err } return ImportsResult{Imports: out}, nil } func meshPackage(pkg string) bool { - _, _, ok := delivery.PackageRepository(pkg) + _, _, ok := trunk.PackageRepository(pkg) return ok } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/installed_toolchain_test.go b/modules/mesh-build-go/cmd/mesh-build-go/installed_toolchain_test.go index 5e7ae030a..75d952dff 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/installed_toolchain_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/installed_toolchain_test.go @@ -2,6 +2,7 @@ package main import ( "context" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "reflect" @@ -12,7 +13,6 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep/buildcpu" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" "git.novox.be/novox/mesh-sdk/go/health" ) @@ -73,7 +73,7 @@ func TestTheFetchStepsGoCommandsSayGotoolchainLocalAndFetchNoToolchain(t *testin if _, err := fetchTool(t, m)(fetchArgs); err != nil { t.Fatal(err) } - if st := states.waitEnd(t); st.State != delivery.StepPassed { + if st := states.waitEnd(t); st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } goCalls := 0 diff --git a/modules/mesh-build-go/cmd/mesh-build-go/integration_level_test.go b/modules/mesh-build-go/cmd/mesh-build-go/integration_level_test.go index fafb7bda0..c4e85e65a 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/integration_level_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/integration_level_test.go @@ -3,6 +3,7 @@ package main import ( "context" "encoding/json" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "net/url" "os" "path/filepath" @@ -11,7 +12,6 @@ import ( "testing" "time" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" ) @@ -126,7 +126,7 @@ func integModule(t *testing.T, f *integFake) (*Module, *keptStates) { return m, states } -func runLevelTool(t *testing.T, m *Module, states *keptStates, level string) (TestResult, delivery.Step) { +func runLevelTool(t *testing.T, m *Module, states *keptStates, level string) (TestResult, sdkstep.Step) { t.Helper() for _, tool := range m.Tools(m.StepTools()) { if tool.Name != "build_go_test" { @@ -138,7 +138,7 @@ func runLevelTool(t *testing.T, m *Module, states *keptStates, level string) (Te } st := states.waitEnd(t) var res TestResult - if st.State == delivery.StepPassed { + if st.State == sdkstep.StepPassed { if err := json.Unmarshal(st.Result, &res); err != nil { t.Fatal(err) } @@ -152,7 +152,7 @@ func TestTheStoreListensOnASocketUnderTheRunAndNowhereElse(t *testing.T) { f := newIntegFake(t, "slow") m, states := integModule(t, f) res, st := runLevelTool(t, m, states, "integration") - if st.State != delivery.StepPassed || !res.Passed || res.Level != "integration" { + if st.State != sdkstep.StepPassed || !res.Passed || res.Level != "integration" { t.Fatalf("the step ended %s (%s): %+v", st.State, st.Reason, res) } var start, initdb string @@ -219,14 +219,14 @@ func TestAnotherPostgresMajorRefusesTheIntegrationLevelOnly(t *testing.T) { f.postgres = "postgres (PostgreSQL) 17.2" m, states := integModule(t, f) _, st := runLevelTool(t, m, states, "integration") - if st.State != delivery.StepRefused || !strings.Contains(st.Reason, "17") || !strings.Contains(st.Reason, "18") { + if st.State != sdkstep.StepRefused || !strings.Contains(st.Reason, "17") || !strings.Contains(st.Reason, "18") { t.Fatalf("the integration step ended %s: %q", st.State, st.Reason) } if strings.Contains(f.lines(), "initdb") || strings.Contains(f.lines(), "-tags") { t.Errorf("the refused level ran something:\n%s", f.lines()) } res, st := runLevelTool(t, m, states, "unit") - if st.State != delivery.StepPassed || !res.Passed || res.Level != "unit" { + if st.State != sdkstep.StepPassed || !res.Passed || res.Level != "unit" { t.Errorf("the unit level: %s %+v", st.State, res) } } @@ -308,7 +308,7 @@ func TestAStoreThatDoesNotStartEndsTheStepFailedAndLeavesNothing(t *testing.T) { return r } _, st := runLevelTool(t, m, states, "integration") - if st.State != delivery.StepFailed || !strings.Contains(st.Reason, "pg_ctl: could not start server") { + if st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, "pg_ctl: could not start server") { t.Errorf("the step ended %s: %q", st.State, st.Reason) } if !strings.Contains(f.lines(), " stop") { diff --git a/modules/mesh-build-go/cmd/mesh-build-go/isolate_test.go b/modules/mesh-build-go/cmd/mesh-build-go/isolate_test.go index a872febb2..4588f7297 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/isolate_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/isolate_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "path/filepath" "slices" "strings" @@ -11,7 +12,6 @@ import ( "testing" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" ) @@ -118,7 +118,7 @@ func TestTheUnitLevelRunsEveryGoTestShutOff(t *testing.T) { m, states, ws, calls := workspaceFor(t, "failing") var seen []shutOff m.Run = throughBubblewrap(t, m.Run, &seen) - if _, st := runUnit(t, m, states, ws); st.State != delivery.StepPassed { + if _, st := runUnit(t, m, states, ws); st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } ran := 0 @@ -174,7 +174,7 @@ func TestABuildRunsShutOffAndOnlyATrunkBuildWritesTheCaches(t *testing.T) { if _, err := run(args); err != nil { t.Fatal(err) } - if st := states.waitEnd(t); st.State != delivery.StepPassed { + if st := states.waitEnd(t); st.State != sdkstep.StepPassed { t.Fatalf("publish %v: the step ended %s: %s", publish, st.State, st.Reason) } if len(seen) != 1 || !strings.HasPrefix(seen[0].command, "go ") || !strings.Contains(seen[0].command, " build ") { @@ -230,7 +230,7 @@ func TestTheIntegrationLevelRunsInOneShutOffProcess(t *testing.T) { t.Fatal(err) } st := states.waitEnd(t) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } var got TestResult diff --git a/modules/mesh-build-go/cmd/mesh-build-go/kit_test.go b/modules/mesh-build-go/cmd/mesh-build-go/kit_test.go index 9dee83e26..c89199a44 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/kit_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/kit_test.go @@ -2,6 +2,7 @@ package main import ( "context" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" "testing" "time" @@ -27,7 +28,7 @@ func TestTheTestStepKeepsTheFailureContract(t *testing.T) { // case: a step a previous process left running is ended at once and said, whatever its age, and a step of this process // is kept. func TestTheStartSweepEndsWhatAPreviousProcessLeft(t *testing.T) { - conformance.LeftRunning(t, func(ctx context.Context, scan sdkstep.Scan, node string, before time.Time, logf func(string, ...any)) { + conformance.LeftRunning(t, func(ctx context.Context, scan buildrun.Scan, node string, before time.Time, logf func(string, ...any)) { (&Module{Node: node}).endLeftRunning(ctx, scan, before, logf) }) } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/level.go b/modules/mesh-build-go/cmd/mesh-build-go/level.go index 88281ee79..b58001efb 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/level.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/level.go @@ -10,6 +10,7 @@ import ( "context" "encoding/json" "fmt" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "os/exec" "path/filepath" @@ -17,7 +18,6 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // levelArg is the first argument that makes this binary a step's shut-off process: the integration level's, and, when @@ -148,7 +148,7 @@ func (m *Module) nodeToolchains() []string { const nodeToolchainMark = ".installed" // Has says whether this node has a need a check ask or a package's tests name (issue 890, ADR 0552; mesh-sdk -// delivery.AskNeeds), read from the node itself at every ask: node-build-node when the Node build module's toolchains +// sdkstep.AskNeeds), read from the node itself at every ask: node-build-node when the Node build module's toolchains // directory, given to the integration level as nodeToolchains gives it, holds a toolchain installed whole (its mark and // its package-lock.json readable by this account), and node, npm and bwrap are installed: what mesh-build-node's // integration tests (realMachine) look for before they run. Any other need it lacks. @@ -157,7 +157,7 @@ func (m *Module) Has(need string) bool { return m.HasNeed(need) } switch need { - case delivery.NeedNodeBuildNode: + case sdkstep.NeedNodeBuildNode: dirs := m.nodeToolchains() if len(dirs) == 0 { return false diff --git a/modules/mesh-build-go/cmd/mesh-build-go/main.go b/modules/mesh-build-go/cmd/mesh-build-go/main.go index 68c886221..a20113d2d 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/main.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/main.go @@ -8,13 +8,14 @@ package main import ( "context" "fmt" + seat "git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildgo" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "os/user" "strings" "time" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // The directories the module's manifest places outside its home (ADR 0466 §1): the workspaces, and the Go module @@ -37,13 +38,13 @@ func main() { m := &Module{ Node: strings.TrimSpace(os.Getenv("MESH_NODE")), Recipe: Current(), - Toolchains: stdio.State(delivery.ToolchainsState).Put, + Toolchains: stdio.State(seat.StateToolchains).Put, Emit: func(t string, b any) error { return stdio.Emit(t, b) }, - Steps: stdio.State(delivery.StepsState).Put, - ReadSteps: readOf(stdio.State(delivery.StepsState)), - Pauses: stdio.State(delivery.PausesState).Put, - ReadPauses: readOf(stdio.State(delivery.PausesState)), - ReadToolchainsState: readOf(stdio.State(delivery.ToolchainsState)), + Steps: stdio.State(seat.StateSteps).Put, + ReadSteps: readOf(stdio.State(seat.StateSteps)), + Pauses: stdio.State(sdkstep.PausesState).Put, + ReadPauses: readOf(stdio.State(sdkstep.PausesState)), + ReadToolchainsState: readOf(stdio.State(seat.StateToolchains)), Ctx: ctx, Say: logf, Work: WorkDir, diff --git a/modules/mesh-build-go/cmd/mesh-build-go/mirror_test.go b/modules/mesh-build-go/cmd/mesh-build-go/mirror_test.go index a316780a6..69595b3b0 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/mirror_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/mirror_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "os/exec" "path/filepath" @@ -11,8 +12,6 @@ import ( "sync" "testing" "time" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) func fetchOnce(t *testing.T, m *Module, states *keptStates, args map[string]any) FetchResult { @@ -21,7 +20,7 @@ func fetchOnce(t *testing.T, m *Module, states *keptStates, args map[string]any) t.Fatal(err) } st := states.waitEnd(t) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } var res FetchResult diff --git a/modules/mesh-build-go/cmd/mesh-build-go/module.go b/modules/mesh-build-go/cmd/mesh-build-go/module.go index 6a4b7265e..a09a976b7 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/module.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/module.go @@ -4,13 +4,13 @@ import ( "context" "encoding/json" "fmt" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" "net/http" "sync" "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" "git.novox.be/novox/mesh-sdk/go/health" ) @@ -129,7 +129,7 @@ func (m *Module) Start(ctx context.Context) { m.Say("the toolchain: %v", err) } m.CleanWorkspaces(time.Now()) - sdkstep.EndStaleRound(m.stepScan(), m.Node, m.Say) // asks past the step bound, on the module's own round (issue 1890) + buildrun.EndStaleRound(m.stepScan(), m.Node, m.Say) // asks past the step bound, on the module's own round (issue 1890) select { case <-ctx.Done(): return @@ -183,8 +183,8 @@ func (m *Module) Long(tool string, run func(ctx context.Context, args map[string if err != nil { return nil, err } - key, _ := delivery.StepKey(m.Node, id) - return map[string]any{"step": id, "key": key, "state": delivery.StepRunning}, nil + key, _ := sdkstep.StepKey(m.Node, id) + return map[string]any{"step": id, "key": key, "state": sdkstep.StepRunning}, nil } } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/module_test.go b/modules/mesh-build-go/cmd/mesh-build-go/module_test.go index a780172fd..162237da0 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/module_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/module_test.go @@ -4,29 +4,30 @@ import ( "context" "encoding/json" "errors" + buildstep "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "strings" "sync" "testing" "time" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/health" ) // keptStates stands in for the toolchains and the steps states. type keptStates struct { mu sync.Mutex - toolchains map[string]delivery.Toolchain - steps map[string][]delivery.Step + toolchains map[string]buildstep.Toolchain + steps map[string][]sdkstep.Step ended chan string } func newStates() *keptStates { - return &keptStates{toolchains: map[string]delivery.Toolchain{}, steps: map[string][]delivery.Step{}, ended: make(chan string, 16)} + return &keptStates{toolchains: map[string]buildstep.Toolchain{}, steps: map[string][]sdkstep.Step{}, ended: make(chan string, 16)} } func (s *keptStates) putToolchain(key string, value any) (uint64, error) { - tc, err := delivery.DecodeToolchain(value.(json.RawMessage)) + tc, err := buildstep.DecodeToolchain(value.(json.RawMessage)) if err != nil { return 0, err } @@ -37,27 +38,27 @@ func (s *keptStates) putToolchain(key string, value any) (uint64, error) { } func (s *keptStates) putStep(key string, value any) (uint64, error) { - st, err := delivery.DecodeStep(value.(json.RawMessage)) + st, err := sdkstep.DecodeStep(value.(json.RawMessage)) if err != nil { return 0, err } s.mu.Lock() s.steps[key] = append(s.steps[key], st) s.mu.Unlock() - if st.State != delivery.StepRunning { + if st.State != sdkstep.StepRunning { s.ended <- key } return 1, nil } -func (s *keptStates) toolchain(key string) (delivery.Toolchain, bool) { +func (s *keptStates) toolchain(key string) (buildstep.Toolchain, bool) { s.mu.Lock() defer s.mu.Unlock() tc, ok := s.toolchains[key] return tc, ok } -func (s *keptStates) waitEnd(t *testing.T) delivery.Step { +func (s *keptStates) waitEnd(t *testing.T) sdkstep.Step { t.Helper() select { case key := <-s.ended: @@ -67,7 +68,7 @@ func (s *keptStates) waitEnd(t *testing.T) delivery.Step { return v[len(v)-1] case <-time.After(30 * time.Second): t.Fatal("the step never ended on its key") - return delivery.Step{} + return sdkstep.Step{} } } @@ -85,7 +86,7 @@ func TestStartWritesTheToolchainAndHealthIsHealthy(t *testing.T) { ctx, stop := context.WithCancel(context.Background()) defer stop() go m.Start(ctx) - var tc delivery.Toolchain + var tc buildstep.Toolchain for deadline := time.Now().Add(30 * time.Second); time.Now().Before(deadline); time.Sleep(5 * time.Millisecond) { if got, ok := states.toolchain("ace.go"); ok { tc = got @@ -127,7 +128,7 @@ func TestAGoThatCannotBeRunRefusesEveryStepAndHealthIsUnhealthy(t *testing.T) { if out.(map[string]any)["step"] == "" { t.Fatalf("%s answered no step id: %v", tool.Name, out) } - if st := states.waitEnd(t); st.State != delivery.StepRefused { + if st := states.waitEnd(t); st.State != sdkstep.StepRefused { t.Errorf("%s: the step ended %s, want refused", tool.Name, st.State) } else { reason = st.Reason diff --git a/modules/mesh-build-go/cmd/mesh-build-go/narrow_integration_test.go b/modules/mesh-build-go/cmd/mesh-build-go/narrow_integration_test.go index e74784787..cdc9491da 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/narrow_integration_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/narrow_integration_test.go @@ -3,12 +3,11 @@ package main import ( + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" "testing" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // ADR 0499 §4 (issue 1758): a fetch asked with the module's directory and its named paths leaves the workspace holding @@ -28,7 +27,7 @@ func TestAFetchWithNamedPathsNarrowsTheWorkspace(t *testing.T) { }) m, states := f.module(t) res, st := fetched(t, m, states, map[string]any{"repository": "novox/narrow", "commit": head, "dir": "lib", "paths": []any{"cmd", "go.mod"}}) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the fetch ended %s: %s", st.State, st.Reason) } tree := filepath.Join(m.Work, res.Workspace, "tree") @@ -46,7 +45,7 @@ func TestAFetchWithNamedPathsNarrowsTheWorkspace(t *testing.T) { t.Errorf("the fetch answered the modules %v, want lib alone", res.Modules) } _, st = fetched(t, m, states, map[string]any{"repository": "novox/narrow", "commit": head, "paths": []any{"cmd"}}) - if st.State != delivery.StepFailed || !strings.Contains(st.Reason, "no module directory") { + if st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, "no module directory") { t.Errorf("paths without a directory: %s %q", st.State, st.Reason) } } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/needtools_test.go b/modules/mesh-build-go/cmd/mesh-build-go/needtools_test.go index afb362560..63b07e738 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/needtools_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/needtools_test.go @@ -1,11 +1,10 @@ package main import ( + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "slices" "strings" "testing" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // Issue 1309: a test that runs a step in bubblewrap is proof only where it runs. Where a build module judges (it hands @@ -32,11 +31,11 @@ func TestAMissingToolSkipsExceptBubblewrapOnABuildNode(t *testing.T) { // The levels a build module judges hand the tests the build node mark, with the siblings they read. func TestEveryLevelHandsTheTestsTheBuildNodeMark(t *testing.T) { m := &Module{Work: t.TempDir()} - if env := m.checkEnv("ws1", nil); !slices.Contains(env, BuildNodeEnv+"=1") || slices.ContainsFunc(env, func(e string) bool { return strings.HasPrefix(e, delivery.NodeNamesEnv) }) { + if env := m.checkEnv("ws1", nil); !slices.Contains(env, BuildNodeEnv+"=1") || slices.ContainsFunc(env, func(e string) bool { return strings.HasPrefix(e, sdkstep.NodeNamesEnv) }) { t.Errorf("env %v lacks %s=1, or names nodes when none were asked", env, BuildNodeEnv) } // And the mesh's node names, when the ask carried them (ADR 0567 §12). - if env := m.checkEnv("ws1", []string{"a", "b"}); !slices.Contains(env, delivery.NodeNamesEnv+"=a,b") { + if env := m.checkEnv("ws1", []string{"a", "b"}); !slices.Contains(env, sdkstep.NodeNamesEnv+"=a,b") { t.Errorf("env %v lacks the node names", env) } } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/node_toolchains_test.go b/modules/mesh-build-go/cmd/mesh-build-go/node_toolchains_test.go index efd415cfa..332a82166 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/node_toolchains_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/node_toolchains_test.go @@ -3,13 +3,13 @@ package main import ( "context" "encoding/json" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "slices" "strconv" "testing" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" ) @@ -36,7 +36,7 @@ func integrationShutOffWith(t *testing.T, toolchains string) shutOff { if _, err := run(map[string]any{"workspace": ws, "level": LevelIntegration}); err != nil { t.Fatal(err) } - if st := states.waitEnd(t); st.State != delivery.StepPassed { + if st := states.waitEnd(t); st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } if len(seen) != 1 { @@ -81,12 +81,12 @@ func TestANodeWithoutNodeToolchainsRunsTheLevelWithNothingMoreBound(t *testing.T } t.Setenv("PATH", bin) m := &Module{NodeToolchains: missing} - if m.Has(delivery.NeedNodeBuildNode) { + if m.Has(sdkstep.NeedNodeBuildNode) { t.Error("a node with no Node toolchain has node-build-node") } installed := t.TempDir() m.NodeToolchains = installed - if m.Has(delivery.NeedNodeBuildNode) { + if m.Has(sdkstep.NeedNodeBuildNode) { t.Error("a node with an empty toolchains directory has node-build-node") } half := filepath.Join(installed, "0.1.0") @@ -96,19 +96,19 @@ func TestANodeWithoutNodeToolchainsRunsTheLevelWithNothingMoreBound(t *testing.T if err := os.WriteFile(filepath.Join(half, "package-lock.json"), []byte("{}"), 0o644); err != nil { t.Fatal(err) } - if m.Has(delivery.NeedNodeBuildNode) { + if m.Has(sdkstep.NeedNodeBuildNode) { t.Error("a toolchain without its installed mark counts") } if err := os.WriteFile(filepath.Join(half, nodeToolchainMark), nil, 0o644); err != nil { t.Fatal(err) } - if !m.Has(delivery.NeedNodeBuildNode) || m.Has("gpu") { - t.Errorf("with a toolchain installed: node-build-node %v, gpu %v; want true, false", m.Has(delivery.NeedNodeBuildNode), m.Has("gpu")) + if !m.Has(sdkstep.NeedNodeBuildNode) || m.Has("gpu") { + t.Errorf("with a toolchain installed: node-build-node %v, gpu %v; want true, false", m.Has(sdkstep.NeedNodeBuildNode), m.Has("gpu")) } if err := os.Remove(filepath.Join(bin, "bwrap")); err != nil { t.Fatal(err) } - if m.Has(delivery.NeedNodeBuildNode) { + if m.Has(sdkstep.NeedNodeBuildNode) { t.Error("a node with no bubblewrap installed has node-build-node") } } @@ -120,7 +120,7 @@ func TestTheUnitLevelIsNotGivenTheNodeToolchains(t *testing.T) { m.NodeToolchains = dir var seen []shutOff m.Run = throughBubblewrap(t, m.Run, &seen) - if _, st := runUnit(t, m, states, ws); st.State != delivery.StepPassed { + if _, st := runUnit(t, m, states, ws); st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } for _, s := range seen { diff --git a/modules/mesh-build-go/cmd/mesh-build-go/packages_shape_test.go b/modules/mesh-build-go/cmd/mesh-build-go/packages_shape_test.go index 11e3b7001..0490b6568 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/packages_shape_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/packages_shape_test.go @@ -9,7 +9,6 @@ import ( "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // 1925/AC1: packagesArg takes the list as the bus's JSON shape ([]any) and as the typed list an ask hands in process @@ -64,8 +63,8 @@ func TestACheckAskReachesTheTestStepPastItsPackages(t *testing.T) { } } } - a := delivery.StepAsk{ID: sdkstep.NewID(), Kind: delivery.AskCheck, Language: delivery.AskGo, Asker: "mesh-delivery-checker", - At: time.Now(), Check: &delivery.CheckJob{Fetch: map[string]any{"repository": "novox/x", "commit": askCommit}, Levels: []string{delivery.LevelUnit}}} + a := sdkstep.StepAsk{ID: sdkstep.NewID(), Kind: sdkstep.AskCheck, Language: sdkstep.AskGo, Asker: "mesh-delivery-checker", + At: time.Now(), Check: &sdkstep.CheckJob{Fetch: sdkstep.Fetch{Repository: "novox/x", Commit: askCommit}, Levels: []string{sdkstep.LevelUnit}}} out, err := buildstep.RunAsk(context.Background(), m.askSteps(steps), a) got := "" if err != nil { diff --git a/modules/mesh-build-go/cmd/mesh-build-go/pins_integration_test.go b/modules/mesh-build-go/cmd/mesh-build-go/pins_integration_test.go index 9060b9506..c3aeebd2c 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/pins_integration_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/pins_integration_test.go @@ -8,12 +8,11 @@ package main import ( "context" "fmt" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "os/exec" "path/filepath" "testing" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // 1148/AC2 as issue 1585 S15 has it (novox/hq ADR 0573 §4): given a forge with a mesh-sdk-like pull request whose branch @@ -46,7 +45,7 @@ func TestRealFetchAndBuildOfAMemberAskedAPullHeadItsGoModDoesNotName(t *testing. res, st := fetched(t, m, states, map[string]any{"repository": "novox/member", "commit": memberHead, "packages": map[string]any{"git.novox.be/novox/dep/go": head}}) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the fetch ended %s: %s", st.State, st.Reason) } if len(res.Packages) != 1 || res.Packages[0].Built != head || res.Packages[0].Named != "v0.0.0-20261021120000-"+fork[:12] { diff --git a/modules/mesh-build-go/cmd/mesh-build-go/pins_test.go b/modules/mesh-build-go/cmd/mesh-build-go/pins_test.go index 48829ce5a..710668068 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/pins_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/pins_test.go @@ -3,6 +3,7 @@ package main import ( "context" "encoding/json" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "os/exec" "path/filepath" @@ -10,7 +11,6 @@ import ( "sync" "testing" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" ) @@ -71,14 +71,14 @@ func newPinHarness(t *testing.T, gomod string, vendor bool, pulls string) (*pinH return h, states } -func (h *pinHarness) fetch(states *keptStates) (FetchResult, delivery.Step) { +func (h *pinHarness) fetch(states *keptStates) (FetchResult, sdkstep.Step) { h.t.Helper() if _, err := fetchTool(h.t, h.m)(fetchArgs); err != nil { h.t.Fatal(err) } st := states.waitEnd(h.t) var res FetchResult - if st.State == delivery.StepPassed { + if st.State == sdkstep.StepPassed { json.Unmarshal(st.Result, &res) } return res, st @@ -101,7 +101,7 @@ const pullList = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\trefs/pull/6/head\n" func TestAPinOnAPullHeadIsPlacedBesideAndHandedToGoByAModfile(t *testing.T) { h, states := newPinHarness(t, pinnedGoMod, false, pullList) res, st := h.fetch(states) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } placed := filepath.Join(h.m.Work, res.Workspace, "pinned", "mesh-sdk@"+commitSHA, "beside", "mesh-sdk") @@ -144,7 +144,7 @@ func TestAPinGoCanDownloadIsLeftAsToday(t *testing.T) { h, states := newPinHarness(t, pinnedGoMod, false, pullList) h.onTrunk = true res, st := h.fetch(states) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } if h.ran("ls-remote") || h.ran("pinned") { @@ -165,7 +165,7 @@ func TestAPinGoCanDownloadIsLeftAsToday(t *testing.T) { func TestAPinOnNoRefFailsNamingTheModuleAndTheCommit(t *testing.T) { h, states := newPinHarness(t, pinnedGoMod, false, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\trefs/pull/6/head\n") _, st := h.fetch(states) - if st.State != delivery.StepFailed { + if st.State != sdkstep.StepFailed { t.Fatalf("the step ended %s, want failed", st.State) } if !strings.Contains(st.Reason, "no pull request head") || !strings.Contains(st.Reason, "unknown revision") || @@ -181,7 +181,7 @@ func TestAPinOnNoRefFailsNamingTheModuleAndTheCommit(t *testing.T) { func TestAVendoringDirectoryResolvesNothing(t *testing.T) { h, states := newPinHarness(t, pinnedGoMod, true, pullList) _, st := h.fetch(states) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } if h.ran("go -C") || h.ran("ls-remote") || h.ran("pinned") { @@ -195,7 +195,7 @@ func TestTwoDirectoriesPinningOneHeadShareOnePlacement(t *testing.T) { h, states := newPinHarness(t, pinnedGoMod, false, pullList) h.f.gomods = "go.mod\nsub/go.mod\n" res, st := h.fetch(states) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } checkouts := 0 @@ -240,7 +240,7 @@ func TestTwoCommitsOfOneRepositoryGetTwoPlacements(t *testing.T) { return base(ctx, env, name, args...) } _, st := h.fetch(states) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } for _, c := range []string{commitSHA, other} { diff --git a/modules/mesh-build-go/cmd/mesh-build-go/preview_integration_test.go b/modules/mesh-build-go/cmd/mesh-build-go/preview_integration_test.go index b7acb409c..c24e7210e 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/preview_integration_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/preview_integration_test.go @@ -7,6 +7,7 @@ package main import ( "encoding/json" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "os/exec" "path/filepath" @@ -15,7 +16,6 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" ) func git(t *testing.T, dir string, args ...string) string { @@ -86,7 +86,7 @@ func (f *forge) module(t *testing.T) (*Module, *keptStates) { } // waitLong is waitEnd for a step that runs the real go, whose first build in a cold cache takes longer than 3 s. -func waitLong(t *testing.T, s *keptStates) delivery.Step { +func waitLong(t *testing.T, s *keptStates) sdkstep.Step { t.Helper() select { case key := <-s.ended: @@ -96,18 +96,18 @@ func waitLong(t *testing.T, s *keptStates) delivery.Step { return v[len(v)-1] case <-time.After(2 * time.Minute): t.Fatal("the step never ended on its key") - return delivery.Step{} + return sdkstep.Step{} } } -func fetched(t *testing.T, m *Module, states *keptStates, args map[string]any) (FetchResult, delivery.Step) { +func fetched(t *testing.T, m *Module, states *keptStates, args map[string]any) (FetchResult, sdkstep.Step) { t.Helper() if _, err := fetchTool(t, m)(args); err != nil { t.Fatal(err) } st := states.waitEnd(t) var res FetchResult - if st.State == delivery.StepPassed { + if st.State == sdkstep.StepPassed { if err := json.Unmarshal(st.Result, &res); err != nil { t.Fatal(err) } @@ -136,7 +136,7 @@ func TestRealFetchMergesConflictsAndPlainlyFetches(t *testing.T) { m, states := f.module(t) res, st := fetched(t, m, states, map[string]any{"repository": "o/r", "commit": clean, "ref": "refs/pull/1/head", "base": trunk}) - if st.State != delivery.StepPassed || res.Merge == "" || res.Base != trunk || res.Commit != clean || len(res.Conflicts) != 0 { + if st.State != sdkstep.StepPassed || res.Merge == "" || res.Base != trunk || res.Commit != clean || len(res.Conflicts) != 0 { t.Fatalf("clean: %s %s", st.State, st.Result) } if strings.Join(res.Changed, ",") != "modules/m/m.txt" { @@ -154,7 +154,7 @@ func TestRealFetchMergesConflictsAndPlainlyFetches(t *testing.T) { } res, st = fetched(t, m, states, map[string]any{"repository": "o/r", "commit": clash, "ref": "refs/pull/2/head", "base": trunk}) - if st.State != delivery.StepPassed || res.Merge != "" || strings.Join(res.Conflicts, ",") != "a.txt" { + if st.State != sdkstep.StepPassed || res.Merge != "" || strings.Join(res.Conflicts, ",") != "a.txt" { t.Fatalf("conflict: %s %s", st.State, st.Result) } if got := git(t, filepath.Join(m.Work, res.Workspace, "tree"), "rev-parse", "HEAD"); got != trunk { @@ -162,7 +162,7 @@ func TestRealFetchMergesConflictsAndPlainlyFetches(t *testing.T) { } res, st = fetched(t, m, states, map[string]any{"repository": "o/r", "commit": clean, "ref": "refs/pull/1/head"}) - if st.State != delivery.StepPassed || res.Merge != "" || res.Base != "" || res.Trees != nil || len(res.Modules) != 1 { + if st.State != sdkstep.StepPassed || res.Merge != "" || res.Base != "" || res.Trees != nil || len(res.Modules) != 1 { t.Errorf("no base: %s %s", st.State, st.Result) } } @@ -192,13 +192,13 @@ func TestRealTestsReadTheSiblingBesideTheTree(t *testing.T) { var res TestResult st := waitLong(t, states) json.Unmarshal(st.Result, &res) - if st.State != delivery.StepPassed || res.Passed || len(res.Failed) != 1 || !strings.Contains(res.Failed[0].Output, "MESH_CHECK_BESIDE is not set") { + if st.State != sdkstep.StepPassed || res.Passed || len(res.Failed) != 1 || !strings.Contains(res.Failed[0].Output, "MESH_CHECK_BESIDE is not set") { t.Fatalf("without the sibling: %s %s", st.State, st.Result) } with, st2 := fetched(t, m, states, map[string]any{"repository": "o/r", "commit": head, "beside": []any{map[string]any{"repository": "o/sibling", "commit": sibling}}}) - if st2.State != delivery.StepPassed || len(with.Beside) != 1 { + if st2.State != sdkstep.StepPassed || len(with.Beside) != 1 { t.Fatalf("with the sibling: %s %s", st2.State, st2.Result) } m.testToolRun(t, with.Workspace) @@ -223,7 +223,7 @@ func TestRealTestsReadTheSiblingBesideTheTree(t *testing.T) { git(t, work, "push", "-q", "-f", filepath.Join(f.root, "forge", "o/linked.git"), "HEAD:refs/heads/main") _, st3 := fetched(t, m, states, map[string]any{"repository": "o/r", "commit": head, "beside": []any{map[string]any{"repository": "o/linked", "commit": bad}}}) - if st3.State != delivery.StepFailed || !strings.Contains(st3.Reason, "etc-link") { + if st3.State != sdkstep.StepFailed || !strings.Contains(st3.Reason, "etc-link") { t.Errorf("a sibling with a symlink: %s %s", st3.State, st3.Reason) } } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/preview_test.go b/modules/mesh-build-go/cmd/mesh-build-go/preview_test.go index 6df51b810..27f0f49b5 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/preview_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/preview_test.go @@ -5,12 +5,12 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" "testing" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" ) @@ -69,7 +69,7 @@ func TestFetchWithABaseMergesAndAnswersThePreview(t *testing.T) { t.Fatal(err) } st := states.waitEnd(t) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } var res FetchResult @@ -102,7 +102,7 @@ func TestFetchWithAConflictEndsPassedAndNamesTheFiles(t *testing.T) { t.Fatal(err) } st := states.waitEnd(t) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("a conflict ended the step %s: %s", st.State, st.Reason) } var res FetchResult @@ -137,7 +137,7 @@ func TestABaseThatIsNotACommitIsRefusedBeforeAnythingRuns(t *testing.T) { f := &fakeStep{} m, states := fetchModule(t, f) fetchTool(t, m)(map[string]any{"repository": "novox/mesh-sdk", "commit": commitSHA, "base": "main"}) - if st := states.waitEnd(t); st.State != delivery.StepFailed || len(f.lines()) != 0 { + if st := states.waitEnd(t); st.State != sdkstep.StepFailed || len(f.lines()) != 0 { t.Errorf("the step ended %s after %d commands", st.State, len(f.lines())) } } @@ -156,7 +156,7 @@ func TestSiblingsArePlacedBesideAndTheUnitLevelIsGivenTheirDirectory(t *testing. st := states.waitEnd(t) var res FetchResult json.Unmarshal(st.Result, &res) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } if len(res.Beside) != 2 || res.Beside[0].Dir != "mesh-catalog" || res.Beside[1].Dir != "mesh-host" { @@ -233,7 +233,7 @@ func TestSiblingsThatAreNotRepositoriesOrCommitsAreRefused(t *testing.T) { f := &fakeStep{} m, states := fetchModule(t, f) fetchTool(t, m)(map[string]any{"repository": "novox/mesh-sdk", "commit": commitSHA, "beside": beside}) - if st := states.waitEnd(t); st.State != delivery.StepFailed || len(f.lines()) != 0 { + if st := states.waitEnd(t); st.State != sdkstep.StepFailed || len(f.lines()) != 0 { t.Errorf("%s: the step ended %s after %d commands", name, st.State, len(f.lines())) } } @@ -285,7 +285,7 @@ func TestTheIntegrationLevelIsGivenTheBesideDirectoryOnlyWhenSiblingsWerePlaced( t.Fatal(err) } } - if _, st := runLevelTool(t, m, states, "integration"); st.State != delivery.StepPassed { + if _, st := runLevelTool(t, m, states, "integration"); st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } tested := 0 diff --git a/modules/mesh-build-go/cmd/mesh-build-go/publish_test.go b/modules/mesh-build-go/cmd/mesh-build-go/publish_test.go index 65d20e0fa..7a59a594f 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/publish_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/publish_test.go @@ -8,6 +8,8 @@ import ( "encoding/hex" "encoding/json" "errors" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" @@ -15,7 +17,6 @@ import ( "testing" registry "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // pushed are the blobs the fake artifact store took, by digest, for the tests that read an archive back. @@ -105,7 +106,7 @@ func TestADoneBuildAnswersTheReferenceOfTheArchiveItPushed(t *testing.T) { m, states, _ := buildModule(t, manifestWith(goBundle), "the program") store := withStore(t, m) res, st := runBuild(t, m, states, "tools") - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } if want := "oci-artifact-registry/demo/tools@" + res.Digest; res.Reference != want { @@ -117,7 +118,7 @@ func TestADoneBuildAnswersTheReferenceOfTheArchiveItPushed(t *testing.T) { a, states2, _ := archiveModule(t, "") withStore(t, a) arch, st := runBuild(t, a, states2, "files") - if st.State != delivery.StepPassed || arch.Reference != "oci-artifact-registry/demo/files@"+arch.Digest { + if st.State != sdkstep.StepPassed || arch.Reference != "oci-artifact-registry/demo/files@"+arch.Digest { t.Errorf("the archive artifact: %s %q, reference %q", st.State, st.Reason, arch.Reference) } } @@ -128,13 +129,13 @@ func TestARefusedPushFailsTheStepNotStored(t *testing.T) { m, states, _ := buildModule(t, manifestWith(goBundle), "the program") store := withStore(t, m) store.fail = errors.New("refused: the forge did not take it: disk full") - if _, st := runBuild(t, m, states, "tools"); st.State != delivery.StepFailed || !strings.HasPrefix(st.Reason, delivery.NotStored+"tools: ") || !strings.Contains(st.Reason, "disk full") { + if _, st := runBuild(t, m, states, "tools"); st.State != sdkstep.StepFailed || !strings.HasPrefix(st.Reason, builds.NotStored+"tools: ") || !strings.Contains(st.Reason, "disk full") { t.Errorf("the step ended %s: %q", st.State, st.Reason) } m.Call = func(string, any) (json.RawMessage, error) { return nil, errors.New("nats: no responders available for request") } - if _, st := runBuild(t, m, states, "tools"); st.State != delivery.StepFailed || !strings.HasPrefix(st.Reason, delivery.NotStored+"tools: ") || + if _, st := runBuild(t, m, states, "tools"); st.State != sdkstep.StepFailed || !strings.HasPrefix(st.Reason, builds.NotStored+"tools: ") || !strings.Contains(st.Reason, "oci-artifact-registry") { t.Errorf("no holder: the step ended %s: %q", st.State, st.Reason) } @@ -178,7 +179,7 @@ func TestAGoPackageIsBuiltAsAModuleZipAndPublishedUnderItsModulePath(t *testing. t.Fatal(err) } } - run := func(args map[string]any) (BuildResult, delivery.Step) { + run := func(args map[string]any) (BuildResult, sdkstep.Step) { t.Helper() for _, tool := range m.Tools(m.StepTools()) { if tool.Name == "build_go_build" { @@ -189,7 +190,7 @@ func TestAGoPackageIsBuiltAsAModuleZipAndPublishedUnderItsModulePath(t *testing. } st := states.waitEnd(t) var res BuildResult - if st.State == delivery.StepPassed { + if st.State == sdkstep.StepPassed { _ = json.Unmarshal(st.Result, &res) } return res, st @@ -197,12 +198,12 @@ func TestAGoPackageIsBuiltAsAModuleZipAndPublishedUnderItsModulePath(t *testing. store := withStore(t, m) args := map[string]any{"workspace": "ws1", "module": "modules/demo", "artifact": "go"} cand, st := run(args) - if st.State != delivery.StepPassed || !strings.HasPrefix(cand.Digest, "sha256:") || cand.Reference != "" || len(store.asked) != 0 { + if st.State != sdkstep.StepPassed || !strings.HasPrefix(cand.Digest, "sha256:") || cand.Reference != "" || len(store.asked) != 0 { t.Fatalf("a candidate's Go package: %s %q, %+v, asked %v", st.State, st.Reason, cand, store.asked) } args["version"], args["seat"] = "v0.1.15", GoPackageSeat res, st := run(args) - if st.State != delivery.StepPassed || res.Reference != "git.example/demo/go@v0.1.15" { + if st.State != sdkstep.StepPassed || res.Reference != "git.example/demo/go@v0.1.15" { t.Fatalf("a trunk Go package: %s %q, %+v", st.State, st.Reason, res) } if len(store.published) != 1 { @@ -226,7 +227,7 @@ func TestAGoPackageIsBuiltAsAModuleZipAndPublishedUnderItsModulePath(t *testing. if err := os.Remove(filepath.Join(src, "go.mod")); err != nil { t.Fatal(err) } - if _, st := run(args); st.State != delivery.StepFailed || !strings.Contains(st.Reason, "go.mod") { + if _, st := run(args); st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, "go.mod") { t.Errorf("no go.mod: %s %q", st.State, st.Reason) } } @@ -268,7 +269,7 @@ func TestEachGoPackageOfAModuleInAFolderIsPublishedUnderItsOwnModulePath(t *test } st := states.waitEnd(t) var res BuildResult - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("%s: %s %q", c.artifact, st.State, st.Reason) } _ = json.Unmarshal(st.Result, &res) @@ -298,7 +299,7 @@ func TestTheNumberedEventPublishesAHeldDigestUnderItsVersion(t *testing.T) { digest := "sha256:" + strings.Repeat("ab", 32) other := "sha256:" + strings.Repeat("cd", 32) numbered := func(kind, seat, digest string) []byte { - raw, err := delivery.EncodeVersionNumbered(delivery.VersionNumbered{Name: "mod/tools", Kind: kind, Version: "0.1.4", + raw, err := builds.EncodeVersionNumbered(builds.VersionNumbered{Name: "mod/tools", Kind: kind, Version: "0.1.4", Module: "mod", Fingerprint: "fp", Commit: "c0", Digest: digest, Seat: seat}) if err != nil { t.Fatal(err) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/read.go b/modules/mesh-build-go/cmd/mesh-build-go/read.go index c0f9b979c..22b6c2d9d 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/read.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/read.go @@ -7,6 +7,8 @@ package main import ( "encoding/json" "fmt" + buildstep "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "log" "sort" "strconv" @@ -15,7 +17,6 @@ import ( "time" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // The read tools, named as the module is: build_go_ and the verb. @@ -98,26 +99,26 @@ func (m *Module) stepKey(id string) (string, error) { } id = rest } - return delivery.StepKey(m.Node, id) + return sdkstep.StepKey(m.Node, id) } // ReadStep is the stored value of this node's step id (state, reason, result). -func (m *Module) ReadStep(id string) (delivery.Step, error) { +func (m *Module) ReadStep(id string) (sdkstep.Step, error) { key, err := m.stepKey(id) if err != nil { - return delivery.Step{}, err + return sdkstep.Step{}, err } if m.ReadSteps.Get == nil { - return delivery.Step{}, fmt.Errorf("the steps state cannot be read here") + return sdkstep.Step{}, fmt.Errorf("the steps state cannot be read here") } raw, err := m.ReadSteps.Get(key) if err != nil { - return delivery.Step{}, err + return sdkstep.Step{}, err } if len(raw) == 0 { - return delivery.Step{}, fmt.Errorf("no step %s in the steps state", key) + return sdkstep.Step{}, fmt.Errorf("no step %s in the steps state", key) } - return delivery.DecodeStep(raw) + return sdkstep.DecodeStep(raw) } // StepLine is a step without its result: the list answers these. @@ -150,7 +151,7 @@ func (m *Module) RecentSteps(limit int) (lines []StepLine, cut bool, err error) own := keys[:0:0] for _, k := range keys { if strings.HasPrefix(k, m.Node+".") { - if node, _, err := delivery.ParseStepKey(k); err == nil && node == m.Node { + if node, _, err := sdkstep.ParseStepKey(k); err == nil && node == m.Node { own = append(own, k) } } @@ -164,12 +165,12 @@ func (m *Module) RecentSteps(limit int) (lines []StepLine, cut bool, err error) if err != nil { return nil, cut, err } - var steps []delivery.Step + var steps []sdkstep.Step for _, raw := range raws { if len(raw) == 0 { continue } - s, err := delivery.DecodeStep(raw) + s, err := sdkstep.DecodeStep(raw) if err != nil { continue // a value this module cannot read is not one of its own steps } @@ -191,7 +192,7 @@ func (m *Module) RecentSteps(limit int) (lines []StepLine, cut bool, err error) } // ReadToolchains is every key of the toolchains state (.) with its stored value. -func (m *Module) ReadToolchains() (map[string]delivery.Toolchain, error) { +func (m *Module) ReadToolchains() (map[string]buildstep.Toolchain, error) { if m.ReadToolchainsState.Keys == nil || m.ReadToolchainsState.Get == nil { return nil, fmt.Errorf("the toolchains state cannot be read here") } @@ -209,12 +210,12 @@ func (m *Module) ReadToolchains() (map[string]delivery.Toolchain, error) { if err != nil { return nil, err } - out := map[string]delivery.Toolchain{} + out := map[string]buildstep.Toolchain{} for i, raw := range raws { if len(raw) == 0 { continue } - t, err := delivery.DecodeToolchain(raw) + t, err := buildstep.DecodeToolchain(raw) if err != nil { return nil, fmt.Errorf("%s: %w", keys[i], err) } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/read_test.go b/modules/mesh-build-go/cmd/mesh-build-go/read_test.go index 05a85019b..21edf59c4 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/read_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/read_test.go @@ -4,13 +4,13 @@ import ( "context" "encoding/json" "fmt" + buildstep "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "slices" "strings" "sync/atomic" "testing" "time" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // fakeState is a state as stored: key to raw value. @@ -29,13 +29,13 @@ func (f fakeState) read() StateRead { } } -func putStep(t *testing.T, f fakeState, s delivery.Step) { +func putStep(t *testing.T, f fakeState, s sdkstep.Step) { t.Helper() - b, err := delivery.EncodeStep(s) + b, err := sdkstep.EncodeStep(s) if err != nil { t.Fatal(err) } - key, _ := delivery.StepKey(s.Node, s.ID) + key, _ := sdkstep.StepKey(s.Node, s.ID) f[key] = b } @@ -60,22 +60,22 @@ func tool(t *testing.T, m *Module, name string) func(map[string]any) (any, error func TestStepToolAnswersTheStoredStep(t *testing.T) { steps := fakeState{} t0 := time.Date(2026, 10, 21, 9, 0, 0, 0, time.UTC) - putStep(t, steps, delivery.Step{ID: "abc1", Tool: "build_go_fetch", Node: "ace", State: delivery.StepPassed, Started: t0, Ended: t0.Add(time.Second), + putStep(t, steps, sdkstep.Step{ID: "abc1", Tool: "build_go_fetch", Node: "ace", State: sdkstep.StepPassed, Started: t0, Ended: t0.Add(time.Second), Result: json.RawMessage(`{"workspace":"w42"}`)}) - putStep(t, steps, delivery.Step{ID: "abc2", Tool: "build_go_test", Node: "ace", State: delivery.StepRefused, Started: t0, Reason: "go cannot be run"}) + putStep(t, steps, sdkstep.Step{ID: "abc2", Tool: "build_go_test", Node: "ace", State: sdkstep.StepRefused, Started: t0, Reason: "go cannot be run"}) m := readModule(steps, fakeState{}) for _, id := range []string{"abc1", "ace.abc1"} { out, err := tool(t, m, StepReadTool)(map[string]any{"id": id}) if err != nil { t.Fatal(err) } - st := out.(delivery.Step) - if st.State != delivery.StepPassed || string(st.Result) != `{"workspace":"w42"}` || st.Tool != "build_go_fetch" { + st := out.(sdkstep.Step) + if st.State != sdkstep.StepPassed || string(st.Result) != `{"workspace":"w42"}` || st.Tool != "build_go_fetch" { t.Errorf("id %s: step = %+v", id, st) } } out, _ := tool(t, m, StepReadTool)(map[string]any{"id": "abc2"}) - if st := out.(delivery.Step); st.State != delivery.StepRefused || st.Reason != "go cannot be run" { + if st := out.(sdkstep.Step); st.State != sdkstep.StepRefused || st.Reason != "go cannot be run" { t.Errorf("refused step = %+v", st) } } @@ -94,10 +94,10 @@ func TestStepToolRefusesAnUnknownOrForeignOrBadID(t *testing.T) { func TestStepsToolListsRecentStepsOfThisNode(t *testing.T) { steps := fakeState{} t0 := time.Date(2026, 10, 21, 9, 0, 0, 0, time.UTC) - putStep(t, steps, delivery.Step{ID: "a", Tool: "build_go_fetch", Node: "ace", State: delivery.StepPassed, Started: t0, Ended: t0, Result: json.RawMessage(`1`)}) - putStep(t, steps, delivery.Step{ID: "b", Tool: "build_go_test", Node: "ace", State: delivery.StepRunning, Started: t0.Add(time.Minute)}) - putStep(t, steps, delivery.Step{ID: "c", Tool: "build_go_build", Node: "ace", State: delivery.StepFailed, Started: t0.Add(2 * time.Minute), Reason: "boom", What: "check ask, novox/x@abc"}) - putStep(t, steps, delivery.Step{ID: "d", Tool: "build_go_build", Node: "g14", State: delivery.StepPassed, Started: t0.Add(time.Hour)}) + putStep(t, steps, sdkstep.Step{ID: "a", Tool: "build_go_fetch", Node: "ace", State: sdkstep.StepPassed, Started: t0, Ended: t0, Result: json.RawMessage(`1`)}) + putStep(t, steps, sdkstep.Step{ID: "b", Tool: "build_go_test", Node: "ace", State: sdkstep.StepRunning, Started: t0.Add(time.Minute)}) + putStep(t, steps, sdkstep.Step{ID: "c", Tool: "build_go_build", Node: "ace", State: sdkstep.StepFailed, Started: t0.Add(2 * time.Minute), Reason: "boom", What: "check ask, novox/x@abc"}) + putStep(t, steps, sdkstep.Step{ID: "d", Tool: "build_go_build", Node: "g14", State: sdkstep.StepPassed, Started: t0.Add(time.Hour)}) m := readModule(steps, fakeState{}) out, err := tool(t, m, StepsReadTool)(map[string]any{}) if err != nil { @@ -111,7 +111,7 @@ func TestStepsToolListsRecentStepsOfThisNode(t *testing.T) { if !slices.Equal(ids, []string{"c", "b", "a"}) { t.Errorf("ids = %v, want c b a", ids) } - if lines[0].Reason != "boom" || lines[0].What != "check ask, novox/x@abc" || lines[0].State != delivery.StepFailed { + if lines[0].Reason != "boom" || lines[0].What != "check ask, novox/x@abc" || lines[0].State != sdkstep.StepFailed { t.Errorf("first = %+v", lines[0]) } out, _ = tool(t, m, StepsReadTool)(map[string]any{"limit": float64(1)}) @@ -123,7 +123,7 @@ func TestStepsToolListsRecentStepsOfThisNode(t *testing.T) { // 1562 (1483/AC5): build_go_toolchains answers each toolchains key as stored. func TestToolchainsToolAnswersTheStoredKeys(t *testing.T) { tcs := fakeState{} - b, err := delivery.EncodeToolchain(delivery.Toolchain{Language: "go", Version: "go1.27.1", Recipe: "1", At: time.Date(2026, 10, 21, 9, 0, 0, 0, time.UTC)}) + b, err := buildstep.EncodeToolchain(buildstep.Toolchain{Language: "go", Version: "go1.27.1", Recipe: "1", At: time.Date(2026, 10, 21, 9, 0, 0, 0, time.UTC)}) if err != nil { t.Fatal(err) } @@ -133,7 +133,7 @@ func TestToolchainsToolAnswersTheStoredKeys(t *testing.T) { if err != nil { t.Fatal(err) } - got := out.(map[string]any)["toolchains"].(map[string]delivery.Toolchain) + got := out.(map[string]any)["toolchains"].(map[string]buildstep.Toolchain) if got["ace.go"].Version != "go1.27.1" || got["ace.go"].Recipe != "1" { t.Errorf("toolchains = %+v", got) } @@ -166,7 +166,7 @@ func TestRecentStepsReadsOnlyTheNodesKeysInParallelAndBounded(t *testing.T) { stored := map[string][]byte{} for _, n := range []string{"ace", "g14", "novox", "shanks"} { for i := 0; i < row.perNode; i++ { - b, _ := delivery.EncodeStep(delivery.Step{ID: fmt.Sprintf("s%04d", i), Tool: "t", Node: n, State: delivery.StepPassed, Started: t0.Add(time.Duration(i) * time.Second)}) + b, _ := sdkstep.EncodeStep(sdkstep.Step{ID: fmt.Sprintf("s%04d", i), Tool: "t", Node: n, State: sdkstep.StepPassed, Started: t0.Add(time.Duration(i) * time.Second)}) stored[n+".s"+fmt.Sprintf("%04d", i)] = b } } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/room_test.go b/modules/mesh-build-go/cmd/mesh-build-go/room_test.go index 40c9853da..239641493 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/room_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/room_test.go @@ -2,6 +2,7 @@ package main import ( "context" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" @@ -9,7 +10,6 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" "git.novox.be/novox/mesh-sdk/go/health" ) @@ -44,7 +44,7 @@ func TestUnderTheFloorEveryStepIsRefusedAndTheModuleIsUnhealthy(t *testing.T) { if _, err := tool.Run(map[string]any{}); err != nil { t.Fatal(err) } - if st := states.waitEnd(t); st.State != delivery.StepRefused || !strings.HasPrefix(st.Reason, underTheFloor) { + if st := states.waitEnd(t); st.State != sdkstep.StepRefused || !strings.HasPrefix(st.Reason, underTheFloor) { t.Errorf("the long step ended %s: %q, want refused: %q", st.State, st.Reason, underTheFloor) } case "short_probe": @@ -95,7 +95,7 @@ func TestAFailedFetchLeavesNoWorkspace(t *testing.T) { if _, err := fetchTool(t, m)(fetchArgs); err != nil { t.Fatal(err) } - if st := states.waitEnd(t); st.State != delivery.StepFailed { + if st := states.waitEnd(t); st.State != sdkstep.StepFailed { t.Fatalf("the step ended %s, want failed", st.State) } if entries, _ := os.ReadDir(m.Work); len(entries) != 0 { diff --git a/modules/mesh-build-go/cmd/mesh-build-go/selected_dirs_test.go b/modules/mesh-build-go/cmd/mesh-build-go/selected_dirs_test.go index 65d3a6aa2..5e1c54b0d 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/selected_dirs_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/selected_dirs_test.go @@ -3,14 +3,13 @@ package main import ( "encoding/json" "fmt" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" "sync" "testing" "time" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // threeModules gives the workspace three go.mod directories, a, b and c, whose modules are fixture/a, fixture/b and @@ -31,7 +30,7 @@ func threeModules(t *testing.T, f *integFake) (*Module, *keptStates) { return m, states } -func runIntegrationOf(t *testing.T, m *Module, states *keptStates, packages ...any) (TestResult, delivery.Step) { +func runIntegrationOf(t *testing.T, m *Module, states *keptStates, packages ...any) (TestResult, sdkstep.Step) { t.Helper() for _, tool := range m.Tools(m.StepTools()) { if tool.Name != "build_go_test" { @@ -47,7 +46,7 @@ func runIntegrationOf(t *testing.T, m *Module, states *keptStates, packages ...a } st := states.waitEnd(t) var res TestResult - if st.State == delivery.StepPassed { + if st.State == sdkstep.StepPassed { if err := json.Unmarshal(st.Result, &res); err != nil { t.Fatal(err) } @@ -60,7 +59,7 @@ func runIntegrationOf(t *testing.T, m *Module, states *keptStates, packages ...a func TestOnlyTheSelectedDirectoryCompilesAndRuns(t *testing.T) { f := newIntegFake(t, "slow") m, states := threeModules(t, f) - if _, st := runIntegrationOf(t, m, states, "fixture/b/x"); st.State != delivery.StepPassed { + if _, st := runIntegrationOf(t, m, states, "fixture/b/x"); st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } tree := filepath.Join(m.Work, "ws1", "tree") @@ -131,7 +130,7 @@ func TestSelectedDirectoriesRunAtOnceAndAnswerInDirectoryOrder(t *testing.T) { m, states := threeModules(t, f) m.Parallel = 3 res, st := runIntegrationOf(t, m, states, "fixture/c/x", "fixture/a/x") - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } if most != 2 { diff --git a/modules/mesh-build-go/cmd/mesh-build-go/store_integration_test.go b/modules/mesh-build-go/cmd/mesh-build-go/store_integration_test.go index c26f4012b..67b093a16 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/store_integration_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/store_integration_test.go @@ -9,6 +9,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "io" "net/http" "net/http/httptest" @@ -25,7 +26,6 @@ import ( registry "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // realStore starts the artifact store's own program (the distribution registry, modules/distribution) inside this @@ -96,7 +96,7 @@ func uploadBlob(base, name, digest string, body []byte) error { // resolve reads a done artifact's reference from the store as a node-engine does (catalogue.Routed): the seat's form // oci-artifact-registry//@ is /v2///blobs/ (ADR 0605 §9). -func resolve(t *testing.T, addr string, a delivery.BuiltArtifact) []byte { +func resolve(t *testing.T, addr string, a builds.BuiltArtifact) []byte { t.Helper() if _, _, ok := catalogue.InRegistrySeat(a.Reference); !ok { t.Fatalf("%s's reference %q is not in the form a registry seat answers", a.Name, a.Reference) @@ -136,16 +136,16 @@ func TestADoneBuildsArtifactsResolveInARealArtifactStore(t *testing.T) { m := &Module{Home: home, Work: work, Cache: t.TempDir()} m.Run = StepRunner(home) addr := realStore(t, m) - done := delivery.BuilderBuild{V: 1, State: delivery.BuildDone, Manifest: strings.Repeat("0", 64)} + done := builds.BuilderBuild{V: 1, State: builds.BuildDone, Manifest: strings.Repeat("0", 64)} for _, a := range []struct{ name, kind string }{{"tools", "bundle"}, {"files", "archive"}} { out, err := m.build(context.Background(), map[string]any{"workspace": "ws1", "module": ".", "artifact": a.name}) if err != nil { t.Fatalf("%s: %v", a.name, err) } r := out.(BuildResult) - done.Artifacts = append(done.Artifacts, delivery.BuiltArtifact{Name: a.name, Kind: a.kind, Digest: r.Digest, Reference: r.Reference}) + done.Artifacts = append(done.Artifacts, builds.BuiltArtifact{Name: a.name, Kind: a.kind, Digest: r.Digest, Reference: r.Reference}) } - if _, err := delivery.EncodeBuilderBuild(done); err != nil { + if _, err := builds.EncodeBuilderBuild(done); err != nil { t.Errorf("the done key the builder would write is refused: %v", err) } if ok, missing := done.Referenced(); !ok { diff --git a/modules/mesh-build-go/cmd/mesh-build-go/test.go b/modules/mesh-build-go/cmd/mesh-build-go/test.go index 879a284d2..f9dcccb74 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/test.go @@ -17,7 +17,6 @@ import ( "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" ) @@ -41,8 +40,8 @@ func (m *Module) testTool() StepTool { "packages": map[string]any{"type": "array", "items": map[string]any{"type": "string"}, "description": "package patterns of each module, ./... when none"}, "run": map[string]any{"type": "string", "description": "optional go test -run pattern: only the tests it matches run (a try's tests)"}, - delivery.NodeNamesArg: map[string]any{"type": "array", "items": map[string]any{"type": "string"}, - "description": "optional, the names of the mesh's nodes: the tests get them comma-separated in " + delivery.NodeNamesEnv + " (a check that keeps node names out of the repository reads them there)"}, + sdkstep.NodeNamesArg: map[string]any{"type": "array", "items": map[string]any{"type": "string"}, + "description": "optional, the names of the mesh's nodes: the tests get them comma-separated in " + sdkstep.NodeNamesEnv + " (a check that keeps node names out of the repository reads them there)"}, "runner": runnerProperty, }, "required": []string{"workspace", "level"}, @@ -82,7 +81,7 @@ func (m *Module) test(ctx context.Context, args map[string]any) (any, error) { if err != nil { return nil, err } - names, err := nodeNamesArg(args[delivery.NodeNamesArg]) + names, err := nodeNamesArg(args[sdkstep.NodeNamesArg]) if err != nil { return nil, err } @@ -173,11 +172,11 @@ func (m *Module) besideEnv(workspace string) []string { const BuildNodeEnv = "MESH_BUILD_NODE" // checkEnv is what every level hands the tests it runs: the build node mark, the siblings (besideEnv) and, when the -// ask carried them, the mesh's node names (delivery.NodeNamesEnv, novox/hq ADR 0567 §12). +// ask carried them, the mesh's node names (sdkstep.NodeNamesEnv, novox/hq ADR 0567 §12). func (m *Module) checkEnv(workspace string, names []string) []string { env := append([]string{BuildNodeEnv + "=1"}, m.besideEnv(workspace)...) if len(names) > 0 { - env = append(env, delivery.NodeNamesEnv+"="+strings.Join(names, ",")) + env = append(env, sdkstep.NodeNamesEnv+"="+strings.Join(names, ",")) } return env } @@ -194,13 +193,13 @@ func nodeNamesArg(raw any) ([]string, error) { for _, e := range v { n, ok := e.(string) if !ok || n == "" || strings.ContainsAny(n, ", \n") { - return nil, fmt.Errorf("%s is a list of node names, not %v", delivery.NodeNamesArg, e) + return nil, fmt.Errorf("%s is a list of node names, not %v", sdkstep.NodeNamesArg, e) } out = append(out, n) } return out, nil } - return nil, fmt.Errorf("%s is a list of node names", delivery.NodeNamesArg) + return nil, fmt.Errorf("%s is a list of node names", sdkstep.NodeNamesArg) } // packagesArg reads the packages argument: a list of package patterns, as []any when it came over the bus as JSON and diff --git a/modules/mesh-build-go/cmd/mesh-build-go/test_test.go b/modules/mesh-build-go/cmd/mesh-build-go/test_test.go index f9047dd67..ed7d98477 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/test_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/test_test.go @@ -3,13 +3,13 @@ package main import ( "context" "encoding/json" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" "testing" "time" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" ) @@ -53,7 +53,7 @@ func workspaceFor(t *testing.T, captured string) (*Module, *keptStates, string, return m, states, "ws1", calls } -func runUnit(t *testing.T, m *Module, states *keptStates, ws string) (TestResult, delivery.Step) { +func runUnit(t *testing.T, m *Module, states *keptStates, ws string) (TestResult, sdkstep.Step) { t.Helper() var run func(map[string]any) (any, error) for _, tool := range m.Tools(m.StepTools()) { @@ -66,7 +66,7 @@ func runUnit(t *testing.T, m *Module, states *keptStates, ws string) (TestResult } st := states.waitEnd(t) var res TestResult - if st.State == delivery.StepPassed { + if st.State == sdkstep.StepPassed { if err := json.Unmarshal(st.Result, &res); err != nil { t.Fatalf("result %s: %v", st.Result, err) } @@ -79,7 +79,7 @@ func runUnit(t *testing.T, m *Module, states *keptStates, ws string) (TestResult func TestUnitLevelNamesTheFailingTestAndFailsTheLevel(t *testing.T) { m, states, ws, _ := workspaceFor(t, "failing") res, st := runUnit(t, m, states, ws) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } if res.Passed || res.Level != "unit" { @@ -109,7 +109,7 @@ func TestUnitLevelNamesTheFailingTestAndFailsTheLevel(t *testing.T) { func TestUnitLevelNamesEveryFailingTestOfEveryPackage(t *testing.T) { m, states, ws, calls := workspaceFor(t, "twofailing") res, st := runUnit(t, m, states, ws) - if st.State != delivery.StepPassed || res.Passed { + if st.State != sdkstep.StepPassed || res.Passed { t.Fatalf("step %s (%s), result %+v: want the step done and the level failed", st.State, st.Reason, res) } var got []string @@ -173,7 +173,7 @@ func TestUnitLevelOfAFixtureWithOnlyAnIntegrationTestHasNoTests(t *testing.T) { func TestUnitLevelOfAFixtureWithNoTestsSaysSo(t *testing.T) { m, states, ws, _ := workspaceFor(t, "empty") res, st := runUnit(t, m, states, ws) - if st.State != delivery.StepPassed || !res.Passed || !res.NoTests || res.Why != "the repository has no tests at the unit level" || len(res.Failed) != 0 { + if st.State != sdkstep.StepPassed || !res.Passed || !res.NoTests || res.Why != "the repository has no tests at the unit level" || len(res.Failed) != 0 { t.Errorf("result = %+v (%s)", res, st.State) } } @@ -206,7 +206,7 @@ func TestUnitLevelOfAContractsModuleOutOfStepFailsNamingEachPath(t *testing.T) { t.Errorf("%s is not under the Go root", p) } } - if st.State != delivery.StepPassed || res.Passed || !stray || !strings.Contains(res.Why, "go/stray.go") { + if st.State != sdkstep.StepPassed || res.Passed || !stray || !strings.Contains(res.Why, "go/stray.go") { t.Errorf("result = %+v (%s %s)", res, st.State, st.Reason) } } @@ -240,7 +240,7 @@ func TestUnitLevelOfAContractsModuleInAFolderOutOfStepFailsNamingEachPath(t *tes t.Errorf("%s is not under the folder's Go root", p) } } - if st.State != delivery.StepPassed || res.Passed || !stray || !strings.Contains(res.Why, "domain/go/stray.go") { + if st.State != sdkstep.StepPassed || res.Passed || !stray || !strings.Contains(res.Why, "domain/go/stray.go") { t.Errorf("result = %+v (%s %s)", res, st.State, st.Reason) } } @@ -291,7 +291,7 @@ func TestAGoTestThatCouldNotRunEndsTheStepFailed(t *testing.T) { return forgekey.Ran{Stdout: "go.mod\n"} }, &[]shutOff{}) _, st := runUnit(t, m, states, ws) - if st.State != delivery.StepFailed || !strings.Contains(st.Reason, "go: cannot find main module") { + if st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, "go: cannot find main module") { t.Errorf("the step ended %s: %q", st.State, st.Reason) } } @@ -312,7 +312,7 @@ func TestATestOfAnUnknownWorkspaceOrAnotherLevelIsRefused(t *testing.T) { {"workspace": "ws1", "level": "unit", "packages": []any{"../x"}}, } { run(args) - if st := states.waitEnd(t); st.State != delivery.StepFailed { + if st := states.waitEnd(t); st.State != sdkstep.StepFailed { t.Errorf("%v: the step ended %s", args, st.State) } } 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 d63adbe28..06f5890ce 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/versions.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/versions.go @@ -2,7 +2,7 @@ package main // The asked versions of the mesh's packages (novox/hq ADR 0573 §2, §4; issue 1585): every module builds against the latest // published version of each mesh package it uses, and a delivery group's check against the group's own heads, whatever -// version its go.mod names. The builder and the checker name each version in the ask (delivery.StepAsk.Packages, a full +// version its go.mod names. The builder and the checker name each version in the ask (sdkstep.StepAsk.Packages, a full // commit by package); before Go downloads anything, the fetch writes them into the temporary -modfile of each directory // whose go.mod requires the package (pins.go), so the fetch's go commands, the build and the tests all take them: // 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 7ba2633fb..460bb75e6 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 @@ -3,12 +3,13 @@ package main import ( "context" "encoding/json" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" "testing" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" ) @@ -101,13 +102,13 @@ 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) { + if st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, c.failsWith) || strings.Contains(st.Reason, "no pull request head") || + !strings.Contains(st.Reason, "may be retaken") || builds.FailedUntilChanged(st.Reason) { t.Errorf("the download failure ended %s: %q", st.State, st.Reason) } return } - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %s", st.State, st.Reason) } var res FetchResult diff --git a/modules/mesh-build-go/cmd/mesh-build-go/xz_test.go b/modules/mesh-build-go/cmd/mesh-build-go/xz_test.go index d2c6ef39b..54c7d6cd2 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/xz_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/xz_test.go @@ -2,14 +2,13 @@ package main import ( "context" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "net" "net/http" "net/http/httptest" "os" "path/filepath" "testing" - - "git.novox.be/novox/mesh-sdk/go/delivery" ) // releaseXzSHA256 is the sha256 of testdata/upstream-release.tar.xz: the tar stream of upstream-release.tar.gz, @@ -45,7 +44,7 @@ func pinnedModuleServing(t *testing.T, fixture, sha, extra string) (*Module, *ke func TestAPinnedXzArchiveIsUnpackedAsTheBuildAgentDoes(t *testing.T) { m, states := pinnedModuleServing(t, "upstream-release.tar.xz", releaseXzSHA256, `,"within":"release/app"`) res, st := runBuild(t, m, states, "files") - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("the step ended %s: %q", st.State, st.Reason) } sameAsBuildAgent(t, res, buildAgentWithinStream, buildAgentWithinDigest) diff --git a/modules/mesh-build-go/go.mod b/modules/mesh-build-go/go.mod index 6828a3633..273571808 100644 --- a/modules/mesh-build-go/go.mod +++ b/modules/mesh-build-go/go.mod @@ -3,6 +3,8 @@ module meshbuildgo go 1.26.0 require ( + git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildgo v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdeliverychecker v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/sdk v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry v0.0.0-00010101000000-000000000000 From cfde90906f222544b1d5c61de16f3d7e114d3453 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 5 Nov 2026 16:06:24 +0100 Subject: [PATCH 2/6] mesh-build-go: the imports the move added sit in the module group (B5i; issue 1966) Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i --- modules/mesh-build-go/buildstep/askrun.go | 5 +++-- modules/mesh-build-go/buildstep/askrun_test.go | 3 ++- modules/mesh-build-go/buildstep/capacity_cpu.go | 2 +- .../mesh-build-go/buildstep/conformance/conformance_test.go | 2 +- modules/mesh-build-go/buildstep/digestshape_test.go | 3 ++- modules/mesh-build-go/buildstep/generated_test.go | 2 +- modules/mesh-build-go/buildstep/latepublish.go | 2 +- modules/mesh-build-go/buildstep/narrate_test.go | 2 +- modules/mesh-build-go/buildstep/phase.go | 3 ++- modules/mesh-build-go/buildstep/pull.go | 4 ++-- modules/mesh-build-go/buildstep/pull_bus.go | 2 +- modules/mesh-build-go/buildstep/pull_fake.go | 3 ++- modules/mesh-build-go/buildstep/pull_integration_test.go | 2 +- modules/mesh-build-go/buildstep/pull_seat.go | 2 +- modules/mesh-build-go/buildstep/pull_seat_test.go | 2 +- modules/mesh-build-go/buildstep/pull_test.go | 4 ++-- modules/mesh-build-go/buildstep/seat_tools_test.go | 3 ++- modules/mesh-build-go/buildstep/step.go | 2 +- modules/mesh-build-go/buildstep/step_test.go | 5 +++-- modules/mesh-build-go/cmd/mesh-build-go/archive_test.go | 3 ++- modules/mesh-build-go/cmd/mesh-build-go/asks.go | 6 +++--- .../cmd/mesh-build-go/asks_integration_test.go | 2 +- .../mesh-build-go/cmd/mesh-build-go/beside_digest_test.go | 3 ++- modules/mesh-build-go/cmd/mesh-build-go/build.go | 2 +- modules/mesh-build-go/cmd/mesh-build-go/build_test.go | 2 +- modules/mesh-build-go/cmd/mesh-build-go/candidate_test.go | 2 +- modules/mesh-build-go/cmd/mesh-build-go/compose.go | 2 +- .../cmd/mesh-build-go/compose_integration_test.go | 2 +- modules/mesh-build-go/cmd/mesh-build-go/compose_test.go | 4 ++-- modules/mesh-build-go/cmd/mesh-build-go/digest.go | 5 +++-- modules/mesh-build-go/cmd/mesh-build-go/fetch_test.go | 2 +- modules/mesh-build-go/cmd/mesh-build-go/gopackage.go | 2 +- modules/mesh-build-go/cmd/mesh-build-go/imports.go | 2 +- .../cmd/mesh-build-go/installed_toolchain_test.go | 2 +- .../cmd/mesh-build-go/integration_level_test.go | 2 +- modules/mesh-build-go/cmd/mesh-build-go/isolate_test.go | 2 +- modules/mesh-build-go/cmd/mesh-build-go/kit_test.go | 2 +- modules/mesh-build-go/cmd/mesh-build-go/level.go | 2 +- modules/mesh-build-go/cmd/mesh-build-go/main.go | 4 ++-- modules/mesh-build-go/cmd/mesh-build-go/mirror_test.go | 5 +++-- modules/mesh-build-go/cmd/mesh-build-go/module.go | 2 +- modules/mesh-build-go/cmd/mesh-build-go/module_test.go | 4 ++-- .../cmd/mesh-build-go/narrow_integration_test.go | 3 ++- modules/mesh-build-go/cmd/mesh-build-go/needtools_test.go | 3 ++- .../mesh-build-go/cmd/mesh-build-go/node_toolchains_test.go | 2 +- .../cmd/mesh-build-go/pins_integration_test.go | 3 ++- modules/mesh-build-go/cmd/mesh-build-go/pins_test.go | 2 +- .../cmd/mesh-build-go/preview_integration_test.go | 2 +- modules/mesh-build-go/cmd/mesh-build-go/preview_test.go | 2 +- modules/mesh-build-go/cmd/mesh-build-go/publish_test.go | 4 ++-- modules/mesh-build-go/cmd/mesh-build-go/read.go | 4 ++-- modules/mesh-build-go/cmd/mesh-build-go/read_test.go | 5 +++-- modules/mesh-build-go/cmd/mesh-build-go/room_test.go | 2 +- .../mesh-build-go/cmd/mesh-build-go/selected_dirs_test.go | 3 ++- .../cmd/mesh-build-go/store_integration_test.go | 2 +- modules/mesh-build-go/cmd/mesh-build-go/test_test.go | 2 +- modules/mesh-build-go/cmd/mesh-build-go/versions_test.go | 4 ++-- modules/mesh-build-go/cmd/mesh-build-go/xz_test.go | 3 ++- 58 files changed, 90 insertions(+), 73 deletions(-) diff --git a/modules/mesh-build-go/buildstep/askrun.go b/modules/mesh-build-go/buildstep/askrun.go index 9c73e967c..aba1dfeaf 100644 --- a/modules/mesh-build-go/buildstep/askrun.go +++ b/modules/mesh-build-go/buildstep/askrun.go @@ -4,13 +4,14 @@ import ( "context" "encoding/json" "fmt" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" - trunk "git.novox.be/novox/mesh-delivery/sdk/trunk" "maps" "path" "slices" "sort" "strings" + + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" + trunk "git.novox.be/novox/mesh-delivery/sdk/trunk" ) // **One ask, one whole job** (novox/hq ADR 0525 §3). A build module runs a pulled ask with its own step tools' bodies, diff --git a/modules/mesh-build-go/buildstep/askrun_test.go b/modules/mesh-build-go/buildstep/askrun_test.go index 3cf0985c4..07dfa08a3 100644 --- a/modules/mesh-build-go/buildstep/askrun_test.go +++ b/modules/mesh-build-go/buildstep/askrun_test.go @@ -5,11 +5,12 @@ import ( "encoding/json" "errors" "fmt" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "slices" "strings" "testing" "time" + + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) const runCommit = "0123456789abcdef0123456789abcdef01234567" diff --git a/modules/mesh-build-go/buildstep/capacity_cpu.go b/modules/mesh-build-go/buildstep/capacity_cpu.go index dc4df230e..ff9e3c829 100644 --- a/modules/mesh-build-go/buildstep/capacity_cpu.go +++ b/modules/mesh-build-go/buildstep/capacity_cpu.go @@ -3,7 +3,6 @@ package buildstep import ( "encoding/json" "fmt" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "math" "os" "runtime" @@ -11,6 +10,7 @@ import ( "strings" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep/buildcpu" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // **A build seat's capacity follows the CPU its node gives builds** (issue 1806's follow-up; issue 1890, 2026-10-26 diff --git a/modules/mesh-build-go/buildstep/conformance/conformance_test.go b/modules/mesh-build-go/buildstep/conformance/conformance_test.go index a70dd2c98..b1460c86d 100644 --- a/modules/mesh-build-go/buildstep/conformance/conformance_test.go +++ b/modules/mesh-build-go/buildstep/conformance/conformance_test.go @@ -3,12 +3,12 @@ package conformance import ( "context" "encoding/json" - buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" "strings" "testing" "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) diff --git a/modules/mesh-build-go/buildstep/digestshape_test.go b/modules/mesh-build-go/buildstep/digestshape_test.go index 3259f19e6..374a6e26d 100644 --- a/modules/mesh-build-go/buildstep/digestshape_test.go +++ b/modules/mesh-build-go/buildstep/digestshape_test.go @@ -5,12 +5,13 @@ import ( "encoding/json" "errors" "fmt" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "sort" "strings" "sync" "testing" "time" + + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // credentialField is the node runtime's rule for a state value (mesh-tools node-tools/internal/bus/state.go, novox/hq diff --git a/modules/mesh-build-go/buildstep/generated_test.go b/modules/mesh-build-go/buildstep/generated_test.go index d4aa6c42b..a1eb3efcf 100644 --- a/modules/mesh-build-go/buildstep/generated_test.go +++ b/modules/mesh-build-go/buildstep/generated_test.go @@ -3,7 +3,6 @@ package buildstep import ( "context" "errors" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "reflect" @@ -12,6 +11,7 @@ import ( "testing" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep/seatgen" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // contracts writes a contracts module of one seat, its generated files as the generator writes them, and answers its diff --git a/modules/mesh-build-go/buildstep/latepublish.go b/modules/mesh-build-go/buildstep/latepublish.go index c81070703..46bf19c2f 100644 --- a/modules/mesh-build-go/buildstep/latepublish.go +++ b/modules/mesh-build-go/buildstep/latepublish.go @@ -13,13 +13,13 @@ import ( "context" "errors" "fmt" - builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "io" "log" "slices" "time" reg "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "git.novox.be/novox/mesh-delivery/sdk/parts" stdio "git.novox.be/novox/mesh-sdk/go" ) diff --git a/modules/mesh-build-go/buildstep/narrate_test.go b/modules/mesh-build-go/buildstep/narrate_test.go index 21078e8ce..5b27e9b60 100644 --- a/modules/mesh-build-go/buildstep/narrate_test.go +++ b/modules/mesh-build-go/buildstep/narrate_test.go @@ -5,13 +5,13 @@ import ( "encoding/json" "errors" "fmt" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "strings" "sync" "testing" "time" reg "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // CAT-NR1: a build's publish on a seat says asked, waiting on the seat (on every tick of NarrateEvery while the holder diff --git a/modules/mesh-build-go/buildstep/phase.go b/modules/mesh-build-go/buildstep/phase.go index 187d4ea3e..ffb0168fc 100644 --- a/modules/mesh-build-go/buildstep/phase.go +++ b/modules/mesh-build-go/buildstep/phase.go @@ -2,10 +2,11 @@ package buildstep import ( "context" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "strings" "sync" "time" + + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // **A running ask says its phases** (issue 1890, 2026-10-26 19:09: a mesh-catalog try's step on the workstation ran 30 minutes diff --git a/modules/mesh-build-go/buildstep/pull.go b/modules/mesh-build-go/buildstep/pull.go index abbc9386b..c5229c60d 100644 --- a/modules/mesh-build-go/buildstep/pull.go +++ b/modules/mesh-build-go/buildstep/pull.go @@ -5,13 +5,13 @@ import ( "encoding/json" "errors" "fmt" - buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "sort" "strings" "sync" "time" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" stdio "git.novox.be/novox/mesh-sdk/go" ) diff --git a/modules/mesh-build-go/buildstep/pull_bus.go b/modules/mesh-build-go/buildstep/pull_bus.go index cbdafc71e..9f2a8f12a 100644 --- a/modules/mesh-build-go/buildstep/pull_bus.go +++ b/modules/mesh-build-go/buildstep/pull_bus.go @@ -3,10 +3,10 @@ package buildstep import ( "context" "fmt" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "sync" "time" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "github.com/nats-io/nats.go/jetstream" ) diff --git a/modules/mesh-build-go/buildstep/pull_fake.go b/modules/mesh-build-go/buildstep/pull_fake.go index 3ba5766e8..ddefb2338 100644 --- a/modules/mesh-build-go/buildstep/pull_fake.go +++ b/modules/mesh-build-go/buildstep/pull_fake.go @@ -2,9 +2,10 @@ package buildstep import ( "context" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "sync" "time" + + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // FakeAsks is a test double of a seat's workers for the build modules' unit tests: Publish puts an ask on a kind's diff --git a/modules/mesh-build-go/buildstep/pull_integration_test.go b/modules/mesh-build-go/buildstep/pull_integration_test.go index e8425771a..5fee7d300 100644 --- a/modules/mesh-build-go/buildstep/pull_integration_test.go +++ b/modules/mesh-build-go/buildstep/pull_integration_test.go @@ -4,7 +4,6 @@ package buildstep import ( "context" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "strings" "sync" "testing" @@ -13,6 +12,7 @@ import ( "github.com/nats-io/nats.go" "github.com/nats-io/nats.go/jetstream" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/testbus" ) diff --git a/modules/mesh-build-go/buildstep/pull_seat.go b/modules/mesh-build-go/buildstep/pull_seat.go index 7c466420b..9441618b7 100644 --- a/modules/mesh-build-go/buildstep/pull_seat.go +++ b/modules/mesh-build-go/buildstep/pull_seat.go @@ -2,9 +2,9 @@ package buildstep import ( "context" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "time" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" stdio "git.novox.be/novox/mesh-sdk/go" ) diff --git a/modules/mesh-build-go/buildstep/pull_seat_test.go b/modules/mesh-build-go/buildstep/pull_seat_test.go index aa1c7bdd7..e72422645 100644 --- a/modules/mesh-build-go/buildstep/pull_seat_test.go +++ b/modules/mesh-build-go/buildstep/pull_seat_test.go @@ -2,10 +2,10 @@ package buildstep import ( "context" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "testing" "time" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" stdio "git.novox.be/novox/mesh-sdk/go" ) diff --git a/modules/mesh-build-go/buildstep/pull_test.go b/modules/mesh-build-go/buildstep/pull_test.go index 999af3855..5e2503719 100644 --- a/modules/mesh-build-go/buildstep/pull_test.go +++ b/modules/mesh-build-go/buildstep/pull_test.go @@ -5,8 +5,6 @@ import ( "encoding/json" "errors" "fmt" - buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" @@ -15,6 +13,8 @@ import ( "testing" "time" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" stdio "git.novox.be/novox/mesh-sdk/go" ) diff --git a/modules/mesh-build-go/buildstep/seat_tools_test.go b/modules/mesh-build-go/buildstep/seat_tools_test.go index ab87f8ad6..5d04a5862 100644 --- a/modules/mesh-build-go/buildstep/seat_tools_test.go +++ b/modules/mesh-build-go/buildstep/seat_tools_test.go @@ -2,9 +2,10 @@ package buildstep import ( "context" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "testing" "time" + + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // 1887/A9a, ADR 0525 §10: a build seat's verbs are .current, .pause and .resume; current names the ask running, diff --git a/modules/mesh-build-go/buildstep/step.go b/modules/mesh-build-go/buildstep/step.go index 7062030d5..c145958ff 100644 --- a/modules/mesh-build-go/buildstep/step.go +++ b/modules/mesh-build-go/buildstep/step.go @@ -9,10 +9,10 @@ import ( "encoding/json" "errors" "fmt" - buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" "log" "time" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) diff --git a/modules/mesh-build-go/buildstep/step_test.go b/modules/mesh-build-go/buildstep/step_test.go index fe7b0f8f2..a2a19cd2c 100644 --- a/modules/mesh-build-go/buildstep/step_test.go +++ b/modules/mesh-build-go/buildstep/step_test.go @@ -4,11 +4,12 @@ import ( "context" "encoding/json" "errors" - buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "sync" "testing" "time" + + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // keys is a steps state in memory: every value put, in order, per key, and a signal for each end. diff --git a/modules/mesh-build-go/cmd/mesh-build-go/archive_test.go b/modules/mesh-build-go/cmd/mesh-build-go/archive_test.go index ab1296673..9df531908 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/archive_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/archive_test.go @@ -6,7 +6,6 @@ import ( "context" "crypto/sha256" "encoding/hex" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "io" "net" "net/http" @@ -16,6 +15,8 @@ import ( "runtime" "strings" "testing" + + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // Issue 1589: the build step packs an archive artifact (novox/hq ADR 0478 §1), as the build agent packs it diff --git a/modules/mesh-build-go/cmd/mesh-build-go/asks.go b/modules/mesh-build-go/cmd/mesh-build-go/asks.go index 175eb687c..cfe30196d 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/asks.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/asks.go @@ -4,13 +4,13 @@ import ( "context" "encoding/json" "fmt" - checkerseat "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdeliverychecker" - seat "git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildgo" - buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" "path/filepath" "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + checkerseat "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdeliverychecker" + seat "git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildgo" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" stdio "git.novox.be/novox/mesh-sdk/go" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/asks_integration_test.go b/modules/mesh-build-go/cmd/mesh-build-go/asks_integration_test.go index 724d5f464..6272dbfb8 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/asks_integration_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/asks_integration_test.go @@ -4,7 +4,6 @@ package main import ( "context" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "sync" "testing" "time" @@ -13,6 +12,7 @@ import ( "github.com/nats-io/nats.go/jetstream" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/testbus" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/beside_digest_test.go b/modules/mesh-build-go/cmd/mesh-build-go/beside_digest_test.go index b3c90d921..0f7b0f514 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/beside_digest_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/beside_digest_test.go @@ -2,12 +2,13 @@ package main import ( "encoding/json" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "slices" "strings" "testing" + + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // writeSiblings records the siblings the fetch placed, as the fetch does. diff --git a/modules/mesh-build-go/cmd/mesh-build-go/build.go b/modules/mesh-build-go/cmd/mesh-build-go/build.go index 512634d42..c50fe1533 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/build.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/build.go @@ -9,12 +9,12 @@ package main import ( "context" "fmt" - builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "os" "path/filepath" "strings" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "git.novox.be/novox/mesh-sdk/go/catalogue" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/build_test.go b/modules/mesh-build-go/cmd/mesh-build-go/build_test.go index c92812b35..16461569f 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/build_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/build_test.go @@ -7,7 +7,6 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "io" "os" "path/filepath" @@ -15,6 +14,7 @@ import ( "strings" "testing" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/candidate_test.go b/modules/mesh-build-go/cmd/mesh-build-go/candidate_test.go index 640e4142b..c18ea5452 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/candidate_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/candidate_test.go @@ -3,13 +3,13 @@ package main import ( "context" "encoding/json" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "slices" "strings" "testing" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/compose.go b/modules/mesh-build-go/cmd/mesh-build-go/compose.go index 3a8155c3d..1a81557c3 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/compose.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/compose.go @@ -17,7 +17,6 @@ import ( "encoding/json" "errors" "fmt" - catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "io" "os" "path/filepath" @@ -27,6 +26,7 @@ import ( "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" + catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-delivery/sdk/composer" stdio "git.novox.be/novox/mesh-sdk/go" diff --git a/modules/mesh-build-go/cmd/mesh-build-go/compose_integration_test.go b/modules/mesh-build-go/cmd/mesh-build-go/compose_integration_test.go index 72b6b442a..4bee95dbf 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/compose_integration_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/compose_integration_test.go @@ -5,7 +5,6 @@ package main import ( "context" "encoding/json" - catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" "io/fs" "os" "os/exec" @@ -18,6 +17,7 @@ import ( "github.com/nats-io/nats.go/jetstream" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-delivery/sdk/composer" "git.novox.be/novox/mesh-sdk/go/forgekey" diff --git a/modules/mesh-build-go/cmd/mesh-build-go/compose_test.go b/modules/mesh-build-go/cmd/mesh-build-go/compose_test.go index 3f01603ec..c4a56907d 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/compose_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/compose_test.go @@ -4,8 +4,6 @@ import ( "context" "encoding/json" "errors" - catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" - meshcat "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" "os" "path/filepath" "slices" @@ -13,6 +11,8 @@ import ( "testing" "time" + catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" + meshcat "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-delivery/sdk/composer" "git.novox.be/novox/mesh-sdk/go/forgekey" diff --git a/modules/mesh-build-go/cmd/mesh-build-go/digest.go b/modules/mesh-build-go/cmd/mesh-build-go/digest.go index 961457a3c..6a85a7ae6 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/digest.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/digest.go @@ -13,8 +13,6 @@ import ( "encoding/json" "errors" "fmt" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" - trunk "git.novox.be/novox/mesh-delivery/sdk/trunk" "io" "io/fs" "os" @@ -23,6 +21,9 @@ import ( "sort" "strconv" "strings" + + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" + trunk "git.novox.be/novox/mesh-delivery/sdk/trunk" ) // DigestVersion is the form of the digest's text: changed whenever what the digest hashes changes in kind. diff --git a/modules/mesh-build-go/cmd/mesh-build-go/fetch_test.go b/modules/mesh-build-go/cmd/mesh-build-go/fetch_test.go index 9f4ae2d1b..e01fd9b45 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/fetch_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/fetch_test.go @@ -3,7 +3,6 @@ package main import ( "context" "encoding/json" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" @@ -11,6 +10,7 @@ import ( "testing" "time" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/gopackage.go b/modules/mesh-build-go/cmd/mesh-build-go/gopackage.go index fb60b04fa..dbeaf4bee 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/gopackage.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/gopackage.go @@ -13,7 +13,6 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "io" "os" "path/filepath" @@ -23,6 +22,7 @@ import ( "golang.org/x/mod/module" modzip "golang.org/x/mod/zip" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "git.novox.be/novox/mesh-sdk/go/catalogue" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/imports.go b/modules/mesh-build-go/cmd/mesh-build-go/imports.go index a19a61d84..e9ea32a9a 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/imports.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/imports.go @@ -9,12 +9,12 @@ package main import ( "context" "fmt" - trunk "git.novox.be/novox/mesh-delivery/sdk/trunk" "os" "path/filepath" "slices" "strings" + trunk "git.novox.be/novox/mesh-delivery/sdk/trunk" "git.novox.be/novox/mesh-sdk/go/catalogue" "git.novox.be/novox/mesh-sdk/go/forgekey" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/installed_toolchain_test.go b/modules/mesh-build-go/cmd/mesh-build-go/installed_toolchain_test.go index 75d952dff..218e34a4d 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/installed_toolchain_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/installed_toolchain_test.go @@ -2,7 +2,6 @@ package main import ( "context" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "reflect" @@ -13,6 +12,7 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep/buildcpu" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" "git.novox.be/novox/mesh-sdk/go/health" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/integration_level_test.go b/modules/mesh-build-go/cmd/mesh-build-go/integration_level_test.go index c4e85e65a..e2cf5bad1 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/integration_level_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/integration_level_test.go @@ -3,7 +3,6 @@ package main import ( "context" "encoding/json" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "net/url" "os" "path/filepath" @@ -12,6 +11,7 @@ import ( "testing" "time" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/isolate_test.go b/modules/mesh-build-go/cmd/mesh-build-go/isolate_test.go index 4588f7297..190224d77 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/isolate_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/isolate_test.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "errors" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "path/filepath" "slices" "strings" @@ -12,6 +11,7 @@ import ( "testing" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/kit_test.go b/modules/mesh-build-go/cmd/mesh-build-go/kit_test.go index c89199a44..73fa84288 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/kit_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/kit_test.go @@ -2,11 +2,11 @@ package main import ( "context" - buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" "testing" "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep/conformance" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/level.go b/modules/mesh-build-go/cmd/mesh-build-go/level.go index b58001efb..d61907753 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/level.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/level.go @@ -10,7 +10,6 @@ import ( "context" "encoding/json" "fmt" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "os/exec" "path/filepath" @@ -18,6 +17,7 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // levelArg is the first argument that makes this binary a step's shut-off process: the integration level's, and, when diff --git a/modules/mesh-build-go/cmd/mesh-build-go/main.go b/modules/mesh-build-go/cmd/mesh-build-go/main.go index a20113d2d..2e1fae05e 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/main.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/main.go @@ -8,13 +8,13 @@ package main import ( "context" "fmt" - seat "git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildgo" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "os/user" "strings" "time" + seat "git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildgo" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" stdio "git.novox.be/novox/mesh-sdk/go" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/mirror_test.go b/modules/mesh-build-go/cmd/mesh-build-go/mirror_test.go index 69595b3b0..6b5c39202 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/mirror_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/mirror_test.go @@ -3,8 +3,6 @@ package main import ( "encoding/json" "fmt" - "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "os/exec" "path/filepath" @@ -12,6 +10,9 @@ import ( "sync" "testing" "time" + + "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) func fetchOnce(t *testing.T, m *Module, states *keptStates, args map[string]any) FetchResult { diff --git a/modules/mesh-build-go/cmd/mesh-build-go/module.go b/modules/mesh-build-go/cmd/mesh-build-go/module.go index a09a976b7..75bd3cff2 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/module.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/module.go @@ -4,12 +4,12 @@ import ( "context" "encoding/json" "fmt" - buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" "net/http" "sync" "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" "git.novox.be/novox/mesh-sdk/go/health" diff --git a/modules/mesh-build-go/cmd/mesh-build-go/module_test.go b/modules/mesh-build-go/cmd/mesh-build-go/module_test.go index 162237da0..e099f16e4 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/module_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/module_test.go @@ -4,13 +4,13 @@ import ( "context" "encoding/json" "errors" - buildstep "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "strings" "sync" "testing" "time" + buildstep "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/health" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/narrow_integration_test.go b/modules/mesh-build-go/cmd/mesh-build-go/narrow_integration_test.go index cdc9491da..d7e684fed 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/narrow_integration_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/narrow_integration_test.go @@ -3,11 +3,12 @@ package main import ( - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" "testing" + + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // ADR 0499 §4 (issue 1758): a fetch asked with the module's directory and its named paths leaves the workspace holding diff --git a/modules/mesh-build-go/cmd/mesh-build-go/needtools_test.go b/modules/mesh-build-go/cmd/mesh-build-go/needtools_test.go index 63b07e738..e39595e3c 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/needtools_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/needtools_test.go @@ -1,10 +1,11 @@ package main import ( - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "slices" "strings" "testing" + + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // Issue 1309: a test that runs a step in bubblewrap is proof only where it runs. Where a build module judges (it hands diff --git a/modules/mesh-build-go/cmd/mesh-build-go/node_toolchains_test.go b/modules/mesh-build-go/cmd/mesh-build-go/node_toolchains_test.go index 332a82166..a1f37d054 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/node_toolchains_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/node_toolchains_test.go @@ -3,13 +3,13 @@ package main import ( "context" "encoding/json" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "slices" "strconv" "testing" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/pins_integration_test.go b/modules/mesh-build-go/cmd/mesh-build-go/pins_integration_test.go index c3aeebd2c..d19157869 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/pins_integration_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/pins_integration_test.go @@ -8,11 +8,12 @@ package main import ( "context" "fmt" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "os/exec" "path/filepath" "testing" + + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // 1148/AC2 as issue 1585 S15 has it (novox/hq ADR 0573 §4): given a forge with a mesh-sdk-like pull request whose branch diff --git a/modules/mesh-build-go/cmd/mesh-build-go/pins_test.go b/modules/mesh-build-go/cmd/mesh-build-go/pins_test.go index 710668068..75a5085af 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/pins_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/pins_test.go @@ -3,7 +3,6 @@ package main import ( "context" "encoding/json" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "os/exec" "path/filepath" @@ -11,6 +10,7 @@ import ( "sync" "testing" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/preview_integration_test.go b/modules/mesh-build-go/cmd/mesh-build-go/preview_integration_test.go index c24e7210e..95cccd6c7 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/preview_integration_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/preview_integration_test.go @@ -7,7 +7,6 @@ package main import ( "encoding/json" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "os/exec" "path/filepath" @@ -16,6 +15,7 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) func git(t *testing.T, dir string, args ...string) string { diff --git a/modules/mesh-build-go/cmd/mesh-build-go/preview_test.go b/modules/mesh-build-go/cmd/mesh-build-go/preview_test.go index 27f0f49b5..87ff97f0c 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/preview_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/preview_test.go @@ -5,12 +5,12 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" "testing" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/publish_test.go b/modules/mesh-build-go/cmd/mesh-build-go/publish_test.go index 7a59a594f..4f5a587d9 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/publish_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/publish_test.go @@ -8,8 +8,6 @@ import ( "encoding/hex" "encoding/json" "errors" - builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" @@ -17,6 +15,8 @@ import ( "testing" registry "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // pushed are the blobs the fake artifact store took, by digest, for the tests that read an archive back. diff --git a/modules/mesh-build-go/cmd/mesh-build-go/read.go b/modules/mesh-build-go/cmd/mesh-build-go/read.go index 22b6c2d9d..57c298779 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/read.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/read.go @@ -7,8 +7,6 @@ package main import ( "encoding/json" "fmt" - buildstep "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "log" "sort" "strconv" @@ -16,6 +14,8 @@ import ( "sync" "time" + buildstep "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" stdio "git.novox.be/novox/mesh-sdk/go" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/read_test.go b/modules/mesh-build-go/cmd/mesh-build-go/read_test.go index 21edf59c4..b83f60e03 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/read_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/read_test.go @@ -4,13 +4,14 @@ import ( "context" "encoding/json" "fmt" - buildstep "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "slices" "strings" "sync/atomic" "testing" "time" + + buildstep "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // fakeState is a state as stored: key to raw value. diff --git a/modules/mesh-build-go/cmd/mesh-build-go/room_test.go b/modules/mesh-build-go/cmd/mesh-build-go/room_test.go index 239641493..3e65c8686 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/room_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/room_test.go @@ -2,7 +2,6 @@ package main import ( "context" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" @@ -10,6 +9,7 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" "git.novox.be/novox/mesh-sdk/go/health" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/selected_dirs_test.go b/modules/mesh-build-go/cmd/mesh-build-go/selected_dirs_test.go index 5e1c54b0d..77e8915e9 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/selected_dirs_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/selected_dirs_test.go @@ -3,13 +3,14 @@ package main import ( "encoding/json" "fmt" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" "sync" "testing" "time" + + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // threeModules gives the workspace three go.mod directories, a, b and c, whose modules are fixture/a, fixture/b and diff --git a/modules/mesh-build-go/cmd/mesh-build-go/store_integration_test.go b/modules/mesh-build-go/cmd/mesh-build-go/store_integration_test.go index 67b093a16..2bf8e34e1 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/store_integration_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/store_integration_test.go @@ -9,7 +9,6 @@ import ( "encoding/hex" "encoding/json" "fmt" - builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "io" "net/http" "net/http/httptest" @@ -25,6 +24,7 @@ import ( _ "github.com/distribution/distribution/v3/registry/storage/driver/inmemory" registry "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "git.novox.be/novox/mesh-sdk/go/catalogue" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/test_test.go b/modules/mesh-build-go/cmd/mesh-build-go/test_test.go index ed7d98477..bd241bb20 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/test_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/test_test.go @@ -3,13 +3,13 @@ package main import ( "context" "encoding/json" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" "testing" "time" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" ) 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 460bb75e6..958a5a34c 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 @@ -3,13 +3,13 @@ package main import ( "context" "encoding/json" - builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "os" "path/filepath" "strings" "testing" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" ) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/xz_test.go b/modules/mesh-build-go/cmd/mesh-build-go/xz_test.go index 54c7d6cd2..35ca8107b 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/xz_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/xz_test.go @@ -2,13 +2,14 @@ package main import ( "context" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "net" "net/http" "net/http/httptest" "os" "path/filepath" "testing" + + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // releaseXzSHA256 is the sha256 of testdata/upstream-release.tar.xz: the tar stream of upstream-release.tar.gz, From aa29d8feb84cf021792ca0b5159fd9afe50e7af1 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 5 Nov 2026 16:06:48 +0100 Subject: [PATCH 3/6] =?UTF-8?q?mesh-build-image=20runs=20its=20asks=20on?= =?UTF-8?q?=20the=20Delivery=20SDK's=20neutral=20build=20ask,=20step=20and?= =?UTF-8?q?=20answer=20forms=20instead=20of=20mesh-sdk's=20go/delivery;=20?= =?UTF-8?q?its=20state=20names=20are=20its=20seat's=20(B5i;=20ADR=200634?= =?UTF-8?q?=20=C2=A71,=20=C2=A76;=20issue=201966)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i --- .../cmd/mesh-build-image/asks.go | 21 +++++++++--------- .../cmd/mesh-build-image/asks_test.go | 17 +++++++------- .../cmd/mesh-build-image/build_test.go | 20 ++++++++--------- .../mesh-build-image/bus_integration_test.go | 14 ++++++------ .../cmd/mesh-build-image/capture_test.go | 6 ++--- .../cmd/mesh-build-image/copy.go | 19 ++++++++-------- .../cmd/mesh-build-image/copy_test.go | 10 ++++----- .../cmd/mesh-build-image/fetch_test.go | 8 +++---- .../cmd/mesh-build-image/helpers_test.go | 14 ++++++------ .../cmd/mesh-build-image/integration_test.go | 22 +++++++++---------- .../cmd/mesh-build-image/kit_test.go | 4 ++-- .../cmd/mesh-build-image/main.go | 13 ++++++----- .../cmd/mesh-build-image/module.go | 8 +++---- .../cmd/mesh-build-image/module_test.go | 4 ++-- .../cmd/mesh-build-image/publish.go | 10 ++++----- .../cmd/mesh-build-image/publish_test.go | 13 ++++++----- .../cmd/mesh-build-image/read.go | 22 +++++++++---------- .../cmd/mesh-build-image/read_test.go | 8 +++---- .../cmd/mesh-build-image/room_test.go | 6 ++--- 19 files changed, 121 insertions(+), 118 deletions(-) diff --git a/modules/mesh-build-image/cmd/mesh-build-image/asks.go b/modules/mesh-build-image/cmd/mesh-build-image/asks.go index 678493d8d..d4f3711dd 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/asks.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/asks.go @@ -5,9 +5,10 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + seat "git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildimage" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // **The module pulls its seat's asks** (novox/hq ADR 0525 §2-§6; issue 1887 A3image), as mesh-build-go does: the seat @@ -36,7 +37,7 @@ func (m *Module) askSteps(steps []StepTool) buildstep.AskSteps { // Puller is the module's pull of its seat's asks, on source (the runtime's seat pull when nil). func (m *Module) Puller(steps []StepTool, source buildstep.AskSource) *buildstep.Puller { if source == nil { - source = buildstep.SeatAsks{Language: delivery.AskImage} + source = buildstep.SeatAsks{Language: sdkstep.AskImage} } capacity := m.Capacity // The capacity's own change wakes the puller (issue 1887): the runtime's watch of the config value as mesh-config @@ -54,16 +55,16 @@ func (m *Module) Puller(steps []StepTool, source buildstep.AskSource) *buildstep capacity = buildstep.NodeCapacity(m.Settings, m.Node, m.Say) settings = m.Settings watch = buildstep.WatchConfigServed - cores = buildstep.NodeCoresPerStep(m.Settings, buildstep.DefaultCoresPerStep[delivery.AskImage], m.Say) + cores = buildstep.NodeCoresPerStep(m.Settings, buildstep.DefaultCoresPerStep[sdkstep.AskImage], m.Say) } ask := m.askSteps(steps) var load func(string) ([]byte, error) if m.ReadPauses.Get != nil { load = func(key string) ([]byte, error) { return m.ReadPauses.Get(key) } } - return &buildstep.Puller{Source: source, Language: delivery.AskImage, Node: m.Node, Put: m.Steps, PausePut: m.Pauses, Load: load, + return &buildstep.Puller{Source: source, Language: sdkstep.AskImage, Node: m.Node, Put: m.Steps, PausePut: m.Pauses, Load: load, Capacity: capacity, SettingsFile: settings, WatchConfig: watch, CoresPerStep: cores, BuildHours: hours, Eligible: m.Eligible, Logf: m.Say, - Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { + Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { if err := m.Check(ctx); err != nil { return nil, err } @@ -83,13 +84,13 @@ func (m *Module) SeatTools(p *buildstep.Puller) []stdio.Tool { const StepEndTool = "build_image_step_end" // endLeftRunning is the module's start sweep (issue 1890): it ends the steps of its node that a previous process left -// running (sdkstep.EndStaleAtStart; every step names its owner). main runs it once at the start, and the module's test +// running (buildrun.EndStaleAtStart; every step names its owner). main runs it once at the start, and the module's test // runs it through the conformance kit's left-running case. -func (m *Module) endLeftRunning(ctx context.Context, scan sdkstep.Scan, booted time.Time, logf func(string, ...any)) { - sdkstep.EndStaleAtStart(ctx, scan, m.Node, booted, logf) +func (m *Module) endLeftRunning(ctx context.Context, scan buildrun.Scan, booted time.Time, logf func(string, ...any)) { + buildrun.EndStaleAtStart(ctx, scan, m.Node, booted, logf) } // stepScan is the module's steps state as buildstep reads it. -func (m *Module) stepScan() sdkstep.Scan { - return sdkstep.ScanOf(stdio.State(delivery.StepsState)) +func (m *Module) stepScan() buildrun.Scan { + return buildrun.ScanOf(stdio.State(seat.StateSteps)) } diff --git a/modules/mesh-build-image/cmd/mesh-build-image/asks_test.go b/modules/mesh-build-image/cmd/mesh-build-image/asks_test.go index 679a7ed0d..4ff1a2d4a 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/asks_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/asks_test.go @@ -8,7 +8,6 @@ import ( "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" ) const askCommit = "0123456789abcdef0123456789abcdef01234567" @@ -32,23 +31,23 @@ func TestAPulledImageAskCopiesThenBuilds(t *testing.T) { answer("build_image_copy", map[string]any{"digest": "sha256:dd", "reference": "registry/m/base@sha256:dd"}), } src := buildstep.NewFakeAsks() - a := delivery.StepAsk{ID: sdkstep.NewID(), Kind: delivery.AskDelivery, Language: delivery.AskImage, Asker: "mesh-delivery-builder", - At: time.Now(), Build: &delivery.BuildJob{Module: "m", Path: "modules/m", Publish: true, - Fetch: map[string]any{"repository": "novox/mesh-catalog", "commit": askCommit}, - Artifacts: []delivery.AskArtifact{{Artifact: "base", From: "docker.io/library/alpine@sha256:00"}, {Artifact: "server"}}}} + a := sdkstep.StepAsk{ID: sdkstep.NewID(), Kind: sdkstep.AskDelivery, Language: sdkstep.AskImage, Asker: "mesh-delivery-builder", + At: time.Now(), Build: &sdkstep.BuildJob{Module: "m", Path: "modules/m", Publish: true, + Fetch: &sdkstep.Fetch{Repository: "novox/mesh-catalog", Commit: askCommit}, + Artifacts: []sdkstep.AskArtifact{{Artifact: "base", From: "docker.io/library/alpine@sha256:00"}, {Artifact: "server"}}}} _ = src.PublishAsk(a) p := m.Puller(steps, src) p.PullWait = 10 * time.Millisecond ctx, stop := context.WithCancel(context.Background()) defer stop() go p.Pull(ctx) - key, _ := delivery.AskStepKey("ace", a.ID) - var step delivery.Step + key, _ := sdkstep.AskStepKey("ace", a.ID) + var step sdkstep.Step for deadline := time.Now().Add(3 * time.Second); ; time.Sleep(5 * time.Millisecond) { states.mu.Lock() v := states.steps[key] states.mu.Unlock() - if len(v) > 0 && v[len(v)-1].State != delivery.StepRunning { + if len(v) > 0 && v[len(v)-1].State != sdkstep.StepRunning { step = v[len(v)-1] break } @@ -56,7 +55,7 @@ func TestAPulledImageAskCopiesThenBuilds(t *testing.T) { t.Fatalf("the ask's step never ended: calls %v", calls) } } - if step.State != delivery.StepPassed || !strings.Contains(string(step.Result), "registry/m/server@sha256:cc") || + if step.State != sdkstep.StepPassed || !strings.Contains(string(step.Result), "registry/m/server@sha256:cc") || !strings.Contains(string(step.Result), "registry/m/base@sha256:dd") { t.Fatalf("the step = %+v", step) } diff --git a/modules/mesh-build-image/cmd/mesh-build-image/build_test.go b/modules/mesh-build-image/cmd/mesh-build-image/build_test.go index fddcc86dd..8430c34a9 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/build_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/build_test.go @@ -2,14 +2,14 @@ package main import ( "encoding/json" - "git.novox.be/novox/mesh-sdk/go/forgekey" "os" "path/filepath" "strings" "testing" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/delivery" + "git.novox.be/novox/mesh-sdk/go/forgekey" ) // The fixture module (testdata/repos/image): a Dockerfile that adds a file to an upstream base the manifest pins in @@ -38,7 +38,7 @@ func place(t *testing.T, m *Module, edit func(string) string) { func same(s string) string { return s } -func runBuild(t *testing.T, m *Module, states *keptStates, extra map[string]any) (BuildResult, delivery.Step) { +func runBuild(t *testing.T, m *Module, states *keptStates, extra map[string]any) (BuildResult, sdkstep.Step) { t.Helper() args := map[string]any{"workspace": "ws1", "module": "modules/demo", "artifact": "server"} for k, v := range extra { @@ -49,7 +49,7 @@ func runBuild(t *testing.T, m *Module, states *keptStates, extra map[string]any) } st := states.waitEnd(t) var res BuildResult - if st.State == delivery.StepPassed { + if st.State == sdkstep.StepPassed { if err := json.Unmarshal(st.Result, &res); err != nil { t.Fatal(err) } @@ -73,7 +73,7 @@ func TestBuildRunsBuildahRootlessAndAnswersTheDigest(t *testing.T) { t.Setenv("MESH_BUILD_CPU_SHARE", "50") // the composer's share (ADR 0553): buildah is given its threads m, f, states := setup(t, same) res, st := runBuild(t, m, states, nil) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("step = %+v", st) } if res.Digest != imageDigest || res.Artifact != "server" || res.Pushed || res.Reference != "" { @@ -144,7 +144,7 @@ func TestBuildContextIsTheModulesDirectoryForADockerfileInASubdirectory(t *testi } } _, st := runBuild(t, m, states, nil) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("step = %+v", st) } bud := f.called("bud") @@ -183,7 +183,7 @@ func TestBuildFailsWithBuildahsError(t *testing.T) { m, f, states := setup(t, same) f.failBud = c.ran _, st := runBuild(t, m, states, nil) - if st.State != delivery.StepFailed { + if st.State != sdkstep.StepFailed { t.Errorf("%s: step = %+v, want failed", name, st) continue } @@ -223,7 +223,7 @@ func TestBuildRefusesAnImageWithARepositoryContextOrAModuleBase(t *testing.T) { for name, c := range cases { m, f, states := setup(t, c.edit) _, st := runBuild(t, m, states, nil) - if st.State != delivery.StepRefused { + if st.State != sdkstep.StepRefused { t.Errorf("%s: step = %+v, want refused", name, st) continue } @@ -266,7 +266,7 @@ func TestBuildFailsForWhatIsNotAnImageOrNotThere(t *testing.T) { } { m, f, states := setup(t, tc.edit) _, st := runBuild(t, m, states, tc.args) - if st.State != delivery.StepFailed { + if st.State != sdkstep.StepFailed { t.Errorf("%s: step = %+v, want failed", name, st) } if len(f.called("bud")) != 0 { @@ -317,7 +317,7 @@ func TestAManifestFallingBackToAPredefinedKeyBuilds(t *testing.T) { return string(out) }) res, st := runBuild(t, m, states, nil) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("step = %+v", st) } if res.Digest != imageDigest || res.Artifact != "server" { diff --git a/modules/mesh-build-image/cmd/mesh-build-image/bus_integration_test.go b/modules/mesh-build-image/cmd/mesh-build-image/bus_integration_test.go index 4444d9276..f5167f7c3 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/bus_integration_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/bus_integration_test.go @@ -16,7 +16,7 @@ import ( "testing" "time" - "git.novox.be/novox/mesh-sdk/go/delivery" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "github.com/nats-io/nats-server/v2/server" "github.com/nats-io/nats.go" "github.com/nats-io/nats.go/jetstream" @@ -100,23 +100,23 @@ func call(t *testing.T, nc *nats.Conn, tool string, args map[string]any) map[str } // ended waits for the step's key in the bucket to leave running and answers the step as the bucket holds it. -func ended(t *testing.T, kv jetstream.KeyValue, key string) delivery.Step { +func ended(t *testing.T, kv jetstream.KeyValue, key string) sdkstep.Step { t.Helper() deadline := time.Now().Add(30 * time.Second) for time.Now().Before(deadline) { if e, err := kv.Get(context.Background(), key); err == nil { - st, err := delivery.DecodeStep(e.Value()) + st, err := sdkstep.DecodeStep(e.Value()) if err != nil { t.Fatal(err) } - if st.State != delivery.StepRunning { + if st.State != sdkstep.StepRunning { return st } } time.Sleep(20 * time.Millisecond) } t.Fatalf("the key %s never left running", key) - return delivery.Step{} + return sdkstep.Step{} } func TestTheStepsAnswerThroughARealBusWithTheCapturedShapes(t *testing.T) { @@ -128,7 +128,7 @@ func TestTheStepsAnswerThroughARealBusWithTheCapturedShapes(t *testing.T) { // The fetch: a running key at once, then the workspace on the key. started := call(t, nc, FetchTool, map[string]any{"repository": "novox/mesh-catalog", "commit": commitSHA}) - if started["state"] != delivery.StepRunning || started["key"] == "" { + if started["state"] != sdkstep.StepRunning || started["key"] == "" { t.Fatalf("the fetch answered %v, want a running step and its key", started) } st := ended(t, kv, started["key"].(string)) @@ -142,7 +142,7 @@ func TestTheStepsAnswerThroughARealBusWithTheCapturedShapes(t *testing.T) { } started := call(t, nc, BuildTool, args) st := ended(t, kv, started["key"].(string)) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("%s: step = %+v", name, st) } var res BuildResult diff --git a/modules/mesh-build-image/cmd/mesh-build-image/capture_test.go b/modules/mesh-build-image/cmd/mesh-build-image/capture_test.go index f251ca7e8..ddbc1389f 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/capture_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/capture_test.go @@ -17,7 +17,7 @@ import ( "testing" "time" - "git.novox.be/novox/mesh-sdk/go/delivery" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) const capturedDir = "testdata/captured" @@ -25,7 +25,7 @@ const capturedDir = "testdata/captured" var hexDigest = regexp.MustCompile(`sha256:[0-9a-f]{64}`) // normalized is a stored step with the words that differ between runs put to fixed ones. -func normalized(t *testing.T, st delivery.Step, workspace, commit, registry string) []byte { +func normalized(t *testing.T, st sdkstep.Step, workspace, commit, registry string) []byte { t.Helper() raw, err := json.Marshal(st) if err != nil { @@ -75,7 +75,7 @@ func compareCaptured(t *testing.T, name string, got []byte) { } } -func workspaceOf(t *testing.T, st delivery.Step) string { +func workspaceOf(t *testing.T, st sdkstep.Step) string { var r struct { Workspace string `json:"workspace"` } diff --git a/modules/mesh-build-image/cmd/mesh-build-image/copy.go b/modules/mesh-build-image/cmd/mesh-build-image/copy.go index 62e4e7682..28655df7e 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/copy.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/copy.go @@ -23,9 +23,10 @@ import ( reg "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // CopyTool is the copy step's tool. @@ -90,7 +91,7 @@ func (m *Module) copy(ctx context.Context, args map[string]any) (any, error) { return nil, fmt.Errorf("not pinned: %s: %v; an upstream artifact is copied by the digest its manifest pins", name, err) } if m.Outcomes == nil || m.Outcomes.Waits == nil { - return nil, fmt.Errorf("%s%s: this process hears no outcome of the image seat", delivery.NotStored, name) + return nil, fmt.Errorf("%s%s: this process hears no outcome of the image seat", builds.NotStored, name) } key := MirrorWaitKey(digest) now := time.Now @@ -104,14 +105,14 @@ func (m *Module) copy(ctx context.Context, args map[string]any) (any, error) { heard, stop := m.Outcomes.Expect(digest) defer stop() if _, err := m.Outcomes.Waits.Put(key, asked); err != nil { - return nil, fmt.Errorf("%s%s: keeping the copy's wait in %s: %v", delivery.NotStored, name, MirrorWaitsState, err) + return nil, fmt.Errorf("%s%s: keeping the copy's wait in %s: %v", builds.NotStored, name, MirrorWaitsState, err) } defer m.Outcomes.drop(key, asked.Token) said := buildstep.NarrateSeat(ctx, buildstep.ImageSeat, "mirror of "+from) raw, err := m.call()("seat:"+buildstep.ImageSeat+"."+reg.VerbMirror, reg.MirrorInput{Name: module + "/" + name, Source: from, Digest: digest}) if err != nil { said.Refused(err) - return nil, fmt.Errorf("%s%s: %s's mirror: %v", delivery.NotStored, name, buildstep.ImageSeat, err) + return nil, fmt.Errorf("%s%s: %s's mirror: %v", builds.NotStored, name, buildstep.ImageSeat, err) } var answer reg.MirrorAnswer _ = json.Unmarshal(raw, &answer) @@ -139,10 +140,10 @@ func (m *Module) copy(ctx context.Context, args map[string]any) (any, error) { case <-bound: err := fmt.Errorf("%s said no outcome of the copy of %s in %s", buildstep.ImageSeat, from, wait) said.Refused(err) - return nil, fmt.Errorf("%s%s: %w", delivery.NotStored, name, err) + return nil, fmt.Errorf("%s%s: %w", builds.NotStored, name, err) case <-ctx.Done(): said.Refused(ctx.Err()) - return nil, fmt.Errorf("%s%s: stopped while waiting for the copy of %s: %w", delivery.NotStored, name, from, ctx.Err()) + return nil, fmt.Errorf("%s%s: stopped while waiting for the copy of %s: %w", builds.NotStored, name, from, ctx.Err()) } } } @@ -150,7 +151,7 @@ func (m *Module) copy(ctx context.Context, args map[string]any) (any, error) { // copyEnd is a copy's end on the outcome kept for it. func copyEnd(name string, o MirrorOutcome, asked string) (any, error) { if o.Event == reg.EventRefused { - return nil, fmt.Errorf("%s%s: %s refused the copy: %s", delivery.NotStored, name, buildstep.ImageSeat, o.Reason) + return nil, fmt.Errorf("%s%s: %s refused the copy: %s", builds.NotStored, name, buildstep.ImageSeat, o.Reason) } ref := o.Reference if ref == "" { @@ -377,7 +378,7 @@ func (m *Module) Plain(tool string, run func(ctx context.Context, args map[strin if err != nil { return nil, err } - key, _ := delivery.StepKey(m.Node, id) - return map[string]any{"step": id, "key": key, "state": delivery.StepRunning}, nil + key, _ := sdkstep.StepKey(m.Node, id) + return map[string]any{"step": id, "key": key, "state": sdkstep.StepRunning}, nil } } diff --git a/modules/mesh-build-image/cmd/mesh-build-image/copy_test.go b/modules/mesh-build-image/cmd/mesh-build-image/copy_test.go index 7cb7b05b0..bd5624766 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/copy_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/copy_test.go @@ -7,17 +7,17 @@ import ( "time" reg "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" - "git.novox.be/novox/mesh-sdk/go/delivery" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) -func runCopy(t *testing.T, m *Module, states *keptStates, args map[string]any) (CopyResult, delivery.Step) { +func runCopy(t *testing.T, m *Module, states *keptStates, args map[string]any) (CopyResult, sdkstep.Step) { t.Helper() if _, err := tool(t, m, CopyTool)(args); err != nil { t.Fatal(err) } st := states.waitEnd(t) var res CopyResult - if st.State == delivery.StepPassed { + if st.State == sdkstep.StepPassed { if err := json.Unmarshal(st.Result, &res); err != nil { t.Fatal(err) } @@ -67,7 +67,7 @@ func TestTheCopyIsTheImageSeatsMirrorAndEndsOnItsOutcome(t *testing.T) { f.atAsk = func() { asked, _ = m.Waiting() } res, st := runCopy(t, m, states, map[string]any{"module": "nats", "artifact": "server", "from": c.from}) if c.reason != "" { - if st.State != delivery.StepFailed || !strings.Contains(st.Reason, c.reason) { + if st.State != sdkstep.StepFailed || !strings.Contains(st.Reason, c.reason) { t.Fatalf("step = %+v, want failed with %q", st, c.reason) } if c.reason == "not pinned: server" && len(f.mirrors) != 0 { @@ -75,7 +75,7 @@ func TestTheCopyIsTheImageSeatsMirrorAndEndsOnItsOutcome(t *testing.T) { } return } - if st.State != delivery.StepPassed || res.Digest != d || !res.Pushed || + if st.State != sdkstep.StepPassed || res.Digest != d || !res.Pushed || res.Reference != reg.Seat+"/upstream/nats/server@"+d { t.Fatalf("step = %+v result = %+v", st, res) } diff --git a/modules/mesh-build-image/cmd/mesh-build-image/fetch_test.go b/modules/mesh-build-image/cmd/mesh-build-image/fetch_test.go index f4d7d3e62..8625c88fa 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/fetch_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/fetch_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "git.novox.be/novox/mesh-sdk/go/delivery" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // 1703b: the fetch step asks git, through the SDK's FetchCommit, for the ssh remote of the forge as the account, makes @@ -20,11 +20,11 @@ func TestFetchAsksGitForTheSshRemoteIntoAWorkspace(t *testing.T) { if err != nil { t.Fatal(err) } - if a := ans.(map[string]any); a["state"] != delivery.StepRunning || a["step"] == "" { + if a := ans.(map[string]any); a["state"] != sdkstep.StepRunning || a["step"] == "" { t.Errorf("the call answered %v, want a running step", a) } st := states.waitEnd(t) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("step = %+v", st) } var res FetchResult @@ -60,7 +60,7 @@ func TestFetchRefusesWhatIsNotARepositoryOrACommit(t *testing.T) { if _, err := tool(t, m, FetchTool)(args); err != nil { t.Fatal(err) } - if st := states.waitEnd(t); st.State != delivery.StepFailed { + if st := states.waitEnd(t); st.State != sdkstep.StepFailed { t.Errorf("%s: step = %+v, want failed", name, st) } } diff --git a/modules/mesh-build-image/cmd/mesh-build-image/helpers_test.go b/modules/mesh-build-image/cmd/mesh-build-image/helpers_test.go index 227341ea1..024543477 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/helpers_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/helpers_test.go @@ -16,7 +16,7 @@ import ( stdio "git.novox.be/novox/mesh-sdk/go" reg "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" - "git.novox.be/novox/mesh-sdk/go/delivery" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" ) @@ -25,29 +25,29 @@ const commitSHA = "0123456789abcdef0123456789abcdef01234567" // keptStates is the steps state, kept in memory: every write of a key, and the keys that ended. type keptStates struct { mu sync.Mutex - steps map[string][]delivery.Step + steps map[string][]sdkstep.Step ended chan string } func newStates() *keptStates { - return &keptStates{steps: map[string][]delivery.Step{}, ended: make(chan string, 16)} + return &keptStates{steps: map[string][]sdkstep.Step{}, ended: make(chan string, 16)} } func (s *keptStates) putStep(key string, value any) (uint64, error) { - st, err := delivery.DecodeStep(value.(json.RawMessage)) + st, err := sdkstep.DecodeStep(value.(json.RawMessage)) if err != nil { return 0, err } s.mu.Lock() s.steps[key] = append(s.steps[key], st) s.mu.Unlock() - if st.State != delivery.StepRunning { + if st.State != sdkstep.StepRunning { s.ended <- key } return 1, nil } -func (s *keptStates) waitEnd(t *testing.T) delivery.Step { +func (s *keptStates) waitEnd(t *testing.T) sdkstep.Step { t.Helper() select { case key := <-s.ended: @@ -57,7 +57,7 @@ func (s *keptStates) waitEnd(t *testing.T) delivery.Step { return v[len(v)-1] case <-time.After(5 * time.Second): t.Fatal("the step never ended on its key") - return delivery.Step{} + return sdkstep.Step{} } } diff --git a/modules/mesh-build-image/cmd/mesh-build-image/integration_test.go b/modules/mesh-build-image/cmd/mesh-build-image/integration_test.go index da2d9d717..7bc292767 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/integration_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/integration_test.go @@ -19,7 +19,7 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) func needTools(t *testing.T, what string, tools ...string) { @@ -91,7 +91,7 @@ func TestFetchOnARealRepository(t *testing.T) { t.Fatal(err) } st := waitLong(t, states) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("step = %+v", st) } var res FetchResult @@ -106,7 +106,7 @@ func TestFetchOnARealRepository(t *testing.T) { } } -func waitLong(t *testing.T, s *keptStates) delivery.Step { +func waitLong(t *testing.T, s *keptStates) sdkstep.Step { t.Helper() select { case key := <-s.ended: @@ -116,7 +116,7 @@ func waitLong(t *testing.T, s *keptStates) delivery.Step { return v[len(v)-1] case <-time.After(5 * time.Minute): t.Fatal("the step never ended on its key") - return delivery.Step{} + return sdkstep.Step{} } } @@ -133,14 +133,14 @@ func imageModule(t *testing.T, m *Module, dockerfile string, files map[string]st } } -func buildReal(t *testing.T, m *Module, states *keptStates) (BuildResult, delivery.Step) { +func buildReal(t *testing.T, m *Module, states *keptStates) (BuildResult, sdkstep.Step) { t.Helper() if _, err := tool(t, m, BuildTool)(map[string]any{"workspace": "ws1", "module": "modules/img", "artifact": "server"}); err != nil { t.Fatal(err) } st := waitLong(t, states) var res BuildResult - if st.State == delivery.StepPassed { + if st.State == sdkstep.StepPassed { if err := json.Unmarshal(st.Result, &res); err != nil { t.Fatal(err) } @@ -154,7 +154,7 @@ func TestARealBuildAnswersTheImagesDigest(t *testing.T) { m, states := realModule(t) imageModule(t, m, "FROM scratch\nCOPY hello.txt /hello.txt\n", map[string]string{"hello.txt": "hello\n"}) res, st := buildReal(t, m, states) - if st.State != delivery.StepPassed || !digestOK.MatchString(res.Digest) { + if st.State != sdkstep.StepPassed || !digestOK.MatchString(res.Digest) { t.Fatalf("step = %+v result = %+v", st, res) } } @@ -191,17 +191,17 @@ func TestARealBuildIsRootlessWithNoSocketAndNoWayOut(t *testing.T) { "RUN awk 'NR==1 { exit ($2 == 0) }' /proc/self/uid_map\n"+ "RUN ! ls /var/run/docker.sock /run/docker.sock /run/podman/podman.sock /run/containerd/containerd.sock 2>/dev/null\n"+ "RUN ! grep -E 'docker.sock|podman.sock|containerd.sock' /proc/self/mountinfo\n", nil) - if _, st := buildReal(t, m, states); st.State != delivery.StepPassed { + if _, st := buildReal(t, m, states); st.State != sdkstep.StepPassed { t.Errorf("the isolation checks inside the build failed: %+v", st) } // A step that writes outside its workspace fails: the context cannot be left, and the host's kernel files are not writable. imageModule(t, m, "FROM "+base+"\nCOPY ../outside /outside\n", nil) - if _, st := buildReal(t, m, states); st.State != delivery.StepFailed { + if _, st := buildReal(t, m, states); st.State != sdkstep.StepFailed { t.Errorf("a COPY out of the context passed: %+v", st) } imageModule(t, m, "FROM "+base+"\nRUN echo b > /proc/sysrq-trigger\n", nil) - if _, st := buildReal(t, m, states); st.State != delivery.StepFailed { + if _, st := buildReal(t, m, states); st.State != sdkstep.StepFailed { t.Errorf("a write to the host's /proc/sysrq-trigger passed: %+v", st) } else if strings.Contains(st.Reason, "setup network") { t.Errorf("the RUN never started, so the write was not what failed (issue 1703): %s", st.Reason) @@ -220,7 +220,7 @@ func TestARealBuildFindsNoCredentialsOfTheAccount(t *testing.T) { "RUN ! find / -xdev -name mesh_ed25519 2>/dev/null | grep .\n"+ "RUN ! test -e /root/.ssh\n"+ "RUN ! env | grep -E 'REGISTRY_AUTH|MESH_|SSH_AUTH'\n", nil) - if _, st := buildReal(t, m, states); st.State != delivery.StepPassed { + if _, st := buildReal(t, m, states); st.State != sdkstep.StepPassed { t.Errorf("a step found a credential path of the account: %+v", st) } } diff --git a/modules/mesh-build-image/cmd/mesh-build-image/kit_test.go b/modules/mesh-build-image/cmd/mesh-build-image/kit_test.go index 2285829cb..9ddec6eac 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/kit_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/kit_test.go @@ -6,14 +6,14 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep/conformance" - sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" ) // 1890/AC7: the module's own start sweep (endLeftRunning, as main runs it) keeps the conformance kit's left-running // case: a step a previous process left running is ended at once and said, whatever its age, and a step of this process // is kept. func TestTheStartSweepEndsWhatAPreviousProcessLeft(t *testing.T) { - conformance.LeftRunning(t, func(ctx context.Context, scan sdkstep.Scan, node string, before time.Time, logf func(string, ...any)) { + conformance.LeftRunning(t, func(ctx context.Context, scan buildrun.Scan, node string, before time.Time, logf func(string, ...any)) { (&Module{Node: node}).endLeftRunning(ctx, scan, before, logf) }) } diff --git a/modules/mesh-build-image/cmd/mesh-build-image/main.go b/modules/mesh-build-image/cmd/mesh-build-image/main.go index 6d623d638..a84f46621 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/main.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/main.go @@ -9,14 +9,15 @@ package main import ( "context" "fmt" - reg "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" "os" "os/user" "strings" "time" + reg "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" + seat "git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildimage" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // The directories the module's manifest places outside its home (ADR 0466 §1): the workspaces, and buildah's image @@ -32,10 +33,10 @@ func main() { ctx := context.Background() m := &Module{ Node: strings.TrimSpace(os.Getenv("MESH_NODE")), - Steps: stdio.State(delivery.StepsState).Put, - ReadSteps: readOf(stdio.State(delivery.StepsState)), - Pauses: stdio.State(delivery.PausesState).Put, - ReadPauses: readOf(stdio.State(delivery.PausesState)), + Steps: stdio.State(seat.StateSteps).Put, + ReadSteps: readOf(stdio.State(seat.StateSteps)), + Pauses: stdio.State(sdkstep.PausesState).Put, + ReadPauses: readOf(stdio.State(sdkstep.PausesState)), Ctx: ctx, Say: logf, Work: WorkDir, diff --git a/modules/mesh-build-image/cmd/mesh-build-image/module.go b/modules/mesh-build-image/cmd/mesh-build-image/module.go index c31cba22b..69e592da7 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/module.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/module.go @@ -8,8 +8,8 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" "git.novox.be/novox/mesh-sdk/go/health" ) @@ -164,7 +164,7 @@ func (m *Module) Start(ctx context.Context) { m.Say("this machine cannot build images: %v", err) } m.CleanWorkspaces(m.clock()) - sdkstep.EndStaleRound(m.stepScan(), m.Node, m.Say) // asks past the step bound, on the module's own round (issue 1890) + buildrun.EndStaleRound(m.stepScan(), m.Node, m.Say) // asks past the step bound, on the module's own round (issue 1890) select { case <-ctx.Done(): return @@ -230,8 +230,8 @@ func (m *Module) Long(tool string, run func(ctx context.Context, args map[string if err != nil { return nil, err } - key, _ := delivery.StepKey(m.Node, id) - return map[string]any{"step": id, "key": key, "state": delivery.StepRunning}, nil + key, _ := sdkstep.StepKey(m.Node, id) + return map[string]any{"step": id, "key": key, "state": sdkstep.StepRunning}, nil } } diff --git a/modules/mesh-build-image/cmd/mesh-build-image/module_test.go b/modules/mesh-build-image/cmd/mesh-build-image/module_test.go index fe2c5f2f6..5ac356a5c 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/module_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/module_test.go @@ -8,7 +8,7 @@ import ( "strings" "testing" - "git.novox.be/novox/mesh-sdk/go/delivery" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" "git.novox.be/novox/mesh-sdk/go/health" ) @@ -167,7 +167,7 @@ func TestAStepOnAMachineThatCannotBuildEndsRefused(t *testing.T) { t.Fatal(err) } st := states.waitEnd(t) - if st.State != delivery.StepRefused || !strings.Contains(st.Reason, "/nonexistent/subgid") { + if st.State != sdkstep.StepRefused || !strings.Contains(st.Reason, "/nonexistent/subgid") { t.Errorf("step = %+v, want refused naming the file", st) } for _, l := range f.lines() { diff --git a/modules/mesh-build-image/cmd/mesh-build-image/publish.go b/modules/mesh-build-image/cmd/mesh-build-image/publish.go index 771a94d01..cdfd74c52 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/publish.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/publish.go @@ -19,9 +19,9 @@ import ( reg "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" ) // KindImage is the kind an image is published as on its seat. @@ -116,16 +116,16 @@ func (m *Module) publish(ctx context.Context, workspace, module, local string, r argv := append(m.storeFlags(), "push", "--digestfile", digestFile, local, "oci:"+dir) if r := m.Run(ctx, m.env(), "buildah", argv...); r.Status != 0 || r.Err != "" { m.sayFailure("buildah push of "+res.Artifact+" to its layout", r) - return nil, fmt.Errorf("%s%s: writing its layout: %s", delivery.NotStored, res.Artifact, cause(r)) + return nil, fmt.Errorf("%s%s: writing its layout: %s", builds.NotStored, res.Artifact, cause(r)) } img, err := readLayout(dir) if err != nil { - return nil, fmt.Errorf("%s%s: %w", delivery.NotStored, res.Artifact, err) + return nil, fmt.Errorf("%s%s: %w", builds.NotStored, res.Artifact, err) } // What buildah wrote is checked against the layout: a digest never goes out unchecked. raw, err := os.ReadFile(digestFile) if pushed := strings.TrimSpace(string(raw)); err != nil || pushed != img.Digest { - return nil, fmt.Errorf("%s%s: buildah wrote the digest %q (%v), but its layout's manifest is %s", delivery.NotStored, res.Artifact, pushed, err, img.Digest) + return nil, fmt.Errorf("%s%s: buildah wrote the digest %q (%v), but its layout's manifest is %s", builds.NotStored, res.Artifact, pushed, err, img.Digest) } name := module + "/" + res.Artifact q := KindImage @@ -136,7 +136,7 @@ func (m *Module) publish(ctx context.Context, workspace, module, local string, r Transfer: buildstep.TransferName(name, q, img.Digest)} sent, err := buildstep.PublishFiles(ctx, m.call(), buildstep.ImageSeat, in, img.Files) if err != nil { - return nil, fmt.Errorf("%s%s: %v", delivery.NotStored, res.Artifact, err) + return nil, fmt.Errorf("%s%s: %v", builds.NotStored, res.Artifact, err) } m.say("published %s on %s: %d of its %d parts sent, the rest held", name, buildstep.ImageSeat, len(sent.Parts), len(img.Files)) res.Digest, res.Pushed = img.Digest, true diff --git a/modules/mesh-build-image/cmd/mesh-build-image/publish_test.go b/modules/mesh-build-image/cmd/mesh-build-image/publish_test.go index 330416b4e..c7e51a66a 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/publish_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/publish_test.go @@ -9,14 +9,15 @@ import ( "testing" reg "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" - "git.novox.be/novox/mesh-sdk/go/delivery" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // 1703d/AC (ADR 0487 §5): a candidate's build leaves the image seat unchanged: nothing is written, nothing is asked. func TestACandidatesBuildLeavesTheRegistryUnchanged(t *testing.T) { m, f, states := setup(t, same) res, st := runBuild(t, m, states, nil) // no publish - if st.State != delivery.StepPassed || res.Pushed { + if st.State != sdkstep.StepPassed || res.Pushed { t.Fatalf("step = %+v result = %+v", st, res) } if len(f.called("push")) != 0 || len(f.published) != 0 { @@ -57,12 +58,12 @@ func TestATrunkBuildPublishesThroughTheImageSeatOnlyWhatTheHolderLacks(t *testin } res, st := runBuild(t, m, states, args) if c.reason != "" { - if (st.State != delivery.StepFailed && st.State != delivery.StepRefused) || !strings.Contains(st.Reason, c.reason) { + if (st.State != sdkstep.StepFailed && st.State != sdkstep.StepRefused) || !strings.Contains(st.Reason, c.reason) { t.Fatalf("step = %+v, want failed with %q", st, c.reason) } return } - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("step = %+v", st) } if !res.Pushed || res.Digest != f.pushed || res.Reference != reg.Seat+"/fixture-image/server@"+f.pushed { @@ -118,7 +119,7 @@ func TestATrunkBuildPublishesThroughTheImageSeatOnlyWhatTheHolderLacks(t *testin }) } m2, f2, states2 := setup(t, same) - if _, st := runBuild(t, m2, states2, map[string]any{"publish": true, "tag": "a/b:c"}); st.State != delivery.StepFailed || len(f2.called("bud")) != 0 { + if _, st := runBuild(t, m2, states2, map[string]any{"publish": true, "tag": "a/b:c"}); st.State != sdkstep.StepFailed || len(f2.called("bud")) != 0 { t.Errorf("a tag that is not one: step = %+v", st) } } @@ -128,7 +129,7 @@ func TestATrunkBuildPublishesThroughTheImageSeatOnlyWhatTheHolderLacks(t *testin func TestTheNumberedEventPublishesAHeldImageUnderItsVersion(t *testing.T) { digest := "sha256:" + strings.Repeat("ab", 32) numbered := func(kind, seat, digest string) []byte { - raw, err := delivery.EncodeVersionNumbered(delivery.VersionNumbered{Name: "fixture-image/server", Kind: kind, Version: "1.4.0", + raw, err := builds.EncodeVersionNumbered(builds.VersionNumbered{Name: "fixture-image/server", Kind: kind, Version: "1.4.0", Module: "fixture-image", Fingerprint: "fp", Commit: "c0", Digest: digest, Seat: seat}) if err != nil { t.Fatal(err) diff --git a/modules/mesh-build-image/cmd/mesh-build-image/read.go b/modules/mesh-build-image/cmd/mesh-build-image/read.go index 550a0d6f3..d0ef53194 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/read.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/read.go @@ -14,8 +14,8 @@ import ( "sync" "time" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // The read tools, named as the module is: build_image_ and the verb. @@ -97,26 +97,26 @@ func (m *Module) stepKey(id string) (string, error) { } id = rest } - return delivery.StepKey(m.Node, id) + return sdkstep.StepKey(m.Node, id) } // ReadStep is the stored value of this node's step id (state, reason, result). -func (m *Module) ReadStep(id string) (delivery.Step, error) { +func (m *Module) ReadStep(id string) (sdkstep.Step, error) { key, err := m.stepKey(id) if err != nil { - return delivery.Step{}, err + return sdkstep.Step{}, err } if m.ReadSteps.Get == nil { - return delivery.Step{}, fmt.Errorf("the steps state cannot be read here") + return sdkstep.Step{}, fmt.Errorf("the steps state cannot be read here") } raw, err := m.ReadSteps.Get(key) if err != nil { - return delivery.Step{}, err + return sdkstep.Step{}, err } if len(raw) == 0 { - return delivery.Step{}, fmt.Errorf("no step %s in the steps state", key) + return sdkstep.Step{}, fmt.Errorf("no step %s in the steps state", key) } - return delivery.DecodeStep(raw) + return sdkstep.DecodeStep(raw) } // StepLine is a step without its result: the list answers these. @@ -149,7 +149,7 @@ func (m *Module) RecentSteps(limit int) (lines []StepLine, cut bool, err error) own := keys[:0:0] for _, k := range keys { if strings.HasPrefix(k, m.Node+".") { - if node, _, err := delivery.ParseStepKey(k); err == nil && node == m.Node { + if node, _, err := sdkstep.ParseStepKey(k); err == nil && node == m.Node { own = append(own, k) } } @@ -163,12 +163,12 @@ func (m *Module) RecentSteps(limit int) (lines []StepLine, cut bool, err error) if err != nil { return nil, cut, err } - var steps []delivery.Step + var steps []sdkstep.Step for _, raw := range raws { if len(raw) == 0 { continue } - s, err := delivery.DecodeStep(raw) + s, err := sdkstep.DecodeStep(raw) if err != nil { continue // a value this module cannot read is not one of its own steps } diff --git a/modules/mesh-build-image/cmd/mesh-build-image/read_test.go b/modules/mesh-build-image/cmd/mesh-build-image/read_test.go index 61c6fc954..773e9b9b1 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/read_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/read_test.go @@ -8,14 +8,14 @@ import ( "testing" "time" - "git.novox.be/novox/mesh-sdk/go/delivery" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // The read tools answer what the steps state holds: a finished build's result is there, read by the step's id. func TestTheReadToolsAnswerAStepsResult(t *testing.T) { m, _, states := setup(t, same) res, st := runBuild(t, m, states, nil) - if st.State != delivery.StepPassed { + if st.State != sdkstep.StepPassed { t.Fatalf("step = %+v", st) } m.ReadSteps = StateRead{ @@ -36,7 +36,7 @@ func TestTheReadToolsAnswerAStepsResult(t *testing.T) { }, } got, err := m.ReadStep(st.ID) - if err != nil || got.State != delivery.StepPassed { + if err != nil || got.State != sdkstep.StepPassed { t.Fatalf("ReadStep = %+v, %v", got, err) } var back BuildResult @@ -67,7 +67,7 @@ func TestRecentStepsReadsOnlyTheNodesKeysInParallelAndBounded(t *testing.T) { stored := map[string][]byte{} for _, n := range []string{"ace", "g14", "novox", "shanks"} { for i := 0; i < row.perNode; i++ { - b, _ := delivery.EncodeStep(delivery.Step{ID: fmt.Sprintf("s%04d", i), Tool: "t", Node: n, State: delivery.StepPassed, Started: t0.Add(time.Duration(i) * time.Second)}) + b, _ := sdkstep.EncodeStep(sdkstep.Step{ID: fmt.Sprintf("s%04d", i), Tool: "t", Node: n, State: sdkstep.StepPassed, Started: t0.Add(time.Duration(i) * time.Second)}) stored[n+".s"+fmt.Sprintf("%04d", i)] = b } } diff --git a/modules/mesh-build-image/cmd/mesh-build-image/room_test.go b/modules/mesh-build-image/cmd/mesh-build-image/room_test.go index dffa5b1d0..216f0636f 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/room_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/room_test.go @@ -9,7 +9,7 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" "git.novox.be/novox/mesh-sdk/go/health" ) @@ -43,7 +43,7 @@ func TestUnderTheFloorAFetchAndABuildAreRefusedAndTheModuleIsUnhealthy(t *testin if _, err := tool(t, m, name)(args); err != nil { t.Fatalf("%s: %v", name, err) } - if st := states.waitEnd(t); st.State != delivery.StepRefused || !strings.HasPrefix(st.Reason, underTheFloor) { + if st := states.waitEnd(t); st.State != sdkstep.StepRefused || !strings.HasPrefix(st.Reason, underTheFloor) { t.Errorf("%s ended %s: %q, want refused: %q", name, st.State, st.Reason, underTheFloor) } } @@ -87,7 +87,7 @@ func TestAFailedFetchLeavesNoWorkspace(t *testing.T) { if _, err := tool(t, m, FetchTool)(map[string]any{"repository": "novox/mesh-catalog", "commit": commitSHA}); err != nil { t.Fatal(err) } - if st := states.waitEnd(t); st.State != delivery.StepFailed { + if st := states.waitEnd(t); st.State != sdkstep.StepFailed { t.Fatalf("the step ended %s (%s), want failed", st.State, st.Reason) } if entries, _ := os.ReadDir(m.Work); len(entries) != 0 { From 941959198e89d96b074978b01dc6c89f62683671 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 5 Nov 2026 16:07:50 +0100 Subject: [PATCH 4/6] =?UTF-8?q?mesh-build-node=20runs=20its=20asks=20on=20?= =?UTF-8?q?the=20Delivery=20SDK's=20neutral=20build=20ask,=20step=20and=20?= =?UTF-8?q?answer=20forms=20instead=20of=20mesh-sdk's=20go/delivery;=20its?= =?UTF-8?q?=20state=20names=20are=20its=20seat's;=20the=20three=20build=20?= =?UTF-8?q?modules=20require=20the=20contracts=20they=20import=20(B5i;=20A?= =?UTF-8?q?DR=200634=20=C2=A71,=20=C2=A76;=20issue=201966)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i --- modules/mesh-build-go/buildstep/go.mod | 2 ++ modules/mesh-build-go/go.mod | 3 ++ modules/mesh-build-image/go.mod | 2 ++ .../cmd/mesh-build-node/asks.go | 27 +++++++------- .../cmd/mesh-build-node/asks_test.go | 23 ++++++------ .../cmd/mesh-build-node/build.go | 4 +-- .../cmd/mesh-build-node/kit_test.go | 3 +- .../cmd/mesh-build-node/main.go | 15 ++++---- .../cmd/mesh-build-node/module.go | 8 ++--- .../cmd/mesh-build-node/module_test.go | 25 ++++++------- .../cmd/mesh-build-node/package.go | 6 ++-- .../cmd/mesh-build-node/package_test.go | 10 +++--- .../cmd/mesh-build-node/publish_test.go | 4 +-- .../cmd/mesh-build-node/push_test.go | 4 +-- .../cmd/mesh-build-node/read.go | 29 +++++++-------- .../cmd/mesh-build-node/read_test.go | 35 ++++++++++--------- .../cmd/mesh-build-node/room_test.go | 4 +-- .../mesh-build-node/store_integration_test.go | 8 ++--- modules/mesh-build-node/go.mod | 2 ++ 19 files changed, 114 insertions(+), 100 deletions(-) diff --git a/modules/mesh-build-go/buildstep/go.mod b/modules/mesh-build-go/buildstep/go.mod index 580b727c9..c665053bf 100644 --- a/modules/mesh-build-go/buildstep/go.mod +++ b/modules/mesh-build-go/buildstep/go.mod @@ -3,6 +3,8 @@ module git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep go 1.26.0 require ( + git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildgo v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildnode v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildimage v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/sdk v0.0.0-00010101000000-000000000000 diff --git a/modules/mesh-build-go/go.mod b/modules/mesh-build-go/go.mod index 273571808..58852098a 100644 --- a/modules/mesh-build-go/go.mod +++ b/modules/mesh-build-go/go.mod @@ -3,6 +3,9 @@ module meshbuildgo go 1.26.0 require ( + git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildgo v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdeliverychecker v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/sdk v0.0.0-00010101000000-000000000000 diff --git a/modules/mesh-build-image/go.mod b/modules/mesh-build-image/go.mod index 34afdabbe..c139be8fd 100644 --- a/modules/mesh-build-image/go.mod +++ b/modules/mesh-build-image/go.mod @@ -3,6 +3,8 @@ module meshbuildimage go 1.26.0 require ( + git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildimage v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/sdk v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep v0.0.0 diff --git a/modules/mesh-build-node/cmd/mesh-build-node/asks.go b/modules/mesh-build-node/cmd/mesh-build-node/asks.go index ef6037ec5..9afc6a576 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/asks.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/asks.go @@ -6,9 +6,10 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + seat "git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildnode" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // **The module pulls its seat's asks** (novox/hq ADR 0525 §2-§6, ADR 0536 §4; issue 1887 A3node), as mesh-build-go @@ -31,12 +32,12 @@ func (m *Module) askSteps(steps []StepTool) buildstep.AskSteps { return buildstep.AskSteps{ Fetch: byName["build_node_fetch"], Build: byName["build_node_build"], Test: byName["build_node_test"], Compare: buildstep.CompareStep(buildstep.GeneratedRootTS, func(ws string) string { return filepath.Join(m.Work, ws, "tree") }), - Toolchain: func(ctx context.Context) (delivery.ToolchainUsed, error) { + Toolchain: func(ctx context.Context) (sdkstep.ToolchainUsed, error) { installed, err := m.Probe(ctx) if err != nil { - return delivery.ToolchainUsed{}, err + return sdkstep.ToolchainUsed{}, err } - return delivery.ToolchainUsed{Version: installed, Recipe: m.recipe().Version()}, nil + return sdkstep.ToolchainUsed{Version: installed, Recipe: m.recipe().Version()}, nil }, Release: func(ws string) error { return m.spaces().Release(ws) }, Logf: m.Say, @@ -46,7 +47,7 @@ func (m *Module) askSteps(steps []StepTool) buildstep.AskSteps { // Puller is the module's pull of its seat's asks, on source (the runtime's seat pull when nil). func (m *Module) Puller(steps []StepTool, source buildstep.AskSource) *buildstep.Puller { if source == nil { - source = buildstep.SeatAsks{Language: delivery.AskNode} + source = buildstep.SeatAsks{Language: sdkstep.AskNode} } capacity := m.Capacity // The capacity's own change wakes the puller (issue 1887): the runtime's watch of the config value as mesh-config @@ -64,16 +65,16 @@ func (m *Module) Puller(steps []StepTool, source buildstep.AskSource) *buildstep capacity = buildstep.NodeCapacity(m.Settings, m.Node, m.Say) settings = m.Settings watch = buildstep.WatchConfigServed - cores = buildstep.NodeCoresPerStep(m.Settings, buildstep.DefaultCoresPerStep[delivery.AskNode], m.Say) + cores = buildstep.NodeCoresPerStep(m.Settings, buildstep.DefaultCoresPerStep[sdkstep.AskNode], m.Say) } ask := m.askSteps(steps) var load func(string) ([]byte, error) if m.ReadPauses.Get != nil { load = func(key string) ([]byte, error) { return m.ReadPauses.Get(key) } } - return &buildstep.Puller{Source: source, Language: delivery.AskNode, Node: m.Node, Put: m.Steps, PausePut: m.Pauses, Load: load, + return &buildstep.Puller{Source: source, Language: sdkstep.AskNode, Node: m.Node, Put: m.Steps, PausePut: m.Pauses, Load: load, Capacity: capacity, SettingsFile: settings, WatchConfig: watch, CoresPerStep: cores, BuildHours: hours, Logf: m.Say, - Run: func(ctx context.Context, a delivery.StepAsk) (any, error) { + Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) { if err := m.Prepare(ctx); err != nil { return nil, err } @@ -93,13 +94,13 @@ func (m *Module) SeatTools(p *buildstep.Puller) []stdio.Tool { const StepEndTool = "build_node_step_end" // endLeftRunning is the module's start sweep (issue 1890): it ends the steps of its node that a previous process left -// running (sdkstep.EndStaleAtStart; every step names its owner). main runs it once at the start, and the module's test +// running (buildrun.EndStaleAtStart; every step names its owner). main runs it once at the start, and the module's test // runs it through the conformance kit's left-running case. -func (m *Module) endLeftRunning(ctx context.Context, scan sdkstep.Scan, booted time.Time, logf func(string, ...any)) { - sdkstep.EndStaleAtStart(ctx, scan, m.Node, booted, logf) +func (m *Module) endLeftRunning(ctx context.Context, scan buildrun.Scan, booted time.Time, logf func(string, ...any)) { + buildrun.EndStaleAtStart(ctx, scan, m.Node, booted, logf) } // stepScan is the module's steps state as buildstep reads it. -func (m *Module) stepScan() sdkstep.Scan { - return sdkstep.ScanOf(stdio.State(delivery.StepsState)) +func (m *Module) stepScan() buildrun.Scan { + return buildrun.ScanOf(stdio.State(seat.StateSteps)) } diff --git a/modules/mesh-build-node/cmd/mesh-build-node/asks_test.go b/modules/mesh-build-node/cmd/mesh-build-node/asks_test.go index 6478684c5..3b02e0b23 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/asks_test.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/asks_test.go @@ -12,7 +12,6 @@ import ( "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" ) const askCommit = "0123456789abcdef0123456789abcdef01234567" @@ -31,14 +30,14 @@ func fakeSteps(calls *[]string) []StepTool { } } -func nodeAsk(kind string) delivery.StepAsk { - a := delivery.StepAsk{ID: sdkstep.NewID(), Kind: kind, Language: delivery.AskNode, Asker: "mesh-delivery-checker", At: time.Now()} - fetch := map[string]any{"repository": "novox/mesh-catalog", "commit": askCommit} - if kind == delivery.AskDelivery { +func nodeAsk(kind string) sdkstep.StepAsk { + a := sdkstep.StepAsk{ID: sdkstep.NewID(), Kind: kind, Language: sdkstep.AskNode, Asker: "mesh-delivery-checker", At: time.Now()} + fetch := sdkstep.Fetch{Repository: "novox/mesh-catalog", Commit: askCommit} + if kind == sdkstep.AskDelivery { a.Asker = "mesh-delivery-builder" - a.Build = &delivery.BuildJob{Module: "gitea", Path: "modules/gitea", Fetch: fetch, Artifacts: []delivery.AskArtifact{{Artifact: "code"}}} + a.Build = &sdkstep.BuildJob{Module: "gitea", Path: "modules/gitea", Fetch: &fetch, Artifacts: []sdkstep.AskArtifact{{Artifact: "code"}}} } else { - a.Check = &delivery.CheckJob{Fetch: fetch, Levels: []string{delivery.LevelUnit}} + a.Check = &sdkstep.CheckJob{Fetch: fetch, Levels: []string{sdkstep.LevelUnit}} } return a } @@ -51,7 +50,7 @@ func TestAPulledNodeAskRunsItsJob(t *testing.T) { m.Capacity = func() int { return 1 } var calls []string src := buildstep.NewFakeAsks() - build, check := nodeAsk(delivery.AskDelivery), nodeAsk(delivery.AskCheck) + build, check := nodeAsk(sdkstep.AskDelivery), nodeAsk(sdkstep.AskCheck) _ = src.PublishAsk(check) _ = src.PublishAsk(build) p := m.Puller(fakeSteps(&calls), src) @@ -70,7 +69,7 @@ func TestAPulledNodeAskRunsItsJob(t *testing.T) { if got := strings.Join(calls, ","); got != "build_node_fetch,build_node_build,build_node_fetch,build_node_test" { t.Errorf("calls = %s, want the delivery ask's job first, then the check's", got) } - key, _ := delivery.AskStepKey("ace", build.ID) + key, _ := sdkstep.AskStepKey("ace", build.ID) states.mu.Lock() v := states.steps[key] states.mu.Unlock() @@ -92,10 +91,10 @@ func TestManifestTakesTheBuildCapacity(t *testing.T) { } _ = json.Unmarshal(raw, &doc) // Issue 1806's follow-up: the cores a step needs is a setting of its own, in the settings file, with the SDK's default. - if cores := string(doc.Config[buildstep.CoresPerStepSetting].Default); cores != fmt.Sprint(buildstep.DefaultCoresPerStep[delivery.AskNode]) { - t.Errorf("the cores-per-step default = %s, want %g", cores, buildstep.DefaultCoresPerStep[delivery.AskNode]) + if cores := string(doc.Config[buildstep.CoresPerStepSetting].Default); cores != fmt.Sprint(buildstep.DefaultCoresPerStep[sdkstep.AskNode]) { + t.Errorf("the cores-per-step default = %s, want %g", cores, buildstep.DefaultCoresPerStep[sdkstep.AskNode]) } - if got := buildstep.NodeCoresPerStep(moduleDir+"/files/settings.json", 0, nil)(); got != buildstep.DefaultCoresPerStep[delivery.AskNode] { + if got := buildstep.NodeCoresPerStep(moduleDir+"/files/settings.json", 0, nil)(); got != buildstep.DefaultCoresPerStep[sdkstep.AskNode] { t.Errorf("the settings template holds cores-per-step %g", got) } // And the build hours (the operator, 2026-10-26): a setting of their own, empty by default (any hour), in the template. diff --git a/modules/mesh-build-node/cmd/mesh-build-node/build.go b/modules/mesh-build-node/cmd/mesh-build-node/build.go index cc838fc3b..88bd2d48c 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/build.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/build.go @@ -18,9 +18,9 @@ import ( "strings" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // Out is where a bundle's compiled files go in the module's directory (builder toolchain.go:118). @@ -145,7 +145,7 @@ func (m *Module) build(ctx context.Context, args map[string]any) (any, error) { // Published from this process once the build ended, a candidate's as a trunk build's (ADR 0498 §1 §2; CAT-BN3): the // step answers the seat's reference, or fails not stored. The packed bytes are never written to the node (L9). if err := m.publishOn(ctx, buildstep.ArtifactSeat, a.module+"/"+a.Name, "bundle", "", digest, archive); err != nil { - return nil, fmt.Errorf("%s%s: %v", delivery.NotStored, a.Name, err) + return nil, fmt.Errorf("%s%s: %v", builds.NotStored, a.Name, err) } files := []string{} _ = filepath.WalkDir(bundleDir, func(p string, d os.DirEntry, err error) error { diff --git a/modules/mesh-build-node/cmd/mesh-build-node/kit_test.go b/modules/mesh-build-node/cmd/mesh-build-node/kit_test.go index c4d0201f0..d3799ea42 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/kit_test.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/kit_test.go @@ -6,6 +6,7 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep/conformance" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" ) @@ -25,7 +26,7 @@ func TestTheTestStepKeepsTheFailureContract(t *testing.T) { // case: a step a previous process left running is ended at once and said, whatever its age, and a step of this process // is kept. func TestTheStartSweepEndsWhatAPreviousProcessLeft(t *testing.T) { - conformance.LeftRunning(t, func(ctx context.Context, scan sdkstep.Scan, node string, before time.Time, logf func(string, ...any)) { + conformance.LeftRunning(t, func(ctx context.Context, scan buildrun.Scan, node string, before time.Time, logf func(string, ...any)) { (&Module{Node: node}).endLeftRunning(ctx, scan, before, logf) }) } diff --git a/modules/mesh-build-node/cmd/mesh-build-node/main.go b/modules/mesh-build-node/cmd/mesh-build-node/main.go index 3788d68d4..e5babf16d 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/main.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/main.go @@ -15,9 +15,10 @@ import ( "strings" "time" + seat "git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildnode" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" dforgekey "git.novox.be/novox/mesh-delivery/sdk/forgekey" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // CacheDir is the cache directory, outside the account's home (ADR 0466 §1; module.json resource `cache`). @@ -43,13 +44,13 @@ func main() { Reload: func() (Recipe, error) { return ReadRecipe(paths.LockPath()) }, Probe: ProbeNode, Toolchain: &Toolchain{Paths: paths, Run: dforgekey.ExecRunnerClean(0), Registry: registry}, - Toolchains: stdio.State(delivery.ToolchainsState).Put, + Toolchains: stdio.State(seat.StateToolchains).Put, Emit: func(t string, b any) error { return stdio.Emit(t, b) }, - Steps: stdio.State(delivery.StepsState).Put, - ReadSteps: readOf(stdio.State(delivery.StepsState)), - Pauses: stdio.State(delivery.PausesState).Put, - ReadPauses: readOf(stdio.State(delivery.PausesState)), - ReadToolchainsState: readOf(stdio.State(delivery.ToolchainsState)), + Steps: stdio.State(seat.StateSteps).Put, + ReadSteps: readOf(stdio.State(seat.StateSteps)), + Pauses: stdio.State(sdkstep.PausesState).Put, + ReadPauses: readOf(stdio.State(sdkstep.PausesState)), + ReadToolchainsState: readOf(stdio.State(seat.StateToolchains)), Work: WorkDir, Run: dforgekey.ExecRunnerClean(0), Ctx: ctx, diff --git a/modules/mesh-build-node/cmd/mesh-build-node/module.go b/modules/mesh-build-node/cmd/mesh-build-node/module.go index 09c8df399..03f3f0d12 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/module.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/module.go @@ -9,8 +9,8 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + buildrun "git.novox.be/novox/mesh-delivery/sdk/buildrun" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/forgekey" "git.novox.be/novox/mesh-sdk/go/health" ) @@ -139,7 +139,7 @@ func (m *Module) Start(ctx context.Context) { m.Say("the toolchain: %v", err) } m.CleanWorkspaces(m.now()) - sdkstep.EndStaleRound(m.stepScan(), m.Node, m.Say) // asks past the step bound, on the module's own round (issue 1890) + buildrun.EndStaleRound(m.stepScan(), m.Node, m.Say) // asks past the step bound, on the module's own round (issue 1890) select { case <-ctx.Done(): return @@ -190,8 +190,8 @@ func (m *Module) Long(tool string, run func(ctx context.Context, args map[string if err != nil { return nil, err } - key, _ := delivery.StepKey(m.Node, id) - return map[string]any{"step": id, "key": key, "state": delivery.StepRunning}, nil + key, _ := sdkstep.StepKey(m.Node, id) + return map[string]any{"step": id, "key": key, "state": sdkstep.StepRunning}, nil } } diff --git a/modules/mesh-build-node/cmd/mesh-build-node/module_test.go b/modules/mesh-build-node/cmd/mesh-build-node/module_test.go index e5fc60f33..606b04bb4 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/module_test.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/module_test.go @@ -11,24 +11,25 @@ import ( "testing" "time" - "git.novox.be/novox/mesh-sdk/go/delivery" + buildstep "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/health" ) // keptStates stands in for the toolchains and the steps states. type keptStates struct { mu sync.Mutex - toolchains map[string]delivery.Toolchain - steps map[string][]delivery.Step + toolchains map[string]buildstep.Toolchain + steps map[string][]sdkstep.Step ended chan string } func newStates() *keptStates { - return &keptStates{toolchains: map[string]delivery.Toolchain{}, steps: map[string][]delivery.Step{}, ended: make(chan string, 16)} + return &keptStates{toolchains: map[string]buildstep.Toolchain{}, steps: map[string][]sdkstep.Step{}, ended: make(chan string, 16)} } func (s *keptStates) putToolchain(key string, value any) (uint64, error) { - tc, err := delivery.DecodeToolchain(value.(json.RawMessage)) + tc, err := buildstep.DecodeToolchain(value.(json.RawMessage)) if err != nil { return 0, err } @@ -39,27 +40,27 @@ func (s *keptStates) putToolchain(key string, value any) (uint64, error) { } func (s *keptStates) putStep(key string, value any) (uint64, error) { - st, err := delivery.DecodeStep(value.(json.RawMessage)) + st, err := sdkstep.DecodeStep(value.(json.RawMessage)) if err != nil { return 0, err } s.mu.Lock() s.steps[key] = append(s.steps[key], st) s.mu.Unlock() - if st.State != delivery.StepRunning { + if st.State != sdkstep.StepRunning { s.ended <- key } return 1, nil } -func (s *keptStates) toolchain(key string) (delivery.Toolchain, bool) { +func (s *keptStates) toolchain(key string) (buildstep.Toolchain, bool) { s.mu.Lock() defer s.mu.Unlock() tc, ok := s.toolchains[key] return tc, ok } -func (s *keptStates) waitEnd(t *testing.T) delivery.Step { +func (s *keptStates) waitEnd(t *testing.T) sdkstep.Step { t.Helper() select { case key := <-s.ended: @@ -69,7 +70,7 @@ func (s *keptStates) waitEnd(t *testing.T) delivery.Step { return v[len(v)-1] case <-time.After(3 * time.Second): t.Fatal("the step never ended on its key") - return delivery.Step{} + return sdkstep.Step{} } } @@ -87,7 +88,7 @@ func TestStartWritesTheToolchainAndHealthIsHealthy(t *testing.T) { ctx, stop := context.WithCancel(context.Background()) defer stop() go m.Start(ctx) - var tc delivery.Toolchain + var tc buildstep.Toolchain for deadline := time.Now().Add(3 * time.Second); time.Now().Before(deadline); time.Sleep(5 * time.Millisecond) { if got, ok := states.toolchain("ace.typescript"); ok { tc = got @@ -130,7 +131,7 @@ func TestANodeThatCannotBeRunRefusesEveryStepAndHealthIsUnhealthy(t *testing.T) t.Fatalf("%s answered no step id: %v", tool.Name, out) } st := states.waitEnd(t) - if st.State != delivery.StepRefused { + if st.State != sdkstep.StepRefused { t.Errorf("%s: the step ended %s, want refused", tool.Name, st.State) } reason = st.Reason diff --git a/modules/mesh-build-node/cmd/mesh-build-node/package.go b/modules/mesh-build-node/cmd/mesh-build-node/package.go index d022b3010..9b36b502a 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/package.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/package.go @@ -31,7 +31,7 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "git.novox.be/novox/mesh-sdk/go/forgekey" ) @@ -365,7 +365,7 @@ func (m *Module) placeSDK(ctx context.Context, dir, rel string, group *packed, t if group != nil { return fmt.Errorf("the lock of %s names %s, which neither the registry nor the group (%s@%s) holds", rel, want, group.Name, group.Version) } - return fmt.Errorf("%s%s", delivery.WaitsFor, want) + return fmt.Errorf("%s%s", builds.WaitsFor, want) } if integrity != "" && integrityOf(got) != integrity { return fmt.Errorf("the registry's %s is %s, and the lock of %s names %s", want, integrityOf(got), rel, integrity) @@ -550,7 +550,7 @@ func (m *Module) buildPackage(ctx context.Context, workspace, module, root, dir return res, nil } if err := m.publishOn(ctx, seat, p.Name, "package", p.Version, p.Digest, p.tgz); err != nil { - return nil, fmt.Errorf("%s%s: %v", delivery.NotStored, a.Name, err) + return nil, fmt.Errorf("%s%s: %v", builds.NotStored, a.Name, err) } res.Reference = p.Name + "@" + p.Version return res, nil diff --git a/modules/mesh-build-node/cmd/mesh-build-node/package_test.go b/modules/mesh-build-node/cmd/mesh-build-node/package_test.go index 09aa04b73..7340d7f85 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/package_test.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/package_test.go @@ -14,7 +14,7 @@ import ( "sync/atomic" "testing" - "git.novox.be/novox/mesh-sdk/go/delivery" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" ) // tgzOf is a packed npm package holding package/package.json of name@version and one more file. @@ -103,8 +103,8 @@ func TestAMemberGetsTheSDKVersionItsLockNamesOrWaitsForIt(t *testing.T) { } dir = memberLocking(t, "0.1.16", "sha512-x") err := m.placeSDK(context.Background(), dir, "modules/m", nil, nil) - if err == nil || err.Error() != delivery.WaitsFor+"@novox/mesh-sdk@0.1.16" { - t.Errorf("a version the registry lacks answered %v, want %s@novox/mesh-sdk@0.1.16", err, delivery.WaitsFor) + if err == nil || err.Error() != builds.WaitsFor+"@novox/mesh-sdk@0.1.16" { + t.Errorf("a version the registry lacks answered %v, want %s@novox/mesh-sdk@0.1.16", err, builds.WaitsFor) } dir = memberLocking(t, "0.1.15", "sha512-another") if err := m.placeSDK(context.Background(), dir, "modules/m", nil, nil); err == nil || !strings.Contains(err.Error(), "sha512-another") { @@ -134,7 +134,7 @@ func TestAMemberGetsTheSDKVersionItsLockNamesOrWaitsForIt(t *testing.T) { } dir = memberLocking(t, "0.1.15", integrityOf(held)) missing := &groupPackage{Name: sdkPackage, Version: "0.1.16-feat-x.9"} - if err := m.placeSDK(context.Background(), dir, "modules/m", nil, missing); err == nil || !strings.Contains(err.Error(), "0.1.16-feat-x.9") || strings.HasPrefix(err.Error(), delivery.WaitsFor) { + if err := m.placeSDK(context.Background(), dir, "modules/m", nil, missing); err == nil || !strings.Contains(err.Error(), "0.1.16-feat-x.9") || strings.HasPrefix(err.Error(), builds.WaitsFor) { t.Errorf("a tagged version the registry lacks answered %v, want it named and no wait", err) } } @@ -160,7 +160,7 @@ func TestTheGroupsPackageIsServedToAMemberLockingItsVersion(t *testing.T) { t.Errorf("a member locking the registry's 0.1.14 in a group: %v, placed %q", err, placedVersion(dir)) } dir = memberLocking(t, "0.1.13", "sha512-x") - if err := m.placeSDK(context.Background(), dir, "modules/m", group, nil); err == nil || !strings.Contains(err.Error(), "0.1.13") || !strings.Contains(err.Error(), "0.1.15") || strings.HasPrefix(err.Error(), delivery.WaitsFor) { + if err := m.placeSDK(context.Background(), dir, "modules/m", group, nil); err == nil || !strings.Contains(err.Error(), "0.1.13") || !strings.Contains(err.Error(), "0.1.15") || strings.HasPrefix(err.Error(), builds.WaitsFor) { t.Errorf("a version neither holds answered %v, want both named and no wait", err) } before := asked.Load() diff --git a/modules/mesh-build-node/cmd/mesh-build-node/publish_test.go b/modules/mesh-build-node/cmd/mesh-build-node/publish_test.go index 54a0b70a8..43e426a0a 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/publish_test.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/publish_test.go @@ -8,7 +8,7 @@ import ( "strings" "testing" - "git.novox.be/novox/mesh-sdk/go/delivery" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" ) const packageManifest = `{"module":"mesh-sdk","version":"1","build":{"artifacts":[{"name":"lib","kind":"package","language":"typescript","paths":["src","package.json"]}]}}` @@ -121,7 +121,7 @@ func TestATrunkPackageIsPublishedOnceAndAVersionTakenIsRefused(t *testing.T) { m, _, _ = packageMachine(t, tgz) withStore(t, m).fail = errors.New("refused: the builder did not number it") - if _, err = m.build(context.Background(), args); err == nil || !strings.HasPrefix(err.Error(), delivery.NotStored+"lib: ") { + if _, err = m.build(context.Background(), args); err == nil || !strings.HasPrefix(err.Error(), builds.NotStored+"lib: ") { t.Errorf("a refused publish: %v", err) } } diff --git a/modules/mesh-build-node/cmd/mesh-build-node/push_test.go b/modules/mesh-build-node/cmd/mesh-build-node/push_test.go index fa119c7de..4854a59e3 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/push_test.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/push_test.go @@ -14,9 +14,9 @@ import ( "testing" registry "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" ) // pushed are the blobs the fake holder took, by digest, for the tests that read an archive back. @@ -127,7 +127,7 @@ func TestARefusedPushFailsNotStoredAndNoPackedFileStays(t *testing.T) { } } _, err := m.build(context.Background(), buildArgs()) - if c.words != "" && (err == nil || !strings.HasPrefix(err.Error(), delivery.NotStored+"tools: ") || !strings.Contains(err.Error(), c.words)) { + if c.words != "" && (err == nil || !strings.HasPrefix(err.Error(), builds.NotStored+"tools: ") || !strings.Contains(err.Error(), c.words)) { t.Errorf("a refused publish answered %v", err) } var archives []string diff --git a/modules/mesh-build-node/cmd/mesh-build-node/read.go b/modules/mesh-build-node/cmd/mesh-build-node/read.go index 8c4463d8e..f2bebc8e0 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/read.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/read.go @@ -14,8 +14,9 @@ import ( "sync" "time" + buildstep "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // The read tools, named as the module is: build_node_ and the verb. @@ -98,26 +99,26 @@ func (m *Module) stepKey(id string) (string, error) { } id = rest } - return delivery.StepKey(m.Node, id) + return sdkstep.StepKey(m.Node, id) } // ReadStep is the stored value of this node's step id (state, reason, result). -func (m *Module) ReadStep(id string) (delivery.Step, error) { +func (m *Module) ReadStep(id string) (sdkstep.Step, error) { key, err := m.stepKey(id) if err != nil { - return delivery.Step{}, err + return sdkstep.Step{}, err } if m.ReadSteps.Get == nil { - return delivery.Step{}, fmt.Errorf("the steps state cannot be read here") + return sdkstep.Step{}, fmt.Errorf("the steps state cannot be read here") } raw, err := m.ReadSteps.Get(key) if err != nil { - return delivery.Step{}, err + return sdkstep.Step{}, err } if len(raw) == 0 { - return delivery.Step{}, fmt.Errorf("no step %s in the steps state", key) + return sdkstep.Step{}, fmt.Errorf("no step %s in the steps state", key) } - return delivery.DecodeStep(raw) + return sdkstep.DecodeStep(raw) } // StepLine is a step without its result: the list answers these. @@ -150,7 +151,7 @@ func (m *Module) RecentSteps(limit int) (lines []StepLine, cut bool, err error) own := keys[:0:0] for _, k := range keys { if strings.HasPrefix(k, m.Node+".") { - if node, _, err := delivery.ParseStepKey(k); err == nil && node == m.Node { + if node, _, err := sdkstep.ParseStepKey(k); err == nil && node == m.Node { own = append(own, k) } } @@ -164,12 +165,12 @@ func (m *Module) RecentSteps(limit int) (lines []StepLine, cut bool, err error) if err != nil { return nil, cut, err } - var steps []delivery.Step + var steps []sdkstep.Step for _, raw := range raws { if len(raw) == 0 { continue } - s, err := delivery.DecodeStep(raw) + s, err := sdkstep.DecodeStep(raw) if err != nil { continue // a value this module cannot read is not one of its own steps } @@ -191,7 +192,7 @@ func (m *Module) RecentSteps(limit int) (lines []StepLine, cut bool, err error) } // ReadToolchains is every key of the toolchains state (.) with its stored value. -func (m *Module) ReadToolchains() (map[string]delivery.Toolchain, error) { +func (m *Module) ReadToolchains() (map[string]buildstep.Toolchain, error) { if m.ReadToolchainsState.Keys == nil || m.ReadToolchainsState.Get == nil { return nil, fmt.Errorf("the toolchains state cannot be read here") } @@ -209,12 +210,12 @@ func (m *Module) ReadToolchains() (map[string]delivery.Toolchain, error) { if err != nil { return nil, err } - out := map[string]delivery.Toolchain{} + out := map[string]buildstep.Toolchain{} for i, raw := range raws { if len(raw) == 0 { continue } - t, err := delivery.DecodeToolchain(raw) + t, err := buildstep.DecodeToolchain(raw) if err != nil { return nil, fmt.Errorf("%s: %w", keys[i], err) } diff --git a/modules/mesh-build-node/cmd/mesh-build-node/read_test.go b/modules/mesh-build-node/cmd/mesh-build-node/read_test.go index a54951fb4..d4a047878 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/read_test.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/read_test.go @@ -10,7 +10,8 @@ import ( "testing" "time" - "git.novox.be/novox/mesh-sdk/go/delivery" + buildstep "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) // fakeState is a state as stored: key to raw value. @@ -29,13 +30,13 @@ func (f fakeState) read() StateRead { } } -func putStep(t *testing.T, f fakeState, s delivery.Step) { +func putStep(t *testing.T, f fakeState, s sdkstep.Step) { t.Helper() - b, err := delivery.EncodeStep(s) + b, err := sdkstep.EncodeStep(s) if err != nil { t.Fatal(err) } - key, _ := delivery.StepKey(s.Node, s.ID) + key, _ := sdkstep.StepKey(s.Node, s.ID) f[key] = b } @@ -60,22 +61,22 @@ func tool(t *testing.T, m *Module, name string) func(map[string]any) (any, error func TestStepToolAnswersTheStoredStep(t *testing.T) { steps := fakeState{} t0 := time.Date(2026, 10, 21, 9, 0, 0, 0, time.UTC) - putStep(t, steps, delivery.Step{ID: "abc1", Tool: "build_node_fetch", Node: "ace", State: delivery.StepPassed, Started: t0, Ended: t0.Add(time.Second), + putStep(t, steps, sdkstep.Step{ID: "abc1", Tool: "build_node_fetch", Node: "ace", State: sdkstep.StepPassed, Started: t0, Ended: t0.Add(time.Second), Result: json.RawMessage(`{"workspace":"w42"}`)}) - putStep(t, steps, delivery.Step{ID: "abc2", Tool: "build_node_test", Node: "ace", State: delivery.StepRefused, Started: t0, Reason: "node cannot be run"}) + putStep(t, steps, sdkstep.Step{ID: "abc2", Tool: "build_node_test", Node: "ace", State: sdkstep.StepRefused, Started: t0, Reason: "node cannot be run"}) m := readModule(steps, fakeState{}) for _, id := range []string{"abc1", "ace.abc1"} { out, err := tool(t, m, StepReadTool)(map[string]any{"id": id}) if err != nil { t.Fatal(err) } - st := out.(delivery.Step) - if st.State != delivery.StepPassed || string(st.Result) != `{"workspace":"w42"}` || st.Tool != "build_node_fetch" { + st := out.(sdkstep.Step) + if st.State != sdkstep.StepPassed || string(st.Result) != `{"workspace":"w42"}` || st.Tool != "build_node_fetch" { t.Errorf("id %s: step = %+v", id, st) } } out, _ := tool(t, m, StepReadTool)(map[string]any{"id": "abc2"}) - if st := out.(delivery.Step); st.State != delivery.StepRefused || st.Reason != "node cannot be run" { + if st := out.(sdkstep.Step); st.State != sdkstep.StepRefused || st.Reason != "node cannot be run" { t.Errorf("refused step = %+v", st) } } @@ -94,10 +95,10 @@ func TestStepToolRefusesAnUnknownOrForeignOrBadID(t *testing.T) { func TestStepsToolListsRecentStepsOfThisNode(t *testing.T) { steps := fakeState{} t0 := time.Date(2026, 10, 21, 9, 0, 0, 0, time.UTC) - putStep(t, steps, delivery.Step{ID: "a", Tool: "build_node_fetch", Node: "ace", State: delivery.StepPassed, Started: t0, Ended: t0, Result: json.RawMessage(`1`)}) - putStep(t, steps, delivery.Step{ID: "b", Tool: "build_node_test", Node: "ace", State: delivery.StepRunning, Started: t0.Add(time.Minute)}) - putStep(t, steps, delivery.Step{ID: "c", Tool: "build_node_build", Node: "ace", State: delivery.StepFailed, Started: t0.Add(2 * time.Minute), Reason: "boom", What: "check ask, novox/x@abc"}) - putStep(t, steps, delivery.Step{ID: "d", Tool: "build_node_build", Node: "g14", State: delivery.StepPassed, Started: t0.Add(time.Hour)}) + putStep(t, steps, sdkstep.Step{ID: "a", Tool: "build_node_fetch", Node: "ace", State: sdkstep.StepPassed, Started: t0, Ended: t0, Result: json.RawMessage(`1`)}) + putStep(t, steps, sdkstep.Step{ID: "b", Tool: "build_node_test", Node: "ace", State: sdkstep.StepRunning, Started: t0.Add(time.Minute)}) + putStep(t, steps, sdkstep.Step{ID: "c", Tool: "build_node_build", Node: "ace", State: sdkstep.StepFailed, Started: t0.Add(2 * time.Minute), Reason: "boom", What: "check ask, novox/x@abc"}) + putStep(t, steps, sdkstep.Step{ID: "d", Tool: "build_node_build", Node: "g14", State: sdkstep.StepPassed, Started: t0.Add(time.Hour)}) m := readModule(steps, fakeState{}) out, err := tool(t, m, StepsReadTool)(map[string]any{}) if err != nil { @@ -111,7 +112,7 @@ func TestStepsToolListsRecentStepsOfThisNode(t *testing.T) { if !slices.Equal(ids, []string{"c", "b", "a"}) { t.Errorf("ids = %v, want c b a", ids) } - if lines[0].Reason != "boom" || lines[0].What != "check ask, novox/x@abc" || lines[0].State != delivery.StepFailed { + if lines[0].Reason != "boom" || lines[0].What != "check ask, novox/x@abc" || lines[0].State != sdkstep.StepFailed { t.Errorf("first = %+v", lines[0]) } out, _ = tool(t, m, StepsReadTool)(map[string]any{"limit": float64(1)}) @@ -123,7 +124,7 @@ func TestStepsToolListsRecentStepsOfThisNode(t *testing.T) { // 1562 (1483/AC5): build_node_toolchains answers each toolchains key as stored. func TestToolchainsToolAnswersTheStoredKeys(t *testing.T) { tcs := fakeState{} - b, err := delivery.EncodeToolchain(delivery.Toolchain{Language: "typescript", Version: "v22.1.0", Recipe: "1", At: time.Date(2026, 10, 21, 9, 0, 0, 0, time.UTC)}) + b, err := buildstep.EncodeToolchain(buildstep.Toolchain{Language: "typescript", Version: "v22.1.0", Recipe: "1", At: time.Date(2026, 10, 21, 9, 0, 0, 0, time.UTC)}) if err != nil { t.Fatal(err) } @@ -133,7 +134,7 @@ func TestToolchainsToolAnswersTheStoredKeys(t *testing.T) { if err != nil { t.Fatal(err) } - got := out.(map[string]any)["toolchains"].(map[string]delivery.Toolchain) + got := out.(map[string]any)["toolchains"].(map[string]buildstep.Toolchain) if got["ace.typescript"].Version != "v22.1.0" || got["ace.typescript"].Recipe != "1" { t.Errorf("toolchains = %+v", got) } @@ -166,7 +167,7 @@ func TestRecentStepsReadsOnlyTheNodesKeysInParallelAndBounded(t *testing.T) { stored := map[string][]byte{} for _, n := range []string{"ace", "g14", "novox", "shanks"} { for i := 0; i < row.perNode; i++ { - b, _ := delivery.EncodeStep(delivery.Step{ID: fmt.Sprintf("s%04d", i), Tool: "t", Node: n, State: delivery.StepPassed, Started: t0.Add(time.Duration(i) * time.Second)}) + b, _ := sdkstep.EncodeStep(sdkstep.Step{ID: fmt.Sprintf("s%04d", i), Tool: "t", Node: n, State: sdkstep.StepPassed, Started: t0.Add(time.Duration(i) * time.Second)}) stored[n+".s"+fmt.Sprintf("%04d", i)] = b } } diff --git a/modules/mesh-build-node/cmd/mesh-build-node/room_test.go b/modules/mesh-build-node/cmd/mesh-build-node/room_test.go index 07bea7a4b..ae0266872 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/room_test.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/room_test.go @@ -9,7 +9,7 @@ import ( "time" "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" - "git.novox.be/novox/mesh-sdk/go/delivery" + sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" "git.novox.be/novox/mesh-sdk/go/forgekey" "git.novox.be/novox/mesh-sdk/go/health" ) @@ -44,7 +44,7 @@ func TestUnderTheFloorEveryStepIsRefusedAndTheModuleIsUnhealthy(t *testing.T) { if _, err := tool.Run(map[string]any{}); err != nil { t.Fatal(err) } - if st := states.waitEnd(t); st.State != delivery.StepRefused || !strings.HasPrefix(st.Reason, underTheFloor) { + if st := states.waitEnd(t); st.State != sdkstep.StepRefused || !strings.HasPrefix(st.Reason, underTheFloor) { t.Errorf("the long step ended %s: %q, want refused: %q", st.State, st.Reason, underTheFloor) } case "short_probe": diff --git a/modules/mesh-build-node/cmd/mesh-build-node/store_integration_test.go b/modules/mesh-build-node/cmd/mesh-build-node/store_integration_test.go index 703f7f9c0..1ee5f17ae 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/store_integration_test.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/store_integration_test.go @@ -21,8 +21,8 @@ import ( _ "github.com/distribution/distribution/v3/registry/storage/driver/inmemory" registry "git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/delivery" ) // realStore starts the artifact store's own program (the distribution registry, modules/distribution) inside this @@ -100,9 +100,9 @@ func TestADoneBundleResolvesInARealArtifactStore(t *testing.T) { t.Fatal(err) } r := out.(BuildResult) - done := delivery.BuilderBuild{V: 1, State: delivery.BuildDone, Manifest: strings.Repeat("0", 64), - Artifacts: []delivery.BuiltArtifact{{Name: "tools", Kind: "bundle", Digest: r.Digest, Reference: r.Reference}}} - if _, err := delivery.EncodeBuilderBuild(done); err != nil { + done := builds.BuilderBuild{V: 1, State: builds.BuildDone, Manifest: strings.Repeat("0", 64), + Artifacts: []builds.BuiltArtifact{{Name: "tools", Kind: "bundle", Digest: r.Digest, Reference: r.Reference}}} + if _, err := builds.EncodeBuilderBuild(done); err != nil { t.Errorf("the done key the builder would write is refused: %v", err) } if _, _, ok := catalogue.InRegistrySeat(r.Reference); !ok || !strings.HasSuffix(r.Reference, "@"+r.Digest) { diff --git a/modules/mesh-build-node/go.mod b/modules/mesh-build-node/go.mod index e9b7fff74..2aaefd4c3 100644 --- a/modules/mesh-build-node/go.mod +++ b/modules/mesh-build-node/go.mod @@ -3,6 +3,8 @@ module meshbuildnode go 1.26.0 require ( + git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildnode v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/sdk v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-delivery/contracts/go/seats/containerimageregistry v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep v0.0.0 From 8f1581f34afb0c19a8e62ba152a0d209d73257a9 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 5 Nov 2026 16:08:26 +0100 Subject: [PATCH 5/6] mesh-build-go: a seat's ask type runs as the neutral ask (AskOf, the step description, the fetch arguments) (B5i; issue 1966) Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i --- .../mesh-build-go/buildstep/askrun_test.go | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/modules/mesh-build-go/buildstep/askrun_test.go b/modules/mesh-build-go/buildstep/askrun_test.go index 07dfa08a3..25ddb3f05 100644 --- a/modules/mesh-build-go/buildstep/askrun_test.go +++ b/modules/mesh-build-go/buildstep/askrun_test.go @@ -10,6 +10,8 @@ import ( "testing" "time" + nodebuildgo "git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildgo" + nodebuildnode "git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildnode" sdkstep "git.novox.be/novox/mesh-delivery/sdk/buildstep" ) @@ -340,3 +342,32 @@ func TestRunAskRunsEveryPackageAndLevelAfterAFailure(t *testing.T) { t.Fatalf("calls %v, levels %+v: want b then a at each of the two levels", r.calls, a.Levels) } } + +// A seat's own ask type (the generated one of any of the three build seats) is the neutral ask through the form's one +// conversion (sdkstep.AskOf), reads for its step description through the same conversion (askRead), and reaches the +// fetch tool as the fetch's arguments alone: no layout version, nothing of the ask's. +func TestASeatsAskTypeRunsAsTheNeutralAsk(t *testing.T) { + at := time.Now().UTC() + fetch := &nodebuildgo.Fetch{Commit: runCommit, Repository: "novox/x", Dir: "modules/m", Paths: []string{"src"}} + goAsk := nodebuildgo.StepAsk{V: sdkstep.StepAskVersion, ID: sdkstep.NewID(), Kind: sdkstep.AskDelivery, Language: sdkstep.AskGo, Asker: "mesh-delivery-builder", At: &at, + Build: &nodebuildgo.StepAskBuild{Module: "m", Path: "modules/m", Fetch: fetch, Artifacts: []nodebuildgo.AskArtifact{{Artifact: "bundle"}}}, + Packages: map[string]string{"git.novox.be/novox/mesh-sdk/go": runCommit}} + a, err := sdkstep.AskOf(goAsk) + if err != nil { + t.Fatal(err) + } + if read := askRead(a); read.Kind != sdkstep.AskDelivery || read.Build == nil || read.Build.Module != "m" { + t.Errorf("the step description reads %+v", read) + } + r := &recorder{fetch: map[string]any{"workspace": "/w"}} + if _, err := RunAsk(context.Background(), r.steps(), a); err != nil { + t.Fatal(err) + } + want := `fetch {"commit":"` + runCommit + `","dir":"modules/m","packages":{"git.novox.be/novox/mesh-sdk/go":"` + runCommit + `"},"paths":["src"],"repository":"novox/x"}` + if len(r.calls) == 0 || r.calls[0] != want { + t.Errorf("the fetch tool was called with %v, want %s", r.calls, want) + } + if back, err := sdkstep.AskAs[nodebuildnode.StepAsk](a); err != nil || back.Build == nil || back.Build.Module != "m" { + t.Errorf("the ask as another seat's type: %+v, %v", back, err) + } +} From 634abead7d4669d060e69c45565b1594d8040aa7 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 5 Nov 2026 16:09:52 +0100 Subject: [PATCH 6/6] =?UTF-8?q?mesh-build-go,=20-image=20and=20-node=20dec?= =?UTF-8?q?lare=20the=20builder's=20published=20package=20builds,=20which?= =?UTF-8?q?=20they=20now=20read=20their=20forms=20and=20keys=20through=20(?= =?UTF-8?q?B5i;=20ADR=200634=20=C2=A71,=20=C2=A74;=20issue=201966)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i --- modules/mesh-build-go/cmd/mesh-build-go/manifest_test.go | 4 ++++ modules/mesh-build-go/module.json | 1 + .../mesh-build-image/cmd/mesh-build-image/manifest_test.go | 4 ++++ modules/mesh-build-image/module.json | 1 + modules/mesh-build-node/cmd/mesh-build-node/manifest_test.go | 4 ++++ modules/mesh-build-node/module.json | 1 + 6 files changed, 15 insertions(+) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/manifest_test.go b/modules/mesh-build-go/cmd/mesh-build-go/manifest_test.go index 1fd98b495..80ae3f70f 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/manifest_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/manifest_test.go @@ -52,6 +52,10 @@ func resource(t *testing.T, m catalogue.Manifest, id string) map[string]any { func TestManifestDeclaresTheAccountTheCapabilityAndThePackages(t *testing.T) { m := readManifest(t) // The key keeper is ssh-client's published package, taken by its series (ADR 0634 §1). + // The builder's step, answer and key forms are read through its published package, taken by its series (ADR 0634 §1). + if m.Packages["builds"] != "0.1" { + t.Errorf("packages %v: want builds of series 0.1", m.Packages) + } if m.Packages["sshkeys"] != "0.1" { t.Errorf("packages %v: want sshkeys of series 0.1", m.Packages) } diff --git a/modules/mesh-build-go/module.json b/modules/mesh-build-go/module.json index 799bf3c61..2530983d6 100644 --- a/modules/mesh-build-go/module.json +++ b/modules/mesh-build-go/module.json @@ -2,6 +2,7 @@ "module": "mesh-build-go", "version": "1", "packages": { + "builds": "0.1", "sshkeys": "0.1" }, "moved": true, diff --git a/modules/mesh-build-image/cmd/mesh-build-image/manifest_test.go b/modules/mesh-build-image/cmd/mesh-build-image/manifest_test.go index 8e4f161ca..887c89869 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/manifest_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/manifest_test.go @@ -54,6 +54,10 @@ func resource(t *testing.T, m catalogue.Manifest, id string) map[string]any { func TestManifestDeclaresTheAccountTheCapabilityAndThePackages(t *testing.T) { m := readManifest(t) // The key keeper is ssh-client's published package, taken by its series (ADR 0634 §1). + // The builder's step, answer and key forms are read through its published package, taken by its series (ADR 0634 §1). + if m.Packages["builds"] != "0.1" { + t.Errorf("packages %v: want builds of series 0.1", m.Packages) + } if m.Packages["sshkeys"] != "0.1" { t.Errorf("packages %v: want sshkeys of series 0.1", m.Packages) } diff --git a/modules/mesh-build-image/module.json b/modules/mesh-build-image/module.json index 737964a9b..a59828c11 100644 --- a/modules/mesh-build-image/module.json +++ b/modules/mesh-build-image/module.json @@ -2,6 +2,7 @@ "module": "mesh-build-image", "version": "1", "packages": { + "builds": "0.1", "sshkeys": "0.1" }, "moved": true, diff --git a/modules/mesh-build-node/cmd/mesh-build-node/manifest_test.go b/modules/mesh-build-node/cmd/mesh-build-node/manifest_test.go index e829b2cc0..fbac8729f 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/manifest_test.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/manifest_test.go @@ -47,6 +47,10 @@ func resource(t *testing.T, m catalogue.Manifest, id string) map[string]any { func TestManifestDeclaresTheAccountTheCapabilityAndThePackages(t *testing.T) { m := readManifest(t) // The key keeper is ssh-client's published package, taken by its series (ADR 0634 §1). + // The builder's step, answer and key forms are read through its published package, taken by its series (ADR 0634 §1). + if m.Packages["builds"] != "0.1" { + t.Errorf("packages %v: want builds of series 0.1", m.Packages) + } if m.Packages["sshkeys"] != "0.1" { t.Errorf("packages %v: want sshkeys of series 0.1", m.Packages) } diff --git a/modules/mesh-build-node/module.json b/modules/mesh-build-node/module.json index 574be27f8..c5b279ba2 100644 --- a/modules/mesh-build-node/module.json +++ b/modules/mesh-build-node/module.json @@ -2,6 +2,7 @@ "module": "mesh-build-node", "version": "1", "packages": { + "builds": "0.1", "sshkeys": "0.1" }, "moved": true,