Read a module whose every artifact names its paths from those paths and its manifest alone, so a change elsewhere in its directory moves nothing (issue 1758, B1, ADR 0499 §5)
This commit is contained in:
@@ -289,8 +289,14 @@ func buildOfKey(ctx context.Context, keys keyReads, t keyTake, kc keyContext) (
|
||||
Commit: t.Trunk.Commit, On: k.Build.By, Path: keyPath(t.Trunk), Manifest: raw,
|
||||
SourceFingerprint: k.Fingerprint, At: time.Now().UTC()}
|
||||
// **Read from the manifest, fresh at every key** (the same rule build-agent says, internal/buildreads). Sources are
|
||||
// left unsaid: the planner then reads the module's whole directory, over-planning and never under-planning, and a
|
||||
// fingerprint that did not change moves nothing (R4e A9).
|
||||
// left unsaid but for a module whose every artifact names its paths: the planner then reads the module's whole
|
||||
// directory, over-planning and never under-planning, and a fingerprint that did not change moves nothing (R4e A9).
|
||||
// **Its build source where its every artifact names its paths** (novox/hq ADR 0499 §1, §5; issue 1758, B1): the
|
||||
// planner reads a merge's changed files against those paths and the manifest alone, so a change elsewhere in the
|
||||
// module's directory touches nothing it builds from.
|
||||
if own := pathsBuildSource(manifest, keyPath(t.Trunk)); own != nil {
|
||||
kept.Sources = []inventory.BuildSource{{Paths: own}}
|
||||
}
|
||||
for _, c := range buildreads.Of(manifest) {
|
||||
kept.Read = append(kept.Read, inventory.ReadRepository{Repository: c.Repository, Ref: c.Ref})
|
||||
}
|
||||
@@ -422,3 +428,33 @@ func openBuilderKeys() (builderkeys.Reader, func(), error) {
|
||||
}
|
||||
return builderkeys.Reader{JS: api}, js.Close, nil
|
||||
}
|
||||
|
||||
// pathsBuildSource is the build source of a module whose every artifact names the paths it is built from (ADR 0499
|
||||
// §1): its manifest and each path, relative to its repository's root, a path read as a file or everything below a
|
||||
// directory of that name (`<path>/**` holds both). Nil when an artifact names none: the module reads its directory.
|
||||
func pathsBuildSource(m catalogue.Manifest, dir string) []string {
|
||||
if m.Build == nil || len(m.Build.Artifacts) == 0 {
|
||||
return nil
|
||||
}
|
||||
in := func(p string) string {
|
||||
if dir == "" {
|
||||
return p
|
||||
}
|
||||
return dir + "/" + p
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
out := []string{in("module.json")}
|
||||
for _, a := range m.Build.Artifacts {
|
||||
if len(a.Paths) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, p := range a.Paths {
|
||||
entry := in(strings.Trim(path.Clean(p), "/")) + "/**"
|
||||
if !seen[entry] {
|
||||
seen[entry] = true
|
||||
out = append(out, entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"github.com/novox/mesh-controller/internal/inventory"
|
||||
)
|
||||
|
||||
// B1 (ADR 0499 §1, §5; issue 1758): a module whose every artifact names the paths it is built from is read from those
|
||||
// paths and its manifest alone. mesh-sdk's TypeScript package at its repository's root: a change to its go/ touches no
|
||||
// module, one to its src/ or its package.json touches it. A module with an artifact naming no paths reads its directory.
|
||||
func TestAModuleNamingItsPathsIsReadFromThemAlone(t *testing.T) {
|
||||
m, err := catalogue.ParseManifest([]byte(`{"module":"mesh-sdk","version":"1","build":{"artifacts":[{"name":"lib",
|
||||
"kind":"package","language":"typescript","paths":["src","package.json","package-lock.json","tsconfig.json"]}]},
|
||||
"resources":[]}`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
own := pathsBuildSource(m, "")
|
||||
read := inventory.WithBuildSources(nil, []inventory.BuildSource{{Paths: own}})
|
||||
e := inventory.Entry{Manifest: m, Source: inventory.Source{Repository: "novox/mesh-sdk", Path: ""}}
|
||||
for file, reads := range map[string]bool{
|
||||
"go/delivery/builder.go": false, "go/go.mod": false, "README.md": false,
|
||||
"src/index.ts": true, "src/deep/x.ts": true, "package.json": true, "module.json": true,
|
||||
} {
|
||||
if got := readsFile(e, read, file); got != reads {
|
||||
t.Errorf("%s: read %v, want %v", file, got, reads)
|
||||
}
|
||||
}
|
||||
// In a module's directory, the paths are under it.
|
||||
if got := pathsBuildSource(m, "modules/sdk"); got[0] != "modules/sdk/module.json" || got[1] != "modules/sdk/src/**" {
|
||||
t.Errorf("paths under a directory: %v", got)
|
||||
}
|
||||
// An artifact naming no paths: the whole directory, as before.
|
||||
m.Build.Artifacts = append(m.Build.Artifacts, catalogue.Artifact{Name: "files", Kind: "archive", From: "files"})
|
||||
if got := pathsBuildSource(m, ""); got != nil {
|
||||
t.Errorf("a module with an artifact naming no paths is narrowed to %v", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user