Indexer: a registered module takes its registered ref, not a newer branch's record; no read at an older commit after a failure
mesh/delivery merged: source.main moved to novox/mesh-delivery@ead9ee2d138d
mesh/check checking 699cbfb7c131 on ead9ee2d138d

This commit is contained in:
2026-10-26 12:52:29 +01:00
parent 319d56be7e
commit 699cbfb7c1
3 changed files with 75 additions and 29 deletions
@@ -95,7 +95,7 @@ func (b *Builds) PathOf(module, repository string) (string, bool) {
// of it names it: the repository, the directory of its manifest there ("" or "." for the root) and the commit it was
// built at.
type Registration struct {
Module, Repository, Path, Commit string
Module, Repository, Path, Commit, Ref string
}
// registered is whether the record is an outcome that did not fail: what registers a module. Unlike IsTrunkBuild it
@@ -112,18 +112,47 @@ func registered(r delivery.BuildRecord) bool {
// first that holds the module's manifest is the one indexed.
func (b *Builds) RegistrationsOf(module string) []Registration {
type place struct{ repository, path string }
best := map[place]delivery.BuildRecord{}
byPlace := map[place][]delivery.BuildRecord{}
b.mu.Lock()
for _, r := range b.records {
if r.Module != module || !registered(r) {
continue
}
k := place{delivery.RepositoryName(r.Repository), pathOf(strings.Trim(r.Path, "/"))}
if cur, ok := best[k]; !ok || newer(r, cur) {
best[k] = r
if r.Module == module && registered(r) {
k := place{delivery.RepositoryName(r.Repository), pathOf(strings.Trim(r.Path, "/"))}
byPlace[k] = append(byPlace[k], r)
}
}
b.mu.Unlock()
// Within one place the record is that of the ref a registration comes from, never a newer pull request's or try's: a
// trunk's ref (main, master, trunk, none), else the ref most of the place's records name (the registered photos, de-spiegel
// and link2pay were built from nox-mesh), the newer of two equal; then its newest record.
best := map[place]delivery.BuildRecord{}
for k, recs := range byPlace {
count, latest := map[string]int{}, map[string]delivery.BuildRecord{}
for _, r := range recs {
count[r.Ref]++
if cur, ok := latest[r.Ref]; !ok || newer(r, cur) {
latest[r.Ref] = r
}
}
var pick string
first := true
for ref, rec := range latest {
switch {
case first:
case trunkLike[ref] != trunkLike[pick]:
if !trunkLike[ref] {
continue
}
case count[ref] != count[pick]:
if count[ref] < count[pick] {
continue
}
case !newer(rec, latest[pick]):
continue
}
pick, first = ref, false
}
best[k] = latest[pick]
}
recs := slices.Collect(maps.Values(best))
slices.SortFunc(recs, func(x, y delivery.BuildRecord) int {
switch {
@@ -141,7 +170,7 @@ func (b *Builds) RegistrationsOf(module string) []Registration {
})
out := make([]Registration, 0, len(recs))
for _, r := range recs {
out = append(out, Registration{Module: r.Module, Repository: r.Repository, Path: r.Path, Commit: r.Commit})
out = append(out, Registration{Module: r.Module, Repository: r.Repository, Path: r.Path, Commit: r.Commit, Ref: r.Ref})
}
return out
}
@@ -75,12 +75,6 @@ func (ix *Indexer) IndexRegistered(ctx context.Context, r Registration) error {
ix.tried[tried] = true
ix.mu.Unlock()
read, err := ix.Read(ctx, repository, commit, dir)
if err != nil && r.Commit != "" && r.Commit != commit {
// A head the forge no longer holds (a history that was rewritten) leaves the commit the module was registered at.
ix.logf("%s: reading %s at the head %s failed (%v), so at the registered commit %s", r.Module, repository, commit, err, r.Commit)
commit = r.Commit
read, err = ix.Read(ctx, repository, commit, dir)
}
if err != nil {
ix.mu.Lock()
delete(ix.tried, tried) // a forge that could not say is asked again
@@ -155,22 +155,45 @@ func TestARegistrationOfAnotherRepositoryDoesNotHideTheRealOne(t *testing.T) { /
}
}
func TestAHeadTheForgeLacksFallsBackToTheRegisteredCommit(t *testing.T) { // car-hunter: the source's head read as a 404
ix, mods := modulesIndexer(t, rec(t, "build-1", "snake", "http://novox.internal:20000/jschoubben/snake.git", "", "master", "", "2026-10-19T09:00:00Z", ""))
ix.Manifests = newMem()
ix.source = sourceNow{rev: 1, heads: map[string]string{"jschoubben/snake": h2}}
var asked []string
ix.Read = func(_ context.Context, _, sha, _ string) (RepoRead, error) {
asked = append(asked, sha)
if sha == h2 {
return RepoRead{}, errors.New("404")
func TestAForgeThatCannotSayLeavesTheModuleUnwrittenAndAsksAgain(t *testing.T) { // a timeout or a 404 at the head: no read at an older commit
for _, failure := range []string{"timeout", "Gitea API /repos/x/git/trees/y: 404 not found"} {
ix, mods := modulesIndexer(t, rec(t, "build-1", "snake", "http://novox.internal:20000/jschoubben/snake.git", "", "master", "", "2026-10-19T09:00:00Z", ""))
ix.Manifests = newMem()
ix.source = sourceNow{rev: 1, heads: map[string]string{"jschoubben/snake": h2}}
var asked []string
ix.Read = func(_ context.Context, _, sha, _ string) (RepoRead, error) {
asked = append(asked, sha)
return RepoRead{}, errors.New(failure)
}
if err := ix.IndexRegisteredAll(context.Background()); err == nil {
t.Errorf("%q: no error", failure)
}
if _, ok := moduleOf(t, mods, "snake"); ok || len(asked) != 1 || asked[0] != h2 {
t.Errorf("%q: written %v, asked %v", failure, ok, asked)
}
if err := ix.IndexRegisteredAll(context.Background()); err == nil || len(asked) != 2 {
t.Errorf("%q: not asked again (asked %v)", failure, asked)
}
return RepoRead{Root: "r0", Trees: map[string]string{"": "t1"}, Manifests: map[string]string{"": `{"module":"snake","version":"1"}`}}, nil
}
if err := ix.IndexRegisteredAll(context.Background()); err != nil {
t.Fatal(err)
}
func TestARecordOfAPullRequestDoesNotReplaceTheRegisteredRef(t *testing.T) { // a newer feat/x record of the same place
const repo = "http://novox.internal:20000/novox/photos.git"
b := NewBuilds()
for _, r := range [][2]any{
rec(t, "b1", "photos", repo, "", "nox-mesh", "", "2026-10-01T09:00:00Z", ""),
rec(t, "b2", "photos", repo, "", "nox-mesh", "", "2026-10-02T09:00:00Z", ""),
rec(t, "b3", "photos", repo, "", "feat/x", "", "2026-10-09T09:00:00Z", ""),
} {
b.Put(r[0].(string), r[1].([]byte))
}
if m, ok := moduleOf(t, mods, "snake"); !ok || m.Commit != "7a74cee83f88e6585a5511c3cc53bdf0f5303d20" || len(asked) != 2 {
t.Fatalf("modules.snake = %+v, found %v, asked %v", m, ok, asked)
got := b.RegistrationsOf("photos")
if len(got) != 1 || got[0].Ref != "nox-mesh" {
t.Fatalf("registrations = %+v, want the ref most records name, not the newer feat/x", got)
}
k, v := record(t, "b4", "photos", repo, "", "main", "", "2026-10-03T09:00:00Z", "")
b.Put(k, v) // a trunk's ref beats a branch of its own
if got := b.RegistrationsOf("photos"); len(got) != 1 || got[0].Ref != "main" {
t.Fatalf("registrations = %+v", got)
}
}