Files
mesh-catalog/modules/mesh-build-node/cmd/mesh-build-node/package_integration_test.go
T
jschoubben b9cdca78b0 mesh-build-node: narrow the fetch to the named paths, build members against the SDK their lock names, and build, pack and publish a package (issues 1758, 1587 S15-S19; ADR 0499 §4, ADR 0498 §5, ADR 0500 §4-§6; lead decision L10)
build_node_fetch takes buildstep.FetchRequest (dir and paths narrow the workspace) and an
optional package {repository, commit, ref}: the group's package member, built and packed
shut off and published nowhere. Each member's lock decides its SDK: the group's packed
file when the version and integrity are the lock's, else the registry's (integrity
checked); a version the registry lacks fails waits for: @novox/mesh-sdk@<version>. A
package artifact is built by its own script and packed with npm pack, shut off; only a
trunk build publishes it, from this process with the write credential (never in a
workspace): absent is published, the same file is done, another is version taken:. The
registry configuration file now lies outside every workspace.
2026-10-22 18:38:22 +02:00

126 lines
6.3 KiB
Go

//go:build integration
package main
import (
"context"
"encoding/json"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/forgekey"
)
// sdkFixture is a package named as the SDK at version 9.9.9 with no dependency, whose build script writes dist/: what
// the group's package member is to its TypeScript members.
var sdkFixture = map[string]string{
"module.json": `{"module":"mesh-sdk","version":"1","build":{"artifacts":[{"name":"lib","kind":"package","language":"typescript"}]}}`,
"package.json": `{"name":"@novox/mesh-sdk","version":"9.9.9","type":"module","files":["dist"],"scripts":{"build":"node build.mjs"}}`,
"package-lock.json": `{"name":"@novox/mesh-sdk","version":"9.9.9","lockfileVersion":3,"requires":true,"packages":{"":{"name":"@novox/mesh-sdk","version":"9.9.9"}}}`,
"build.mjs": "import fs from 'node:fs';\nfs.mkdirSync('dist', {recursive: true});\nfs.writeFileSync('dist/index.js', 'export const v = \"9.9.9\";\\n');\n",
}
// forgeRepo makes a bare repository o/<name> under root/forge holding files at one commit, and answers the commit.
func forgeRepo(t *testing.T, root, name string, files map[string]string) string {
t.Helper()
bare, work := filepath.Join(root, "forge", "o", name+".git"), filepath.Join(root, "work-"+name)
os.MkdirAll(bare, 0o755)
os.MkdirAll(work, 0o755)
git(t, bare, "init", "-q", "--bare")
git(t, work, "init", "-q", "-b", "main")
for n, c := range files {
write(t, filepath.Join(work, filepath.FromSlash(n)), c, 0o644)
}
git(t, work, "add", ".")
git(t, work, "commit", "-q", "-m", "c")
git(t, work, "push", "-q", bare, "HEAD:refs/heads/main")
return git(t, work, "rev-parse", "HEAD")
}
// ADR 0500 §5 with the lead's decision L10, on real git, npm and bubblewrap: the fetch packs the group's package member
// (its build script and npm pack shut off, nothing published), and a member whose lock names that version with that
// integrity gets it in its node_modules; a member whose lock names it with another integrity fails naming both.
func TestTheFetchPacksTheGroupsPackageAndServesItToAMember(t *testing.T) {
for _, tool := range []string{"node", "npm", "git", "bwrap"} {
if _, err := exec.LookPath(tool); err != nil {
t.Skipf("NOT RUN: no %s where this check runs; every build node has it", tool)
}
}
root := t.TempDir()
sdkCommit := forgeRepo(t, root, "sdk", sdkFixture)
m, _, _ := newMachine(t)
m.Run = forgekey.ExecRunner
m.RemoteBase = "file://" + filepath.Join(root, "forge") + "/"
m.FetchOptions = []buildstep.Option{buildstep.AllowFileRemote()}
fakeRegistry(t, m, nil) // the registry holds no 9.9.9: only the group can serve it
// What the group's member packs to, as the member's lock would name it: packed once here the way the fetch packs it.
probe, err := m.fetch(context.Background(), map[string]any{"repository": "o/sdk", "commit": sdkCommit,
"package": map[string]any{"repository": "o/sdk", "commit": sdkCommit}})
if err != nil {
t.Fatal(err)
}
group := strings.Fields(probe.(FetchResult).Group)
if len(group) != 2 || group[0] != "@novox/mesh-sdk@9.9.9" || !strings.HasPrefix(group[1], "sha512-") {
t.Fatalf("the fetch answered the group %q", probe.(FetchResult).Group)
}
member := func(integrity string) string {
lock, _ := json.Marshal(map[string]any{"name": "m", "lockfileVersion": 3, "requires": true, "packages": map[string]any{
"": map[string]any{"name": "m", "dependencies": map[string]any{"@novox/mesh-sdk": "9.9.9"}},
"node_modules/@novox/mesh-sdk": map[string]any{"version": "9.9.9", "integrity": integrity}}})
files := typeScriptModule(`{"name":"m","dependencies":{"@novox/mesh-sdk":"9.9.9"}}`)
files["modules/m/package-lock.json"] = string(lock)
return forgeRepo(t, root, "m-"+integrity[len(integrity)-6:len(integrity)-2], files)
}
commit := member(group[1])
name := "m-" + group[1][len(group[1])-6:len(group[1])-2]
out, err := m.fetch(context.Background(), map[string]any{"repository": "o/" + name, "commit": commit,
"package": map[string]any{"repository": "o/sdk", "commit": sdkCommit}})
if err != nil {
t.Fatalf("a member locking the group's version: %v", err)
}
placed := filepath.Join(m.Work, out.(FetchResult).Workspace, "tree", "modules", "m", "node_modules", "@novox", "mesh-sdk")
if raw, err := os.ReadFile(filepath.Join(placed, "dist", "index.js")); err != nil || !strings.Contains(string(raw), "9.9.9") {
t.Errorf("the member's SDK is not the group's built package: %q %v", raw, err)
}
other := member("sha512-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")
_, err = m.fetch(context.Background(), map[string]any{"repository": "o/m-AAAA", "commit": other,
"package": map[string]any{"repository": "o/sdk", "commit": sdkCommit}})
if err == nil || !strings.Contains(err.Error(), group[1]) {
t.Errorf("a member locking another integrity answered %v", err)
}
}
// ADR 0499 §4 (issue 1758): a fetch asked with the module's directory and its named paths leaves only those, the
// manifest and the lock files; another module of the commit is not listed or installed.
func TestAFetchWithNamedPathsNarrowsTheWorkspace(t *testing.T) {
root := t.TempDir()
files := typeScriptModule(`{"name":"m"}`)
files["modules/m/tools/index.ts"] = "export {}\n"
files["modules/m/docs/a.md"] = "not named\n"
files["modules/other/module.json"] = files["modules/m/module.json"]
files["README.md"] = "the repository\n"
commit := forgeRepo(t, root, "narrow", files)
m, _, _ := newMachine(t)
m.Run = forgekey.ExecRunner
m.RemoteBase = "file://" + filepath.Join(root, "forge") + "/"
m.FetchOptions = []buildstep.Option{buildstep.AllowFileRemote()}
out, err := m.fetch(context.Background(), map[string]any{"repository": "o/narrow", "commit": commit, "dir": "modules/m", "paths": []any{"tools"}})
if err != nil {
t.Fatal(err)
}
r := out.(FetchResult)
tree := filepath.Join(m.Work, r.Workspace, "tree")
for _, gone := range []string{"README.md", "modules/m/docs/a.md", "modules/other/module.json"} {
if _, err := os.Stat(filepath.Join(tree, gone)); err == nil {
t.Errorf("%s is still in the workspace", gone)
}
}
if _, err := os.Stat(filepath.Join(tree, "modules/m/tools/index.ts")); err != nil || strings.Join(r.Modules, ",") != "modules/m" {
t.Errorf("the named path or the module went: %v, modules %v", err, r.Modules)
}
}