Write a preview of the conflicts for a head that does not merge, and give the candidate's modules the reason; pin mesh-sdk to the R4c-5a head (issue 1445)

This commit is contained in:
2026-10-21 21:25:45 +02:00
parent e554094b74
commit a2a5167d72
14 changed files with 59 additions and 21 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-delivery-builder
go 1.26.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021185947-afbe371003a5
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021192148-78364e318bdc
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.54.0
)
+2 -2
View File
@@ -1,5 +1,5 @@
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021185947-afbe371003a5 h1:1BiPKRPTYpgex8rSHWT9az0BteOafGWRDzd/Ba6GAcA=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021185947-afbe371003a5/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021192148-78364e318bdc h1:ZJScJSnF6LgFl55/VJ9RT/lNroVWun469sXtx0nlVYw=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021192148-78364e318bdc/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
@@ -443,7 +443,7 @@ func keptCount(t *testing.T, b *bed) int {
}
// TestAHeadThatDoesNotMergeFailsNamingTheFilesAndRunsNoTest: the fetch answers the files in conflict; the verdict fails naming
// them, no test or digest step is run, no preview is written and the status is owed as failure.
// them, no test or digest step is run, a preview of the conflicts alone is written and the status is owed as failure.
func TestAHeadThatDoesNotMergeFailsNamingTheFilesAndRunsNoTest(t *testing.T) { // 1289/AC4
b := startBed(t)
b.fake.conflict.Store(true)
@@ -459,8 +459,11 @@ func TestAHeadThatDoesNotMergeFailsNamingTheFilesAndRunsNoTest(t *testing.T) { /
if n := b.fake.count("mesh-build-go.build_go_digest") + b.fake.count("mesh-build-go.build_go_test"); n != 0 {
t.Errorf("%d digest and test steps ran after a conflict", n)
}
if keys, _ := b.buckets[delivery.PreviewsBucket].Keys(b.ctx); len(keys) != 0 {
t.Errorf("previews %v for a head that does not merge", keys)
pk, _ := delivery.PreviewKey(repo, head1, trunk)
if e, err := b.buckets[delivery.PreviewsBucket].Get(b.ctx, pk); err != nil {
t.Errorf("previews.%s: %v", pk, err)
} else if pv, err := delivery.DecodePreview(e.Value()); err != nil || strings.Join(pv.Conflicts, ",") != "a.go,sub/b.go" || pv.Merge != "" {
t.Errorf("preview = %+v, %v, want the files in conflict alone", pv, err)
}
}
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-delivery-checker
go 1.26.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021185947-afbe371003a5
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021192148-78364e318bdc
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.54.0
)
+2 -4
View File
@@ -1,7 +1,5 @@
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021100209-cb54756c3865 h1:VLir9NZbyi1LdH1YwWDIVRuL+lDC+AYlm6FZPlvmlm4=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021100209-cb54756c3865/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021185947-afbe371003a5 h1:1BiPKRPTYpgex8rSHWT9az0BteOafGWRDzd/Ba6GAcA=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021185947-afbe371003a5/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021192148-78364e318bdc h1:ZJScJSnF6LgFl55/VJ9RT/lNroVWun469sXtx0nlVYw=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021192148-78364e318bdc/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
@@ -481,12 +481,18 @@ func TestACleanMergeWritesItsPreviewWithTheTreesManifestsAndLocks(t *testing.T)
}
}
func TestAHeadThatDoesNotMergeWritesNoPreview(t *testing.T) { // 1445/AC5
func TestAHeadThatDoesNotMergeWritesAPreviewOfItsConflictsAlone(t *testing.T) { // 1445/AC5
b := newBench(t)
b.fetch = captured[Fetched](t, "go-fetch-conflict")
b.judge(t, caseOf(t, pullOf(repoA, 7, head1)))
if len(b.prev.vals) != 0 {
t.Errorf("previews %v written for a head that does not merge", b.prev.vals)
key, _ := delivery.PreviewKey(repoA, head1, trunkA)
raw, _, found, _ := b.prev.Get(context.Background(), key)
if !found {
t.Fatalf("no preview for a head that does not merge; the bucket holds %v", b.prev.vals)
}
pv, err := delivery.DecodePreview(raw)
if err != nil || strings.Join(pv.Conflicts, ",") != "a.go,sub/b.go" || pv.Merge != "" || len(pv.Modules) != 0 {
t.Errorf("preview = %+v, %v, want the files in conflict and no merge", pv, err)
}
}
@@ -226,6 +226,7 @@ func (st *state) fetchAll(ctx context.Context) *delivery.Verdict {
return fail(node, fmt.Sprintf("the fetch of %s#%d answered no workspace: %s", p.Repository, p.Number, raw))
}
if len(t.fetched.Conflicts) > 0 {
st.j.writePreview(ctx, p, append(merged, t.fetched))
return fail(node, fmt.Sprintf("%s#%d does not merge into the trunk: files in conflict: %s", p.Repository, p.Number, strings.Join(t.fetched.Conflicts, ", ")))
}
t.changed = t.fetched.Changed
@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"regexp"
"slices"
"git.novox.be/novox/mesh-sdk/go/delivery"
)
@@ -15,10 +16,22 @@ var digest64 = regexp.MustCompile(`^[0-9a-f]{64}$`)
// key (ADR 0484 clause 3): the merge commit and, for each module directory the fetches named with a manifest, its tree, the
// digest of its manifest and the hashes of its lock files. The fetches of the repository's build modules merge the same
// trees; the first one's merge commit is kept. A module directory with no tree or no manifest digest is left out, so the
// indexer gives its module no fingerprint and says why. It answers false when no fetch merged.
// indexer gives its module no fingerprint and says why. A head that does not merge has a preview of the files in conflict
// alone, so the indexer says the candidate's modules have no fingerprint because it does not merge (issue 1445). It
// answers false when no fetch was made.
func PreviewOf(p Pull, fetched []Fetched) (delivery.Preview, bool) {
var merge string
var conflicts []string
mods := map[string]delivery.PreviewModule{}
for _, f := range fetched {
if len(f.Conflicts) > 0 {
conflicts = append(conflicts, f.Conflicts...)
}
}
if len(conflicts) > 0 {
slices.Sort(conflicts)
return delivery.Preview{Repository: p.Repository, Head: p.Head, Trunk: p.Trunk, Conflicts: slices.Compact(conflicts)}, true
}
for _, f := range fetched {
if f.Merge == "" {
continue
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-delivery-forge-bridge
go 1.26.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021185947-afbe371003a5
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021192148-78364e318bdc
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.54.0
)
+2 -2
View File
@@ -1,5 +1,5 @@
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021185947-afbe371003a5 h1:1BiPKRPTYpgex8rSHWT9az0BteOafGWRDzd/Ba6GAcA=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021185947-afbe371003a5/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021192148-78364e318bdc h1:ZJScJSnF6LgFl55/VJ9RT/lNroVWun469sXtx0nlVYw=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021192148-78364e318bdc/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-delivery-indexer
go 1.26.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021185947-afbe371003a5
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021192148-78364e318bdc
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.54.0
)
+2 -2
View File
@@ -1,5 +1,5 @@
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021185947-afbe371003a5 h1:1BiPKRPTYpgex8rSHWT9az0BteOafGWRDzd/Ba6GAcA=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021185947-afbe371003a5/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021192148-78364e318bdc h1:ZJScJSnF6LgFl55/VJ9RT/lNroVWun469sXtx0nlVYw=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261021192148-78364e318bdc/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
@@ -19,6 +19,9 @@ import (
const (
// NonePreviewStale is for a module whose preview was made onto a trunk head that is not the trunk's head now.
NonePreviewStale = "the merge preview is out of date: the trunk moved since it was made"
// NonePreviewConflict opens the reason of a module whose pull request's head does not merge into the trunk; the files
// in conflict follow.
NonePreviewConflict = "does not merge: the head conflicts with the trunk in "
// NonePreviewNoModule is for a module whose directory the preview names no manifest for.
NonePreviewNoModule = "the merge preview names no manifest for the module's directory"
// NonePreviewNoManifest is for a module whose manifest at the merge the indexer does not hold.
@@ -150,6 +153,8 @@ func (ix *Indexer) withPreviews(ctx context.Context, c *delivery.Candidate) bool
switch {
case stale:
next.None2 = NonePreviewStale
case len(pv.Conflicts) > 0:
next.None2 = NonePreviewConflict + strings.Join(pv.Conflicts, ", ")
default:
dir, known := dirs[m]
if !known {
@@ -179,3 +179,15 @@ func TestTheSamePreviewAppliedAgainWritesNothing(t *testing.T) {
t.Errorf("candidates written %d times for the same preview, want none", cands.writes-w)
}
}
func TestAPreviewOfConflictsGivesTheCandidatesModuleTheReasonItDoesNotMerge(t *testing.T) { // 1445/AC5
ix, _, cands := previewBed(t, true)
if err := ix.Apply(context.Background(), avahiPull(t, h1)); err != nil {
t.Fatal(err)
}
applyPreview(t, ix, delivery.Preview{Repository: catalogueRepo, Head: h1, Trunk: trunkNow, Conflicts: []string{"modules/avahi/main.go", "go.mod"}})
got := fpOf(t, cands)
if got.FP2 != "" || !strings.HasPrefix(got.None2, "does not merge") || !strings.Contains(got.None2, "go.mod, modules/avahi/main.go") && !strings.Contains(got.None2, "modules/avahi/main.go, go.mod") {
t.Errorf("candidate avahi = %+v, want it not merging and naming the files", got)
}
}