Ship the Node build module's toolchain lock as an archive, not a template naming hosts (issue 1488)
This commit is contained in:
@@ -10,13 +10,13 @@ builder uses it. Its forge key and ssh files are the same as mesh-build-go's (is
|
||||
|
||||
`recipe.go` names the one Node version it builds with (`RecipeNode`, `v26.10.0`, as `node --version` prints it) and the
|
||||
recipe's own version (`RecipeSteps`). The recipe version is a hash of those two and of the bytes of the lock file
|
||||
`files/toolchain/package-lock.json`, so one changed byte of the lock, another Node or another recipe moves it.
|
||||
`toolchain/package-lock.json`, so one changed byte of the lock, another Node or another recipe moves it.
|
||||
|
||||
## The toolchain directory
|
||||
|
||||
`files/toolchain/package.json` and its committed `package-lock.json` name typescript 5.9.3, esbuild 0.25.12, @types/node 22.20.1 (the types tsc checks node imports against),
|
||||
@novox/mesh-sdk 0.1.14 and nats 2.29.3. The mesh writes both into `<home>/toolchain/` (resources `toolchain-package`
|
||||
and `toolchain-lock`); the program reads the lock from there. When `<cache dir>/toolchain/<recipe version>` is missing
|
||||
`toolchain/package.json` and its committed `package-lock.json` name typescript 5.9.3, esbuild 0.25.12, @types/node 22.20.1 (the types tsc checks node imports against),
|
||||
@novox/mesh-sdk 0.1.14 and nats 2.29.3. The mesh unpacks both, as the archive artifact `toolchain`, into `<home>/toolchain/` (resource `toolchain-dir`; a
|
||||
manifest names no host, and the lock does, so it is not a template); the program reads the lock from there. When `<cache dir>/toolchain/<recipe version>` is missing
|
||||
the module runs `npm ci --ignore-scripts` there once (a directory without its `.installed` mark counts as missing).
|
||||
|
||||
**How the registry is reached** (the choice of issue 1488): the lock holds @novox/mesh-sdk at the forge's public
|
||||
|
||||
@@ -24,7 +24,7 @@ func realMachine(t *testing.T) (*Module, string) {
|
||||
}
|
||||
home, cache, work := t.TempDir(), t.TempDir(), t.TempDir()
|
||||
for _, n := range []string{"package.json", "package-lock.json"} {
|
||||
raw, err := os.ReadFile(filepath.Join(moduleDir, "files", "toolchain", n))
|
||||
raw, err := os.ReadFile(filepath.Join(moduleDir, "toolchain", n))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -124,22 +125,13 @@ func TestTheToolsServedAreTheToolsTheManifestNames(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// 1488/AC1: the module carries the committed lock beside its package.json, and the manifest has the mesh write both
|
||||
// into the home's toolchain directory, where the program reads them.
|
||||
// 1488/AC1: the module carries the committed lock beside its package.json, and the manifest unpacks them into the
|
||||
// home's toolchain directory, where the program reads them.
|
||||
func TestTheModuleCarriesItsToolchainLockAndTheManifestPlacesIt(t *testing.T) {
|
||||
m := readManifest(t)
|
||||
for _, name := range []string{"package.json", "package-lock.json"} {
|
||||
if _, err := os.Stat(filepath.Join(moduleDir, "files", "toolchain", name)); err != nil {
|
||||
t.Errorf("the module carries no files/toolchain/%s: %v", name, err)
|
||||
}
|
||||
}
|
||||
lock := resource(t, m, "toolchain-lock")
|
||||
if lock["path"] != "${dir:toolchain-dir}/package-lock.json" || lock["owner"] != "mesh-build-node" {
|
||||
t.Errorf("toolchain-lock = %v", lock)
|
||||
}
|
||||
for _, r := range readForgeManifest(t).Resources {
|
||||
if r["id"] == "toolchain-lock" && r["template"] != "files/toolchain/package-lock.json" {
|
||||
t.Errorf("toolchain-lock takes its text from %v", r["template"])
|
||||
if _, err := os.Stat(filepath.Join(moduleDir, "toolchain", name)); err != nil {
|
||||
t.Errorf("the module carries no toolchain/%s: %v", name, err)
|
||||
}
|
||||
}
|
||||
if !slices.Contains(m.Requires, "npm-package-registry") {
|
||||
@@ -150,7 +142,7 @@ func TestTheModuleCarriesItsToolchainLockAndTheManifestPlacesIt(t *testing.T) {
|
||||
// 1488/AC1: the lock names the versions of the recipe: typescript 5.9.3, esbuild 0.25.12, @novox/mesh-sdk 0.1.14
|
||||
// and nats, all by the lock's own hash (read from the file the module carries).
|
||||
func TestTheLockNamesTheToolchainVersions(t *testing.T) {
|
||||
raw, err := os.ReadFile(filepath.Join(moduleDir, "files", "toolchain", "package-lock.json"))
|
||||
raw, err := os.ReadFile(filepath.Join(moduleDir, "toolchain", "package-lock.json"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -168,3 +160,34 @@ func TestTheLockNamesTheToolchainVersions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1488 (the catalogue's manifest check): a manifest names no host, the mesh being name-agnostic. The tree-read
|
||||
// manifest carries each template's text as the resource's content, and the toolchain's lock names registries, so it is
|
||||
// shipped as an archive artifact instead, never as a template. No resource of the module, read as the mesh reads it,
|
||||
// carries content naming a host, and the raw module.json names none either.
|
||||
func TestNoResourceCarriesContentNamingAHost(t *testing.T) {
|
||||
host := regexp.MustCompile(`(?i)://[a-z0-9]|\b[a-z0-9-]+(\.[a-z0-9-]+)*\.(com|org|net|be|io|dev)\b`)
|
||||
m := readManifest(t)
|
||||
for i, r := range m.Resources {
|
||||
if c, _ := r["content"].(string); host.MatchString(c) {
|
||||
t.Errorf("resources[%d] (%v) carries content naming %q", i, r["id"], host.FindString(c))
|
||||
}
|
||||
}
|
||||
raw, _ := os.ReadFile(filepath.Join(moduleDir, "module.json"))
|
||||
if h := host.FindString(string(raw)); h != "" {
|
||||
t.Errorf("module.json names %q", h)
|
||||
}
|
||||
}
|
||||
|
||||
// 1488: the toolchain's package.json and lock are shipped in the archive artifact `toolchain` and unpacked into the
|
||||
// home's toolchain directory, where the program reads them.
|
||||
func TestTheToolchainFilesAreAnArchiveUnpackedIntoTheHome(t *testing.T) {
|
||||
m := readManifest(t)
|
||||
r := resource(t, m, "toolchain-dir")
|
||||
if r["type"] != "archive" || r["path"] != "${dir:state}/toolchain" || r["owner"] != "mesh-build-node" {
|
||||
t.Errorf("toolchain-dir = %v, want an archive unpacked at ${dir:state}/toolchain", r)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(moduleDir, "toolchain", "package-lock.json")); err != nil {
|
||||
t.Errorf("the module carries no toolchain/package-lock.json: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
"streams": [
|
||||
{
|
||||
"name": "toolchains-node",
|
||||
"events": ["toolchain.**"]
|
||||
"events": [
|
||||
"toolchain.**"
|
||||
]
|
||||
}
|
||||
],
|
||||
"requires": [
|
||||
@@ -117,28 +119,12 @@
|
||||
},
|
||||
{
|
||||
"id": "toolchain-dir",
|
||||
"type": "directory",
|
||||
"type": "archive",
|
||||
"path": "${dir:state}/toolchain",
|
||||
"mode": "0700",
|
||||
"owner": "mesh-build-node",
|
||||
"artifact": "toolchain",
|
||||
"unknown": "program"
|
||||
},
|
||||
{
|
||||
"id": "toolchain-package",
|
||||
"type": "file",
|
||||
"path": "${dir:toolchain-dir}/package.json",
|
||||
"owner": "mesh-build-node",
|
||||
"mode": "0644",
|
||||
"template": "files/toolchain/package.json"
|
||||
},
|
||||
{
|
||||
"id": "toolchain-lock",
|
||||
"type": "file",
|
||||
"path": "${dir:toolchain-dir}/package-lock.json",
|
||||
"owner": "mesh-build-node",
|
||||
"mode": "0644",
|
||||
"template": "files/toolchain/package-lock.json"
|
||||
},
|
||||
{
|
||||
"id": "nodejs",
|
||||
"type": "package",
|
||||
@@ -177,6 +163,11 @@
|
||||
"name": "files",
|
||||
"kind": "archive",
|
||||
"from": "files"
|
||||
},
|
||||
{
|
||||
"name": "toolchain",
|
||||
"kind": "archive",
|
||||
"from": "toolchain"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user