diff --git a/modules/mesh-build-go/cmd/mesh-build-go/digest.go b/modules/mesh-build-go/cmd/mesh-build-go/digest.go index c3494d08..2a8310b3 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/digest.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/digest.go @@ -398,7 +398,10 @@ func packageDigest(root, testMain *goPackage, pkgs map[string]*goPackage, tree s if mod.Replace != nil { mod = mod.Replace } - if !mod.Main && mod.Version != "" { + // A module outside the tree counts by its version and checksum; a package of the mesh's own forge by the content of + // its files, as a local replacement does, so a new version of a mesh package whose reached files are the same keeps + // every verdict kept for them (ADR 0593 §5, ADR 0444 §3). + if !mod.Main && mod.Version != "" && !strings.HasPrefix(mod.Path, delivery.ForgeModulePrefix) { lines = append(lines, "module "+mod.Path+"@"+mod.Version+" "+mod.Sum) continue } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/digest_test.go b/modules/mesh-build-go/cmd/mesh-build-go/digest_test.go index 0a449589..09d5a441 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/digest_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/digest_test.go @@ -152,8 +152,9 @@ func TestTheDigestIsTheSameInAnotherWorkspace(t *testing.T) { } } -// A module outside the tree counts by its version and checksum, not by its files: the package of mesh-sdk, as go list -// gave it for this module's own dependency (testdata/captured/golist-external.json, which README describes). +// A module outside the tree counts by its version and checksum, not by its files: a package of a module that is not the +// mesh's, as go list gave it for this module's own dependency (testdata/captured/golist-external.json, which README +// describes). A package of the mesh's own forge counts by its files' content instead (ADR 0593 §5; the next test). func TestAModuleOutsideTheTreeCountsByVersionAndChecksum(t *testing.T) { raw, err := os.ReadFile(filepath.Join("testdata", "captured", "golist-external.json")) if err != nil { @@ -167,6 +168,7 @@ func TestAModuleOutsideTheTreeCountsByVersionAndChecksum(t *testing.T) { if ext == nil || ext.Module == nil || ext.Module.Sum == "" || ext.Module.Version == "" || ext.Module.Main { t.Fatalf("the capture holds no external package with a version and a checksum: %+v", ext) } + ext.Module.Path = "example.com/outside" // the capture's package, as a module that is not the mesh's dir := t.TempDir() os.WriteFile(filepath.Join(dir, "r.go"), []byte("package r\n"), 0o644) root := &goPackage{ImportPath: "x/r", Dir: dir, Module: &goModule{Path: "x", Main: true}, GoFiles: []string{"r.go"}, TestGoFiles: []string{"r.go"}} @@ -205,6 +207,52 @@ func TestAModuleOutsideTheTreeCountsByVersionAndChecksum(t *testing.T) { } } +// ADR 0593 §5 (C5): a package of the mesh's forge counts by the content of the files the tests reach, not by the version +// of its module. Two versions of mesh-sdk whose reached files are equal give one digest; a changed reached file changes it; +// a changed file of a package no test reaches does not. +func TestAMeshPackageCountsByTheContentOfTheFilesReached(t *testing.T) { + mesh := t.TempDir() + write := func(dir, name, text string) { + t.Helper() + if err := os.MkdirAll(dir, 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, name), []byte(text), 0o644); err != nil { + t.Fatal(err) + } + } + write(filepath.Join(mesh, "reached"), "a.go", "package reached\n") + write(filepath.Join(mesh, "unreached"), "b.go", "package unreached\n") + module := &goModule{Path: "git.novox.be/novox/mesh-sdk/go", Version: "v0.1.1", Sum: "h1:one="} + reached := &goPackage{ImportPath: module.Path + "/reached", Dir: filepath.Join(mesh, "reached"), Module: module, GoFiles: []string{"a.go"}} + unreached := &goPackage{ImportPath: module.Path + "/unreached", Dir: filepath.Join(mesh, "unreached"), Module: module, GoFiles: []string{"b.go"}} + own := t.TempDir() + write(own, "r.go", "package r\n") + root := &goPackage{ImportPath: "x/r", Dir: own, Module: &goModule{Path: "x", Main: true}, GoFiles: []string{"r.go"}, TestGoFiles: []string{"r.go"}} + pkgs := map[string]*goPackage{reached.ImportPath: reached, unreached.ImportPath: unreached, root.ImportPath: root} + testMain := &goPackage{ImportPath: "x/r.test", Deps: []string{reached.ImportPath}} + digest := func() string { + d, err := packageDigest(root, testMain, pkgs, own, []string{"digest 1"}, nil, nil, nil) + if err != nil { + t.Fatal(err) + } + return d + } + d1 := digest() + module.Version, module.Sum = "v0.2.0", "h1:two=" // a new version of the module whose reached files are the same + if d2 := digest(); d2 != d1 { + t.Errorf("a new version of mesh-sdk with equal reached files changed the digest") + } + write(filepath.Join(mesh, "unreached"), "b.go", "package unreached\n\nconst B = 1\n") + if d3 := digest(); d3 != d1 { + t.Errorf("a changed package no test reaches changed the digest") + } + write(filepath.Join(mesh, "reached"), "a.go", "package reached\n\nconst A = 1\n") + if d4 := digest(); d4 == d1 { + t.Errorf("a changed reached file left the digest as it was") + } +} + // Issue 1935, 1936: a package whose reads-outside marker lists nothing it can trust is never kept: its digest is one no // kept verdict can have (it differs on every call, though nothing changed), and the answer names it. A marker that lists // what the tests read is kept: a change to a file it names changes the package's digest, a change elsewhere does not.