From 357967308f9ff6add29e00a690edaa94b094e9a3 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 11 Nov 2026 11:00:52 +0100 Subject: [PATCH] BLD11: the three build modules take the version from the ask as MESH_VERSION; version.numbered is no longer heard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Go compile, the Node tsc/esbuild/npm and the image's buildah bud get the build argument MESH_VERSION from the version the build ask carries. The late publish on version.numbered goes (code, tests, the consumes of the Go and image manifests). The image's label and tag and a program's stamp are open (question to the lead): the design names no key or symbol. Builds: design 47 G §349, §370, §413 Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ --- .../mesh-build-go/buildstep/latepublish.go | 91 ------------------- .../mesh-build-go/cmd/mesh-build-go/build.go | 11 ++- .../cmd/mesh-build-go/build_test.go | 31 +++++++ .../cmd/mesh-build-go/latepublish.go | 27 ------ .../mesh-build-go/cmd/mesh-build-go/main.go | 2 - .../cmd/mesh-build-go/manifest_test.go | 6 +- .../cmd/mesh-build-go/publish_test.go | 54 ----------- modules/mesh-build-go/module.json | 3 - .../cmd/mesh-build-image/build.go | 4 + .../cmd/mesh-build-image/build_test.go | 17 ++++ .../cmd/mesh-build-image/compose_test.go | 4 +- .../cmd/mesh-build-image/latepublish.go | 23 ----- .../cmd/mesh-build-image/main.go | 2 - .../cmd/mesh-build-image/publish_test.go | 48 ---------- modules/mesh-build-image/module.json | 1 - .../cmd/mesh-build-node/build.go | 19 +++- .../cmd/mesh-build-node/build_test.go | 26 ++++++ .../cmd/mesh-build-node/package.go | 1 + 18 files changed, 106 insertions(+), 264 deletions(-) delete mode 100644 modules/mesh-build-go/buildstep/latepublish.go delete mode 100644 modules/mesh-build-go/cmd/mesh-build-go/latepublish.go delete mode 100644 modules/mesh-build-image/cmd/mesh-build-image/latepublish.go diff --git a/modules/mesh-build-go/buildstep/latepublish.go b/modules/mesh-build-go/buildstep/latepublish.go deleted file mode 100644 index 46bf19c2f..000000000 --- a/modules/mesh-build-go/buildstep/latepublish.go +++ /dev/null @@ -1,91 +0,0 @@ -package buildstep - -// **The late publish** (novox/hq ADR 0617 §1, design 51 *The versions*, *Publishing*; CAT-BG2, CAT-BI1): a trunk build -// whose number the builder did not know yet publishes its digest unnumbered; the builder says version.numbered once it -// numbers that fingerprint, and the build module publishes the held digest again under that version. Nothing travels: -// the publish names the one part by its digest, which the holder holds, so it answers held and tags the version (the -// holder asks builder_versions first, ADR 0605 §4). The bytes never stayed on the node, so a holder that no longer holds -// the digest is said and the event offered again. Every instance may hear the same event; the publish is the same call -// under the same transfer name, so a second one is answered held. One place for every build module: mesh-build-go's -// bundles and archives on oci-artifact-registry, mesh-build-image's images on container-image-registry. - -import ( - "context" - "errors" - "fmt" - "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" -) - -// NumberedPattern is the event type a build module consumes for the late publish, as its manifest's `consumes` names it. -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") - -// LatePublish publishes a numbered build's held digest under its version on seat, from the builder's version.numbered -// body, when its kind is one of kinds. It answers false, nil for an event that is not the module's to publish: another -// 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 := builds.DecodeVersionNumbered(body) - if err != nil { - return false, err - } - on := n.Seat - if on == "" { - on = ArtifactSeat - } - if n.Digest == "" || on != seat || !slices.Contains(kinds, n.Kind) { - return false, nil - } - in := reg.PublishInput{Name: n.Name, Kind: n.Kind, Version: n.Version, Tag: n.Tag, Digest: n.Digest, - Fingerprint: n.Fingerprint, Commit: n.Commit, Transfer: TransferName(n.Name, "v"+n.Version, n.Digest)} - sent, err := OnSeat(ctx, seat, "late publish of "+n.Name+" "+n.Version+" at "+n.Digest, func() (parts.Sent, error) { - return PublishParts(ctx, call, seat, in, []parts.Part{{Digest: n.Digest, - Open: func() (io.ReadCloser, error) { return nil, errNotHere }}}) - }, nil) - if err != nil { - return false, fmt.Errorf("the late publish of %s@%s (%s): %w", n.Name, n.Version, n.Digest, err) - } - if len(sent.Parts) > 0 { - return false, fmt.Errorf("the late publish of %s@%s sent parts it should not have", n.Name, n.Version) - } - return true, nil -} - -// HearNumbered subscribes late to the builder's version.numbered, asking again until the runtime takes it, and says -// each publish and each failure; an error is the event's, which is offered again. -func HearNumbered(ctx context.Context, late func(ctx context.Context, body []byte) (bool, error)) { - handle := func(e stdio.Envelope) error { - did, err := late(ctx, e.Body) - if err != nil { - log.Printf("%v", err) - return err - } - if did { - log.Printf("published a numbered build's held digest under its version (%s)", e.Headers["x-event-id"]) - } - return nil - } - for wait := 2 * time.Second; ; wait = min(wait*2, time.Minute) { - err := stdio.Subscribe(NumberedPattern, handle) - if err == nil { - log.Printf("listening for the builder's %s", NumberedPattern) - return - } - log.Printf("not hearing the builder's %s yet (%v); asking again in %s", NumberedPattern, err, wait) - select { - case <-ctx.Done(): - return - case <-time.After(wait): - } - } -} 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 466fae221..6a202317f 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/build.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/build.go @@ -54,7 +54,7 @@ func (m *Module) buildTool() StepTool { "workspace": map[string]any{"type": "string", "description": "the workspace id build_go_fetch answered"}, "module": map[string]any{"type": "string", "description": "the module's directory in the workspace, . for the repository's root"}, "artifact": map[string]any{"type": "string", "description": "the artifact's name in the module's manifest"}, - "version": map[string]any{"type": "string", "description": "the version the builder gave a package at the trunk's claim; absent for a candidate, whose package is not published"}, + "version": map[string]any{"type": "string", "description": "the version the build ask carries for the artifact: a Go package's tag, and the build argument MESH_VERSION of every artifact; absent for a candidate, whose package is not published"}, "seat": map[string]any{"type": "string", "description": "the registry seat the artifact is published through, as the build ask names it"}, "publish": map[string]any{"type": "boolean", "description": "true for a merged trunk commit alone: the build writes the shared Go caches; without it (a candidate) they are read beneath a throwaway layer"}, }, @@ -114,8 +114,9 @@ func (m *Module) build(ctx context.Context, args map[string]any) (any, error) { if art == nil { return nil, fmt.Errorf("the module %s has no artifact %q (it has %s)", manifest.Module, name, strings.Join(names, ", ")) } + // The version the build ask carries is the build's argument MESH_VERSION for every artifact (design 47 G §370). + version, _ := args["version"].(string) if art.Kind == catalogue.ArtifactPackage && art.Language == "go" { - version, _ := args["version"].(string) seat, _ := args["seat"].(string) return m.buildGoPackage(ctx, workspace, dir, *art, version, seat) } @@ -153,7 +154,11 @@ func (m *Module) build(ctx context.Context, args map[string]any) (any, error) { if err != nil { return nil, err } - if r := run(ctx, m.buildEnv(dir), "go", cmd...); r.Status != 0 || r.Err != "" { + env := m.buildEnv(dir) + if version != "" { + env = append(env, "MESH_VERSION="+version) + } + if r := run(ctx, env, "go", cmd...); r.Status != 0 || r.Err != "" { return nil, fmt.Errorf("go build of %s: %s", art.Name, causeLine(r.Err+"\n"+r.Stderr+"\n"+r.Stdout)) } if err := m.insideModule(workspace, dir, out); err != 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 16461569f..29dda3fbc 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 @@ -255,3 +255,34 @@ func TestAManifestFallingBackToAPredefinedKeyBuilds(t *testing.T) { t.Errorf("result = %+v", res) } } + +// Design 47 G §370 (BLD11): a build ask carrying a version gives the compile the build argument MESH_VERSION, and one +// without gives none. +func TestTheBuildGetsTheVersionTheAskCarriesAsMeshVersion(t *testing.T) { + for _, version := range []string{"1.4.3", ""} { + m, states, calls := buildModule(t, manifestWith(goBundle), "binary") + for _, tool := range m.Tools(m.StepTools()) { + if tool.Name == "build_go_build" { + if _, err := tool.Run(map[string]any{"workspace": "ws1", "module": "modules/demo", "artifact": "tools", "version": version}); err != nil { + t.Fatal(err) + } + } + } + if st := states.waitEnd(t); st.State != sdkstep.StepPassed { + t.Fatalf("the step ended %s: %s", st.State, st.Reason) + } + got := "" + for _, r := range *calls { + if strings.HasPrefix(r.line, "go ") { + for _, e := range r.env { + if strings.HasPrefix(e, "MESH_VERSION=") { + got = strings.TrimPrefix(e, "MESH_VERSION=") + } + } + } + } + if got != version { + t.Errorf("ask version %q: the compile's MESH_VERSION = %q", version, got) + } + } +} diff --git a/modules/mesh-build-go/cmd/mesh-build-go/latepublish.go b/modules/mesh-build-go/cmd/mesh-build-go/latepublish.go deleted file mode 100644 index 66c6d7123..000000000 --- a/modules/mesh-build-go/cmd/mesh-build-go/latepublish.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -// The late publish (CAT-BG2): a numbered bundle or archive's held digest published under its version, by the build -// modules' one late publish (buildstep/latepublish.go). - -import ( - "context" - - "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" - stdio "git.novox.be/novox/mesh-sdk/go" -) - -// NumberedPattern is the event type this module consumes for the late publish, as its manifest's `consumes` names it. -const NumberedPattern = buildstep.NumberedPattern - -// LatePublish publishes a numbered bundle or archive's held digest under its version on the artifact seat; a Go package -// publishes at its build, an image is mesh-build-image's. -func (m *Module) LatePublish(ctx context.Context, body []byte) (bool, error) { - call := m.Call - if call == nil { - call = stdio.Ask - } - return buildstep.LatePublish(ctx, call, body, ArtifactSeat, "bundle", "archive") -} - -// hearNumbered hears the builder's version.numbered for the late publish. -func (m *Module) hearNumbered(ctx context.Context) { buildstep.HearNumbered(ctx, m.LatePublish) } 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 3eae5fca1..bda976699 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/main.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/main.go @@ -88,8 +88,6 @@ func main() { if m.Node != "" { // The seat's asks, pulled once Serve has the runtime's channel; a pull before it is said and tried again. go func() { _ = puller.Pull(ctx) }() - // The builder's version.numbered, for the late publish of a held digest (latepublish.go). - go m.hearNumbered(ctx) } if err := stdio.Serve("", append(m.Tools(steps), m.SeatTools(puller)...)); err != nil { logf("%v", err) 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 57910c946..e717db4d4 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 @@ -186,9 +186,9 @@ func TestTheModuleInvokesTheArtifactSeatsVerbsAndWritesNoStore(t *testing.T) { } } } - // The late publish hears the builder's version.numbered (latepublish.go). - if !slices.Contains(m.Consumes, NumberedPattern) { - t.Errorf("consumes %v lack %s", m.Consumes, NumberedPattern) + // The version comes in the ask: no consume of version.numbered (design 47 G §349, §413). + if slices.Contains(m.Consumes, "mesh-delivery-builder.version.numbered") { + t.Errorf("consumes %v still hear version.numbered", m.Consumes) } for _, r := range m.Resources { if r["id"] == "registry" { 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 7a37ace2b..0892e16b2 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 @@ -313,57 +313,3 @@ func TestEachGoPackageOfAModuleInAFolderIsPublishedUnderItsOwnModulePath(t *test } } } - -// CAT-BG2 (design 51 *The versions*): the builder's version.numbered for a bundle or an archive publishes the held -// digest under its version, sending nothing; a digest the holder no longer holds fails the event (offered again), -// and what is not this module's to publish is let pass. -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 := 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) - } - return raw - } - for _, c := range []struct { - name string - body []byte - did, fail bool - }{ - {"a held bundle is tagged", numbered("bundle", ArtifactSeat, digest), true, false}, - {"an archive with no seat named goes to the artifact seat", numbered("archive", "", digest), true, false}, - {"a digest the holder lacks fails, sending nothing", numbered("bundle", ArtifactSeat, other), false, true}, - {"a Go package is not published late", numbered("package", GoPackageSeat, digest), false, false}, - {"an image is mesh-build-image's", numbered("image", "container-image-registry", digest), false, false}, - {"no digest, nothing to publish", numbered("bundle", ArtifactSeat, ""), false, false}, - {"an unreadable body fails", []byte(`{"name":"mod/tools"}`), false, true}, - } { - t.Run(c.name, func(t *testing.T) { - m := &Module{} - s := withStore(t, m) - s.blobs["mod/tools@"+digest] = []byte("held") - did, err := m.LatePublish(t.Context(), c.body) - if did != c.did || (err != nil) != c.fail { - t.Fatalf("did %v, err %v; want did %v, fail %v", did, err, c.did, c.fail) - } - for _, k := range s.asked { - if strings.HasSuffix(k, ".publish-part") { - t.Errorf("a late publish sent a part: %v", s.asked) - } - } - if !c.did { - return - } - if len(s.published) != 1 { - t.Fatalf("published %v", s.published) - } - p := s.published[0] - if p.Name != "mod/tools" || p.Version != "0.1.4" || p.Digest != digest || p.Fingerprint != "fp" || p.Commit != "c0" { - t.Errorf("published %+v", p) - } - }) - } -} diff --git a/modules/mesh-build-go/module.json b/modules/mesh-build-go/module.json index b447e70c4..7d43103f0 100644 --- a/modules/mesh-build-go/module.json +++ b/modules/mesh-build-go/module.json @@ -24,9 +24,6 @@ "serves": ["current", "drop", "pause", "resume", "steps"] } ], - "consumes": [ - "mesh-delivery-builder.version.numbered" - ], "reads": [ "mesh-delivery-checker.kept" ], diff --git a/modules/mesh-build-image/cmd/mesh-build-image/build.go b/modules/mesh-build-image/cmd/mesh-build-image/build.go index 70fa9e083..79b582095 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/build.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/build.go @@ -170,6 +170,10 @@ func (m *Module) build(ctx context.Context, args map[string]any) (any, error) { argv = append(argv, "--target", art.Target) } argv = append(argv, imageArgs(manifest)...) + // The version the build ask carries is the build argument MESH_VERSION (design 47 G §370). + if version != "" { + argv = append(argv, "--build-arg", "MESH_VERSION="+version) + } argv = append(argv, contextDir) if r := m.Run(ctx, m.env(), "buildah", argv...); r.Status != 0 || r.Err != "" { m.sayFailure("buildah bud of "+art.Name+" of "+manifest.Module, r) 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 b886de329..7bbb850c4 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 @@ -330,3 +330,20 @@ func TestAManifestFallingBackToAPredefinedKeyBuilds(t *testing.T) { t.Errorf("result = %+v", res) } } + +// Design 47 G §370 (BLD11): a build ask carrying a version gives the image build the build argument MESH_VERSION. +func TestTheImageBuildGetsTheVersionTheAskCarriesAsMeshVersion(t *testing.T) { + m, f, states := setup(t, same) + if _, st := runBuild(t, m, states, map[string]any{"version": "1.4.3"}); st.State != sdkstep.StepPassed { + t.Fatalf("step = %+v", st) + } + bud := f.called("bud") + if len(bud) != 1 || !strings.Contains(bud[0].line, "--build-arg MESH_VERSION=1.4.3") { + t.Fatalf("bud = %+v", bud) + } + m, f, states = setup(t, same) + runBuild(t, m, states, nil) + if bud := f.called("bud"); len(bud) != 1 || strings.Contains(bud[0].line, "MESH_VERSION") { + t.Fatalf("a build with no version: %+v", bud) + } +} diff --git a/modules/mesh-build-image/cmd/mesh-build-image/compose_test.go b/modules/mesh-build-image/cmd/mesh-build-image/compose_test.go index ff7acedf9..8a09744da 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/compose_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/compose_test.go @@ -27,8 +27,8 @@ func TestTheModuleInvokesTheImageSeatAndHoldsNoRegistry(t *testing.T) { "seat:container-image-registry.mirror", "seat:mesh-module-assigner.assignments"}; !slices.Equal(m.Invokes, want) { t.Errorf("invokes = %v, want %v", m.Invokes, want) } - // The builder's version.numbered for the late publish (ADR 0617 §1), and the seat's outcomes a copy waits on. - consumes := []string{NumberedPattern} + // The seat's outcomes a copy waits on; the version comes in the ask, so version.numbered is not heard (design 47 G §413). + consumes := []string{} for _, e := range OutcomeEvents { consumes = append(consumes, "container-image-registry."+e) } diff --git a/modules/mesh-build-image/cmd/mesh-build-image/latepublish.go b/modules/mesh-build-image/cmd/mesh-build-image/latepublish.go deleted file mode 100644 index 2e5a03c8b..000000000 --- a/modules/mesh-build-image/cmd/mesh-build-image/latepublish.go +++ /dev/null @@ -1,23 +0,0 @@ -package main - -// The late publish (novox/hq ADR 0617 §1, CAT-BI1): an image whose floor the builder did not know yet is built -// unnumbered and published by its digest; once the builder numbers it, its version.numbered publishes the held digest -// under that version through the image seat, sending nothing (buildstep/latepublish.go, the build modules' one). - -import ( - "context" - - "git.novox.be/novox/mesh-catalog/modules/mesh-build-go/buildstep" -) - -// NumberedPattern is the event type this module consumes for the late publish, as its manifest's `consumes` names it. -const NumberedPattern = buildstep.NumberedPattern - -// LatePublish publishes a numbered image's held digest under its version on the image seat; a bundle or an archive is -// mesh-build-go's. -func (m *Module) LatePublish(ctx context.Context, body []byte) (bool, error) { - return buildstep.LatePublish(ctx, m.call(), body, buildstep.ImageSeat, KindImage) -} - -// hearNumbered hears the builder's version.numbered for the late publish. -func (m *Module) hearNumbered(ctx context.Context) { buildstep.HearNumbered(ctx, m.LatePublish) } 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 82be8871b..13224f1b2 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/main.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/main.go @@ -76,8 +76,6 @@ func main() { // The image seat's outcomes, which a copy waits on (the manifest's consumes), and the copies' waits in // mirror-waits, where another instance writes an outcome it heard. go hearOutcomes(ctx, m.Outcomes) - // The builder's version.numbered, for the late publish of an image built unnumbered (ADR 0617 §1). - go m.hearNumbered(ctx) go waits.Follow("", m.Outcomes.Changed) } if m.Node != "" { 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 c7e51a66a..554635c50 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,7 +9,6 @@ import ( "testing" reg "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" ) @@ -123,50 +122,3 @@ func TestATrunkBuildPublishesThroughTheImageSeatOnlyWhatTheHolderLacks(t *testin t.Errorf("a tag that is not one: step = %+v", st) } } - -// ADR 0617 §1: the builder's version.numbered for an image publishes the held digest under its version through the image -// seat, sending nothing; a digest the holder lacks fails the event (offered again); what is not this module's passes. -func TestTheNumberedEventPublishesAHeldImageUnderItsVersion(t *testing.T) { - digest := "sha256:" + strings.Repeat("ab", 32) - numbered := func(kind, seat, digest string) []byte { - 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) - } - return raw - } - for name, c := range map[string]struct { - body []byte - did, fail bool - }{ - "a held image is numbered": {body: numbered("image", reg.Seat, digest), did: true}, - "a digest the holder lacks fails": {body: numbered("image", reg.Seat, "sha256:"+strings.Repeat("cd", 32)), fail: true}, - "a bundle is mesh-build-go's": {body: numbered("bundle", "oci-artifact-registry", digest)}, - "an event naming no seat is a bundle's": {body: numbered("image", "", digest)}, - "no digest, nothing to publish": {body: numbered("image", reg.Seat, "")}, - } { - t.Run(name, func(t *testing.T) { - m, f, _ := setup(t, same) - f.held[digest] = true - did, err := m.LatePublish(t.Context(), c.body) - if did != c.did || (err != nil) != c.fail { - t.Fatalf("did %v, err %v; want did %v, fail %v", did, err, c.did, c.fail) - } - if len(f.sent) != 0 { - t.Errorf("a late publish sent parts: %v", f.sent) - } - if !c.did { - return - } - if len(f.published) != 1 { - t.Fatalf("published %+v", f.published) - } - p := f.published[0] - if p.Name != "fixture-image/server" || p.Kind != KindImage || p.Version != "1.4.0" || p.Digest != digest || - p.Fingerprint != "fp" || p.Commit != "c0" || len(p.Parts) != 1 || p.Parts[0].Digest != digest { - t.Errorf("published %+v", p) - } - }) - } -} diff --git a/modules/mesh-build-image/module.json b/modules/mesh-build-image/module.json index ac256f530..ec0de87d9 100644 --- a/modules/mesh-build-image/module.json +++ b/modules/mesh-build-image/module.json @@ -68,7 +68,6 @@ "seat:mesh-module-assigner.assignments" ], "consumes": [ - "mesh-delivery-builder.version.numbered", "container-image-registry.published", "container-image-registry.refused" ], 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 4c7bb7da0..4147c76c5 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/build.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/build.go @@ -110,8 +110,9 @@ func (m *Module) build(ctx context.Context, args map[string]any) (any, error) { if err != nil { return nil, err } + // The version the build ask carries is the build argument MESH_VERSION of every artifact (design 47 G §370). + version, _ := args["version"].(string) if a.Kind == "package" { - version, _ := args["version"].(string) seat, _ := args["seat"].(string) at := a.packageDir(dir) return m.buildPackage(ctx, workspace, module, root, filepath.Join(dir, filepath.FromSlash(at)), at, a, publish, version, seat) @@ -145,14 +146,14 @@ func (m *Module) build(ctx context.Context, args map[string]any) (any, error) { tsc := []string{m.tsc(), "--module", "NodeNext", "--moduleResolution", "NodeNext", "--target", "ES2022", "--rootDir", ".", "--outDir", out} tsc = append(tsc, sourcesFor(a.Entrypoints, out, ".ts")...) - if why := ranFailed(m.runIn(ctx, root, publish, dir, nil, "node", tsc...)); why != "" { + if why := ranFailed(m.runIn(ctx, root, publish, dir, versionEnv(version), "node", tsc...)); why != "" { return nil, fmt.Errorf("tsc for %s: %s", a.Name, why) } launchers, err := writeLaunchers(filepath.Join(dir, out), a) if err != nil { return nil, err } - if err := m.bundle(ctx, root, publish, dir, a, launchers); err != nil { + if err := m.bundle(ctx, root, publish, dir, a, launchers, version); err != nil { return nil, err } bundleDir := filepath.Join(dir, final) @@ -185,7 +186,7 @@ func (m *Module) build(ctx context.Context, args map[string]any) (any, error) { // bundle makes every entrypoint and every launcher ONE file, with esbuild (builder.go:1971-2039): an entrypoint is // bundled in place under its own name, a launcher keeps its name with the extension .mjs. -func (m *Module) bundle(ctx context.Context, root string, publish bool, dir string, a artifact, launchers map[string]string) error { +func (m *Module) bundle(ctx context.Context, root string, publish bool, dir string, a artifact, launchers map[string]string, version string) error { out, final := Out(a.Name), Out(a.Name)+".bundled" if err := os.RemoveAll(filepath.Join(dir, final)); err != nil { return err @@ -212,7 +213,7 @@ func (m *Module) bundle(ctx context.Context, root string, publish bool, dir stri return nil } args := append(append(append([]string{}, entries...), common...), extra...) - if why := ranFailed(m.runIn(ctx, root, publish, dir, nil, m.esbuild(), args...)); why != "" { + if why := ranFailed(m.runIn(ctx, root, publish, dir, versionEnv(version), m.esbuild(), args...)); why != "" { return fmt.Errorf("esbuild for %s: %s", a.Name, why) } return nil @@ -319,3 +320,11 @@ func readArtifact(dir, name string) (artifact, error) { } return artifact{}, fmt.Errorf("module.json declares no artifact %q", name) } + +// versionEnv is the build argument MESH_VERSION for the version the build ask carries, none when it carries none. +func versionEnv(version string) []string { + if version == "" { + return nil + } + return []string{"MESH_VERSION=" + version} +} diff --git a/modules/mesh-build-node/cmd/mesh-build-node/build_test.go b/modules/mesh-build-node/cmd/mesh-build-node/build_test.go index 43fe83cc0..469482168 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/build_test.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/build_test.go @@ -302,3 +302,29 @@ func TestRanFailedKeepsTheError(t *testing.T) { } } } + +// Design 47 G §370 (BLD11): a build ask carrying a version gives the compiler and the bundler the build argument +// MESH_VERSION; one without gives none. +func TestTheBundleBuildGetsTheVersionTheAskCarriesAsMeshVersion(t *testing.T) { + for _, version := range []string{"1.4.3", ""} { + m, f, _ := builtMachine(t, "") + args := buildArgs() + if version != "" { + args["version"] = version + } + if _, err := m.build(context.Background(), args); err != nil { + t.Fatal(err) + } + for _, c := range f.calls { + got := "" + for _, e := range c.env { + if v, ok := strings.CutPrefix(e, "MESH_VERSION="); ok { + got = v + } + } + if got != version { + t.Errorf("ask version %q: %s ran with MESH_VERSION=%q", version, c.name, got) + } + } + } +} 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 9da43efab..4a994da7e 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/package.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/package.go @@ -201,6 +201,7 @@ func (m *Module) buildAndPack(ctx context.Context, root, dir, rel string, write return packed{}, err } env := []string{"PATH=" + shimDir(root, rel) + ":" + pathOrDefault(), "npm_config_cache=" + m.npmCache()} + env = append(env, versionEnv(version)...) if p.Scripts["build"] != "" { if why := ranFailed(m.runIn(ctx, root, write, dir, env, "npm", "run", "build")); why != "" { return packed{}, fmt.Errorf("the build of the package %s: %s", p.Name, why)