mesh-build-go: the generated-files compare finds a contracts module in any folder; a folder module's Go packages each publish under their own module path (ADR 0634 §8; issue 1966)
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -122,6 +122,30 @@ func generatedNames(dir string) (goModule, tsPackage string, err error) {
|
||||
return goModule, tsPackage, nil
|
||||
}
|
||||
|
||||
// ModuleDirs is every directory in tree that holds a module.json, in any folder (ADR 0634 §8: a module is found by its
|
||||
// manifest, whether it lies at the root, under modules/ or in a folder of another module), the tree's own first, then
|
||||
// sorted. Hidden directories, node_modules and testdata are not entered.
|
||||
func ModuleDirs(tree string) ([]string, error) {
|
||||
var out []string
|
||||
err := filepath.WalkDir(tree, func(p string, e os.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if e.IsDir() {
|
||||
if n := e.Name(); p != tree && (strings.HasPrefix(n, ".") || n == "node_modules" || n == "testdata") {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if e.Name() == "module.json" {
|
||||
out = append(out, filepath.Dir(p))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
sort.Strings(out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// CompareStep is AskSteps.Compare for a build module comparing root: it reads {"workspace", "module"}, the workspace's
|
||||
// tree where tree says it is (the build module's own layout), and answers {"out-of-step": [...]}.
|
||||
func CompareStep(root string, tree func(workspace string) string) StepFunc {
|
||||
|
||||
@@ -231,6 +231,66 @@ func TestAGoPackageIsBuiltAsAModuleZipAndPublishedUnderItsModulePath(t *testing.
|
||||
}
|
||||
}
|
||||
|
||||
// K-2 (ADR 0634 §8): a module in a folder of the repository, the folder holding more than one Go package, builds and
|
||||
// publishes each as a root module's would: each artifact its own zip of its own directory under its own module path,
|
||||
// the sibling package's directory (a Go module of its own) left out of the zip of the folder's.
|
||||
func TestEachGoPackageOfAModuleInAFolderIsPublishedUnderItsOwnModulePath(t *testing.T) {
|
||||
manifest := manifestWith(`{"name":"go-aone","kind":"package","language":"go","paths":["go/seats/aone"],"series":"0.1"},
|
||||
{"name":"go-btwo","kind":"package","language":"go","paths":["go/seats/btwo"],"series":"0.1"},
|
||||
{"name":"go-whole","kind":"package","language":"go","paths":["go"],"series":"0.1"}`)
|
||||
m, states, _ := buildModule(t, manifest, "unused")
|
||||
src := filepath.Join(m.Work, "ws1", "tree", "domain-a", "contracts")
|
||||
for name, body := range map[string]string{
|
||||
"module.json": manifest,
|
||||
"go/seats/aone/go.mod": "module git.example/c/domain-a/go/seats/aone\n\ngo 1.26\n", "go/seats/aone/a.go": "package aone\n",
|
||||
"go/seats/btwo/go.mod": "module git.example/c/domain-a/go/seats/btwo\n\ngo 1.26\n", "go/seats/btwo/b.go": "package btwo\n",
|
||||
"go/go.mod": "module git.example/c/domain-a/go\n\ngo 1.26\n", "go/w.go": "package w\n"} {
|
||||
if err := os.MkdirAll(filepath.Dir(filepath.Join(src, name)), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(src, name), []byte(body), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
store := withStore(t, m)
|
||||
for _, c := range []struct{ artifact, ref string }{
|
||||
{"go-aone", "git.example/c/domain-a/go/seats/aone@v0.1.3"},
|
||||
{"go-btwo", "git.example/c/domain-a/go/seats/btwo@v0.1.3"},
|
||||
{"go-whole", "git.example/c/domain-a/go@v0.1.3"},
|
||||
} {
|
||||
for _, tool := range m.Tools(m.StepTools()) {
|
||||
if tool.Name == "build_go_build" {
|
||||
args := map[string]any{"workspace": "ws1", "module": "domain-a/contracts", "artifact": c.artifact, "version": "v0.1.3", "seat": GoPackageSeat}
|
||||
if _, err := tool.Run(args); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
st := states.waitEnd(t)
|
||||
var res BuildResult
|
||||
if st.State != delivery.StepPassed {
|
||||
t.Fatalf("%s: %s %q", c.artifact, st.State, st.Reason)
|
||||
}
|
||||
_ = json.Unmarshal(st.Result, &res)
|
||||
if res.Reference != c.ref {
|
||||
t.Errorf("%s published as %q, want %q", c.artifact, res.Reference, c.ref)
|
||||
}
|
||||
}
|
||||
if len(store.published) != 3 {
|
||||
t.Fatalf("published %+v", store.published)
|
||||
}
|
||||
in := store.published[2]
|
||||
z, err := zip.NewReader(bytes.NewReader(store.blobs[in.Name+"@"+in.Digest]), int64(len(store.blobs[in.Name+"@"+in.Digest])))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, f := range z.File {
|
||||
if strings.Contains(f.Name, "/seats/") {
|
||||
t.Errorf("the zip of the folder's own package holds %s, a package of its own", f.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
@@ -109,15 +109,14 @@ func (m *Module) test(ctx context.Context, args map[string]any) (any, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// compareGenerated regenerates the generated Go files of each contracts module in the tree (the tree's own manifest and
|
||||
// each modules/<m>/module.json; CAT-BG5) and fails the level on any out of step, Why naming each path.
|
||||
// compareGenerated regenerates the generated Go files of each contracts module in the tree (every module.json in the tree, in
|
||||
// any folder: ADR 0634 §8; CAT-BG5) and fails the level on any out of step, Why naming each path.
|
||||
func compareGenerated(tree string, res *TestResult) error {
|
||||
manifests, _ := filepath.Glob(filepath.Join(tree, "modules", "*", "module.json"))
|
||||
if _, err := os.Stat(filepath.Join(tree, "module.json")); err == nil {
|
||||
manifests = append([]string{filepath.Join(tree, "module.json")}, manifests...)
|
||||
dirs, err := buildstep.ModuleDirs(tree)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, mf := range manifests {
|
||||
dir := filepath.Dir(mf)
|
||||
for _, dir := range dirs {
|
||||
paths, err := buildstep.OutOfStep(dir, buildstep.GeneratedRootGo)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -186,7 +186,6 @@ func TestUnitLevelOfAContractsModuleOutOfStepFailsNamingEachPath(t *testing.T) {
|
||||
tree := filepath.Join(m.Work, ws, "tree")
|
||||
for p, text := range map[string]string{
|
||||
"module.json": `{"module":"c","build":{"artifacts":[{"name":"go","kind":"package","language":"go","paths":["go"],"generated-from":"."}]}}`,
|
||||
"seats/index.json": `{"format":1,"seats":["one-store"]}`,
|
||||
"seats/one-store/seat.json": `{"format":1,"seat":"one-store","scope":"mesh","grain":"seat-list","decision":"ADR 1","verbs":[{"name":"query","input":{"type":"object"}}]}`,
|
||||
"go/go.mod": "module example.org/c/go\n",
|
||||
"go/stray.go": "package stray\n",
|
||||
@@ -212,6 +211,40 @@ func TestUnitLevelOfAContractsModuleOutOfStepFailsNamingEachPath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// ADR 0634 §8: the same for a contracts module in a folder of a tree whose root holds a module of its own (found by its
|
||||
// manifest, not by lying under modules/); a contracts module (a package artifact naming generated-from) whose generated Go files are out of step with
|
||||
// the seat generator fails the unit level, each path named in its out-of-step and its why; its TypeScript is not this
|
||||
// module's to compare.
|
||||
func TestUnitLevelOfAContractsModuleInAFolderOutOfStepFailsNamingEachPath(t *testing.T) {
|
||||
m, states, ws, _ := workspaceFor(t, "empty")
|
||||
tree := filepath.Join(m.Work, ws, "tree")
|
||||
for p, text := range map[string]string{
|
||||
"module.json": `{"module":"c","build":{"artifacts":[{"name":"go","kind":"package","language":"go","paths":["go"],"generated-from":"."}]}}`,
|
||||
"seats/one-store/seat.json": `{"format":1,"seat":"one-store","scope":"mesh","grain":"seat-list","decision":"ADR 1","verbs":[{"name":"query","input":{"type":"object"}}]}`,
|
||||
"go/go.mod": "module example.org/c/go\n",
|
||||
"go/stray.go": "package stray\n",
|
||||
"ts/package.json": `{"name":"@example/c"}`,
|
||||
"ts/stray.ts": "// not this module's\n",
|
||||
} {
|
||||
full := filepath.Join(tree, "domain", filepath.FromSlash(p))
|
||||
_ = os.MkdirAll(filepath.Dir(full), 0o755)
|
||||
if err := os.WriteFile(full, []byte(text), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
res, st := runUnit(t, m, states, ws)
|
||||
stray := false
|
||||
for _, p := range res.OutOfStep {
|
||||
stray = stray || p == "domain/go/stray.go"
|
||||
if !strings.HasPrefix(p, "domain/go/") {
|
||||
t.Errorf("%s is not under the folder's Go root", p)
|
||||
}
|
||||
}
|
||||
if st.State != delivery.StepPassed || res.Passed || !stray || !strings.Contains(res.Why, "domain/go/stray.go") {
|
||||
t.Errorf("result = %+v (%s %s)", res, st.State, st.Reason)
|
||||
}
|
||||
}
|
||||
|
||||
// A package that does not build fails the level with the compiler's words.
|
||||
func TestUnitLevelOfAPackageThatDoesNotBuildFailsWithTheCompilersLine(t *testing.T) {
|
||||
m, states, ws, _ := workspaceFor(t, "broken")
|
||||
|
||||
Reference in New Issue
Block a user