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.
117 lines
4.7 KiB
Go
117 lines
4.7 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
const packageManifest = `{"module":"mesh-sdk","version":"1","build":{"artifacts":[{"name":"lib","kind":"package","language":"typescript","paths":["src","package.json"]}]}}`
|
|
|
|
// packageMachine is a machine whose workspace w1 holds the package @novox/mesh-sdk@0.1.15 at its root; npm pack writes
|
|
// the packed file tgz into its --pack-destination, as npm does.
|
|
func packageMachine(t *testing.T, tgz []byte) (*Module, *fakeMachine, string) {
|
|
t.Helper()
|
|
m, f, work := newMachine(t)
|
|
workspaceWith(t, work, map[string]string{"module.json": packageManifest, "src/index.ts": "export const v = 1;\n",
|
|
"package.json": `{"name":"@novox/mesh-sdk","version":"0.1.15","scripts":{"build":"tsc"}}`, "package-lock.json": `{"lockfileVersion":3}`})
|
|
f.effect = func(c call) {
|
|
if c.name != "npm" || len(c.args) == 0 || c.args[0] != "pack" {
|
|
return
|
|
}
|
|
for i, a := range c.args {
|
|
if a == "--pack-destination" {
|
|
write(t, filepath.Join(c.args[i+1], "novox-mesh-sdk-0.1.15.tgz"), string(tgz), 0o644)
|
|
}
|
|
}
|
|
}
|
|
return m, f, work
|
|
}
|
|
|
|
func publishes(f *fakeMachine) []call {
|
|
var out []call
|
|
for _, c := range f.calls {
|
|
if c.name == "npm" && len(c.args) > 0 && c.args[0] == "publish" {
|
|
out = append(out, c)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// 1587-S15..S19 (ADR 0498 §5): a package is built by its own build script and packed, shut off; a candidate answers the
|
|
// packed file's digest, publishes nothing and asks the registry nothing; its reference is empty.
|
|
func TestACandidatesPackageIsBuiltAndPackedAndNeverPublished(t *testing.T) {
|
|
tgz := tgzOf(t, sdkPackage, "0.1.15")
|
|
m, f, _ := packageMachine(t, tgz)
|
|
asked := fakeRegistry(t, m, nil)
|
|
out, err := m.build(context.Background(), map[string]any{"workspace": "w1", "module": ".", "artifact": "lib"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
r := out.(BuildResult)
|
|
if r.Digest != digestOf(tgz) || r.Reference != "" || r.Bytes != len(tgz) {
|
|
t.Errorf("result %+v, want the packed file's digest and no reference", r)
|
|
}
|
|
if len(publishes(f)) != 0 || asked.Load() != 0 {
|
|
t.Errorf("a candidate published %d times and asked the registry %d times", len(publishes(f)), asked.Load())
|
|
}
|
|
var ran []string
|
|
for _, s := range f.shut {
|
|
ran = append(ran, s.command)
|
|
}
|
|
if len(f.shut) != 2 || !strings.Contains(ran[0], "npm run build") || !strings.Contains(ran[1], "npm pack --ignore-scripts") {
|
|
t.Errorf("shut off %v, want the build and the pack", ran)
|
|
}
|
|
}
|
|
|
|
// ADR 0498 §5: a trunk build (publish) publishes a version the registry lacks and answers <name>@<version>; the same
|
|
// packed file already there is done without a publish; another file under that version fails `version taken:`. The
|
|
// packed file is gone from the node afterwards.
|
|
func TestATrunkPackageIsPublishedOnceAndAVersionTakenIsRefused(t *testing.T) {
|
|
tgz := tgzOf(t, sdkPackage, "0.1.15")
|
|
args := map[string]any{"workspace": "w1", "module": ".", "artifact": "lib", "publish": true}
|
|
m, f, work := packageMachine(t, tgz)
|
|
fakeRegistry(t, m, nil)
|
|
out, err := m.build(context.Background(), args)
|
|
if err != nil || out.(BuildResult).Reference != "@novox/mesh-sdk@0.1.15" || len(publishes(f)) != 1 {
|
|
t.Fatalf("an absent version: %+v %v, %d publishes", out, err, len(publishes(f)))
|
|
}
|
|
if p := publishes(f)[0]; !slices.Contains(p.args, "--ignore-scripts") || !strings.HasSuffix(p.args[1], ".tgz") {
|
|
t.Errorf("published with %v", p.args)
|
|
}
|
|
// ADR 0500 §4: the registry's credential is never in a workspace, which a run step is given.
|
|
for i, a := range publishes(f)[0].args {
|
|
if a == "--userconfig" && strings.HasPrefix(publishes(f)[0].args[i+1], work) {
|
|
t.Errorf("the credential was written into the workspace: %s", publishes(f)[0].args[i+1])
|
|
}
|
|
}
|
|
var left []string
|
|
filepath.WalkDir(work, func(p string, d os.DirEntry, err error) error {
|
|
if err == nil && strings.HasSuffix(p, ".tgz") || strings.Contains(p, ".npmrc") {
|
|
left = append(left, p)
|
|
}
|
|
return nil
|
|
})
|
|
if len(left) != 0 {
|
|
t.Errorf("left on the node: %v", left)
|
|
}
|
|
|
|
m, f, _ = packageMachine(t, tgz)
|
|
fakeRegistry(t, m, map[string][]byte{"0.1.15": tgz})
|
|
if out, err := m.build(context.Background(), args); err != nil || out.(BuildResult).Reference != "@novox/mesh-sdk@0.1.15" || len(publishes(f)) != 0 {
|
|
t.Errorf("the same file published before: %+v %v, %d publishes", out, err, len(publishes(f)))
|
|
}
|
|
|
|
m, f, _ = packageMachine(t, tgz)
|
|
fakeRegistry(t, m, map[string][]byte{"0.1.15": tgzOf(t, sdkPackage, "another")})
|
|
_, err = m.build(context.Background(), args)
|
|
if err == nil || !strings.HasPrefix(err.Error(), delivery.VersionTaken+"@novox/mesh-sdk@0.1.15") || len(publishes(f)) != 0 {
|
|
t.Errorf("another file under the version: %v, %d publishes", err, len(publishes(f)))
|
|
}
|
|
}
|