Merge pull request 'A composer is kept per the package versions it was built with (issue 1921)' (#169) from fix/1921-zero-version-builds into main

This commit was merged in pull request #169.
This commit is contained in:
2026-11-06 08:00:15 +00:00
2 changed files with 32 additions and 9 deletions
+13 -3
View File
@@ -310,9 +310,19 @@ type ComposeAnswer struct {
// ComposerKey is the key a build module keeps a built composer under: the repository, commit, directory and package it // ComposerKey is the key a build module keeps a built composer under: the repository, commit, directory and package it
// was built from and the toolchain it was built with, hashed (`composer-` and 16 hex digits), so each head is built once // was built from and the toolchain it was built with, hashed (`composer-` and 16 hex digits), so each head is built once
// on a node (ADR 0482 clause 4). // on a node (ADR 0482 clause 4). The mesh package versions the ask names are an input of the build, so they are in the
func ComposerKey(repository, commit, dir, pkg string, toolchain ToolchainUsed) string { // key, sorted, when there are any; an ask that names none gets the key it always had (issue 1921).
sum := sha256.Sum256([]byte(strings.Join([]string{repository, commit, dir, pkg, toolchain.Version, toolchain.Recipe}, "\n"))) func ComposerKey(repository, commit, dir, pkg string, toolchain ToolchainUsed, versions PackageVersions) string {
parts := []string{repository, commit, dir, pkg, toolchain.Version, toolchain.Recipe}
pkgs := make([]string, 0, len(versions))
for p := range versions {
pkgs = append(pkgs, p)
}
sort.Strings(pkgs)
for _, p := range pkgs {
parts = append(parts, p+"="+versions[p])
}
sum := sha256.Sum256([]byte(strings.Join(parts, "\n")))
return "composer-" + hex.EncodeToString(sum[:8]) return "composer-" + hex.EncodeToString(sum[:8])
} }
+19 -6
View File
@@ -56,21 +56,34 @@ func TestAComposeAskIsRefusedWhereItDoesNotBelong(t *testing.T) {
} }
} }
// 1622/AC3: a composer is kept under one key per repository, commit, directory, package and toolchain, so two asks of // 1622/AC3, 1921: a composer is kept under one key per repository, commit, directory, package, toolchain and asked versions, so two asks of
// one head build it once on a node, and another head or toolchain builds its own. // one head build it once on a node, and another head or toolchain builds its own.
func TestAComposerIsKeptByWhatItWasBuiltFrom(t *testing.T) { func TestAComposerIsKeptByWhatItWasBuiltFrom(t *testing.T) {
tc := ToolchainUsed{Version: "go1.26.0", Recipe: "3"} tc := ToolchainUsed{Version: "go1.26.0", Recipe: "3"}
k := ComposerKey("novox/mesh-sdk", askCommit, "go", "p", tc) k := ComposerKey("novox/mesh-sdk", askCommit, "go", "p", tc, nil)
if k != ComposerKey("novox/mesh-sdk", askCommit, "go", "p", tc) || !strings.HasPrefix(k, "composer-") || len(k) != len("composer-")+16 { if k != ComposerKey("novox/mesh-sdk", askCommit, "go", "p", tc, nil) || !strings.HasPrefix(k, "composer-") || len(k) != len("composer-")+16 {
t.Fatalf("key = %q", k) t.Fatalf("key = %q", k)
} }
for _, other := range []string{ for _, other := range []string{
ComposerKey("novox/mesh-sdk", strings.Repeat("1", 40), "go", "p", tc), ComposerKey("novox/mesh-sdk", strings.Repeat("1", 40), "go", "p", tc, nil),
ComposerKey("novox/mesh-controller", askCommit, ".", "p", tc), ComposerKey("novox/mesh-controller", askCommit, ".", "p", tc, nil),
ComposerKey("novox/mesh-sdk", askCommit, "go", "p", ToolchainUsed{Version: "go1.26.1", Recipe: "3"}), ComposerKey("novox/mesh-sdk", askCommit, "go", "p", ToolchainUsed{Version: "go1.26.1", Recipe: "3"}, nil),
ComposerKey("novox/mesh-sdk", askCommit, "go", "p", tc, PackageVersions{"git.novox.be/novox/mesh-sdk/go": strings.Repeat("2", 40)}),
} { } {
if other == k { if other == k {
t.Errorf("two composers built from different inputs share the key %s", k) t.Errorf("two composers built from different inputs share the key %s", k)
} }
} }
// 1921: the asked versions are in the key, in any order of naming; none, or an empty ask, gives the key without them.
a, b := strings.Repeat("a", 40), strings.Repeat("b", 40)
k1 := ComposerKey("r", askCommit, "go", "p", tc, PackageVersions{"m/x": a, "m/y": b})
if k1 != ComposerKey("r", askCommit, "go", "p", tc, PackageVersions{"m/y": b, "m/x": a}) {
t.Error("the key depends on the order of the versions")
}
if k1 == ComposerKey("r", askCommit, "go", "p", tc, PackageVersions{"m/x": b, "m/y": a}) || k1 == ComposerKey("r", askCommit, "go", "p", tc, nil) {
t.Error("other versions, or none, share the key")
}
if ComposerKey("r", askCommit, "go", "p", tc, nil) != ComposerKey("r", askCommit, "go", "p", tc, PackageVersions{}) {
t.Error("an empty ask changed the key")
}
} }