A release answers only the build whose fingerprint it moved: the indexer stamps the source revision at which a fingerprint last changed, a recompute with no merge the revision of its moment, and the assigner reads that stamp, never the Src a recompute keeps (ADR 0601 §1; review round 1, finding 1)
This commit is contained in:
@@ -803,18 +803,23 @@ func aReleasesApproveAnswersTheMoveOfItsBuildAlone(t *testing.T) {
|
||||
alone bool
|
||||
at string // the fingerprint the have runs
|
||||
mergedAt string // the commit the release merged web at; "" for no merge of the release
|
||||
fpSrc uint64 // the source revision at which web's fingerprint last changed
|
||||
yes, asked bool
|
||||
}{
|
||||
{"the build alone, its release approved", true, fpOld, commit, true, false},
|
||||
{"a setting changed too", false, fpOld, commit, false, true},
|
||||
{"a setting changed at the build it runs", true, fpTest, commit, false, true},
|
||||
{"no approved release carries it", true, fpOld, "", false, true},
|
||||
{"the release merged another commit", true, fpOld, strings.Repeat("2", 40), false, true},
|
||||
{"the build alone, its release approved", true, fpOld, commit, 7, true, false},
|
||||
{"a setting changed too", false, fpOld, commit, 7, false, true},
|
||||
{"a setting changed at the build it runs", true, fpTest, commit, 7, false, true},
|
||||
{"no approved release carries it", true, fpOld, "", 7, false, true},
|
||||
{"the release merged another commit", true, fpOld, strings.Repeat("2", 40), 7, false, true},
|
||||
// Review round 1: its fingerprint moved by a recompute after the release (a toolchain, a package), with no merge of
|
||||
// web: stamped with that moment's revision, whose release carries nothing of web; the earlier Approve answers nothing.
|
||||
{"a fingerprint moved by a recompute after the release", true, fpOld, commit, 8, false, true},
|
||||
{"a fingerprint whose revision is not known", true, fpOld, commit, 0, false, true},
|
||||
} {
|
||||
asksKV := &memKV{values: map[string][]byte{}}
|
||||
p := newPasser(buckets{delivery.AssignerAsksBucket: asksKV}, time.Now())
|
||||
p.logf = t.Logf
|
||||
mod, _ := delivery.EncodeModule(delivery.Module{FP2: fpTest, Repository: "novox/web", Commit: commit, Src: 7, Path: delivery.RootPath})
|
||||
mod, _ := delivery.EncodeModule(delivery.Module{FP2: fpTest, Repository: "novox/web", Commit: commit, Src: 7, FPSrc: c.fpSrc, Path: delivery.RootPath})
|
||||
p.w.put(delivery.ModulesBucket, "web", mod)
|
||||
src, _ := delivery.EncodeSource(delivery.Source{Group: "feat/web", Heads: map[string]string{"novox/web": commit}})
|
||||
p.w.putEntry(delivery.SourceBucket, delivery.SourceMainKey, src, 7, time.Now())
|
||||
@@ -827,6 +832,12 @@ func aReleasesApproveAnswersTheMoveOfItsBuildAlone(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
p.w.put(delivery.MergesBucket, "feat/web", merge)
|
||||
other, err := delivery.EncodeMerge(delivery.Merge{Group: "feat/other", Ask: "merge.feat_other.0123456789ab", Pulls: []delivery.MergePull{
|
||||
{Head: delivery.Head{Repository: "novox/x", Number: 4, Head: strings.Repeat("4", 40)}, State: delivery.MergeMerged, Commit: commit}}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
p.w.put(delivery.MergesBucket, "feat/other", other)
|
||||
}
|
||||
have, _ := delivery.EncodeHave(delivery.Have{FP: c.at, Composed: was, Phase: delivery.PhaseWaitingYes, Health: delivery.HealthOK,
|
||||
Judgement: delivery.JudgedRecreates, Waits: waiting, Detail: "it recreates web.server", BuildAlone: c.alone})
|
||||
|
||||
@@ -82,16 +82,17 @@ func (w *world) putEntry(bucket, key string, value []byte, revision uint64, at t
|
||||
}
|
||||
|
||||
// release is the release whose Approve carries module's build fp (ADR 0601 §1), and whether one does: the trunk's value of
|
||||
// the module names fp, the source revision it was first merged at names the release that moved it, and the gate's merge of
|
||||
// that release, which it writes on the operator's Approve, holds the module's own trunk merge among its merged pull
|
||||
// requests. Any of them unknown: none, and the move is asked of a person.
|
||||
// the module names fp, the source revision at which that fingerprint last changed (FPSrc, never the Src of its last merge,
|
||||
// which a recompute with no merge keeps) names the release that moved it, and the gate's merge of that release, which it
|
||||
// writes on the operator's Approve, holds the module's own trunk merge among its merged pull requests. Any of them
|
||||
// unknown: none, and the move is asked of a person.
|
||||
func (w *world) release(module, fp string) (string, bool) {
|
||||
t, ok := w.trunk()[module]
|
||||
if !ok || fp == "" || t.FP2 != fp || t.Src == 0 || t.Commit == "" {
|
||||
if !ok || fp == "" || t.FP2 != fp || t.FPSrc == 0 || t.Commit == "" {
|
||||
return "", false
|
||||
}
|
||||
w.mu.Lock()
|
||||
group := w.sourceGroups[t.Src]
|
||||
group := w.sourceGroups[t.FPSrc]
|
||||
w.mu.Unlock()
|
||||
key, err := delivery.MergesKey(group)
|
||||
if group == "" || err != nil {
|
||||
|
||||
@@ -14,6 +14,13 @@ import (
|
||||
// with it (Module.Src) when the head the source names for its repository is the merge commit the module's fingerprint
|
||||
// was computed at: from the modules bucket when the merge was heard first, and when the merge is heard after the source.
|
||||
|
||||
// sourceRev is the latest source revision seen, 0 before any.
|
||||
func (ix *Indexer) sourceRev() uint64 {
|
||||
ix.mu.Lock()
|
||||
defer ix.mu.Unlock()
|
||||
return ix.source.rev
|
||||
}
|
||||
|
||||
// sourceNow is the latest source revision seen.
|
||||
type sourceNow struct {
|
||||
rev uint64
|
||||
@@ -82,6 +89,9 @@ func (ix *Indexer) ApplySource(ctx context.Context, rev uint64, s delivery.Sourc
|
||||
return nil, false, nil
|
||||
}
|
||||
cur.Src = rev
|
||||
if cur.FPSrc == 0 {
|
||||
cur.FPSrc = rev // its fingerprint moved at this merge, whose revision is heard only now (ADR 0601 §1)
|
||||
}
|
||||
data, err := delivery.EncodeModule(cur)
|
||||
return data, false, err
|
||||
})
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestASourceRevisionStampsTheModulesOfTheRepositoriesHeadItNames(t *testing.
|
||||
}
|
||||
m, ok := moduleOf(t, mods, "a")
|
||||
want := before
|
||||
want.Src = 7
|
||||
want.Src, want.FPSrc = 7, 7 // its fingerprint moved at that merge (ADR 0601 §1)
|
||||
if !ok || !reflect.DeepEqual(m, want) {
|
||||
t.Errorf("module a = %+v (%v), want %+v: the fingerprint and the commit as the merge wrote them, with Src 7", m, ok, want)
|
||||
}
|
||||
|
||||
@@ -312,6 +312,11 @@ func (ix *Indexer) recomputeModules(ctx context.Context, overlay map[string]deli
|
||||
if cur.FP2 == r.fp && cur.None2 == r.none && reflect.DeepEqual(cur.Toolchains, r.tcs) && reflect.DeepEqual(cur.Packages, r.pkgs) {
|
||||
return nil, false, nil
|
||||
}
|
||||
if cur.FP2 != r.fp {
|
||||
// Moved with no merge of its own repository (a toolchain, a package, a base): the source revision of now, whose
|
||||
// release does not carry it, never the Src of the merge it was last merged at (ADR 0601 §1).
|
||||
cur.FPSrc = ix.sourceRev()
|
||||
}
|
||||
cur.FP2, cur.None2, cur.Toolchains, cur.Packages = r.fp, r.none, r.tcs, r.pkgs
|
||||
cur.Inputs2, cur.ArtifactPaths = inputs, paths
|
||||
data, err := delivery.EncodeModule(cur)
|
||||
@@ -355,6 +360,13 @@ func (ix *Indexer) writeOverlay(ctx context.Context, overlay, finals map[string]
|
||||
// refused or outgrown module as accepted; only the judge changes it.
|
||||
next.Verdict, next.Problems, next.Unknown, next.Warnings = cur.Verdict, cur.Problems, cur.Unknown, cur.Warnings
|
||||
}
|
||||
// The source revision at which FP2 last changed (ADR 0601 §1): this merge's when it moved it (0 until the
|
||||
// source revision naming the merge is heard, which stamps it), else the one held.
|
||||
if held && cur.FP2 == next.FP2 {
|
||||
next.FPSrc = cur.FPSrc
|
||||
} else {
|
||||
next.FPSrc = next.Src
|
||||
}
|
||||
if held && sameButWhere(cur, next) {
|
||||
return nil, false, nil
|
||||
}
|
||||
@@ -379,7 +391,7 @@ func (ix *Indexer) writeOverlay(ctx context.Context, overlay, finals map[string]
|
||||
// which only the judge writes: the module is unchanged.
|
||||
func sameButWhere(cur, next delivery.Module) bool {
|
||||
next = withV(next)
|
||||
next.Commit, next.Src = cur.Commit, cur.Src
|
||||
next.Commit, next.Src, next.FPSrc = cur.Commit, cur.Src, cur.FPSrc
|
||||
next.Verdict, next.Problems, next.Unknown, next.Warnings = cur.Verdict, cur.Problems, cur.Unknown, cur.Warnings
|
||||
return reflect.DeepEqual(cur, next)
|
||||
}
|
||||
|
||||
@@ -113,12 +113,20 @@ func TestAgreedToolchainChangesAGoModulesReasonWithNoMerge(t *testing.T) { // 14
|
||||
if m, _ := moduleOf(t, mods, "avahi"); m.None2 != delivery.ToolchainNoReport {
|
||||
t.Fatalf("before: none2 = %q", m.None2)
|
||||
}
|
||||
ix.mu.Lock()
|
||||
ix.source.rev = 11 // the source revision of now, whose release merged nothing of avahi's
|
||||
ix.mu.Unlock()
|
||||
reportToolchain(t, ix, "mesh-build-go", "novox", "go", "go1.27.1")
|
||||
reportToolchain(t, ix, "mesh-build-go", "ace", "go", "go1.27.1")
|
||||
m, _ := moduleOf(t, mods, "avahi")
|
||||
if m.None2 != "" || m.FP2 == "" {
|
||||
t.Errorf("none2 = %q fp2 = %q, want a fingerprint: no builder input is waited for (ADR 0530 §1)", m.None2, m.FP2)
|
||||
}
|
||||
// ADR 0601 §1: a fingerprint moved with no merge is stamped with the source revision of the moment, never the Src of
|
||||
// the merge it was last merged at, so no earlier release is taken to carry it.
|
||||
if m.FPSrc != 11 || m.Src == 11 {
|
||||
t.Errorf("a fingerprint moved by a recompute: fp-src %d, src %d; want fp-src 11", m.FPSrc, m.Src)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodesReportingDifferentVersionsLeaveTheReasonNamingBoth(t *testing.T) { // 1444/AC6
|
||||
|
||||
Reference in New Issue
Block a user