diff --git a/cmd/mesh-controller/bus_step.go b/cmd/mesh-controller/bus_step.go index 95a4880..e13854d 100644 --- a/cmd/mesh-controller/bus_step.go +++ b/cmd/mesh-controller/bus_step.go @@ -54,13 +54,13 @@ type busPending struct { machines []string from map[string]string to string - // same are the commits whose build made the same artifacts as the build the mesh holds. + // same are the commits whose build made the same artifacts and manifest as the build the mesh holds. same map[string]bool } // moves is whether sending the machine would replace its bus: a build it was not last sent, unless the -// two builds made the same artifacts — a rebuild of the same source for another module's merge changes -// nothing the machine runs. +// two builds made the same artifacts from the same manifest — a rebuild of the same source for another +// module's merge changes nothing the machine runs. func (b busPending) moves(machine string) bool { from, known := b.from[machine] if b.module == "" || b.to == "" || (known && sameCommit(from, b.to)) { @@ -93,7 +93,7 @@ func pendingBus(ctx context.Context, inv *inventory.Inventory) (busPending, erro return b, err } b.from, b.same = map[string]string{}, map[string]bool{} - made, err := madeBy(ctx, inv, b.module) + made, err := inv.BuildFingerprints(ctx, b.module) if err != nil { return b, err } @@ -397,28 +397,3 @@ func withBusStep(ctx context.Context) context.Context { } func busStepSending(ctx context.Context) bool { on, _ := ctx.Value(busStepKey{}).(bool); return on } - -// madeBy is, per commit, the artifacts the newest worked build of a module from it made, as one sorted -// string: what tells a rebuild that changes nothing from one that does. -func madeBy(ctx context.Context, inv *inventory.Inventory, module string) (map[string]string, error) { - builds, err := inv.Builds(ctx, module, 50) - if err != nil { - return nil, err - } - out := map[string]string{} - for _, b := range builds { - if !b.Worked() || b.Commit == "" { - continue - } - if _, seen := out[b.Commit]; seen { - continue - } - var refs []string - for _, a := range b.Made { - refs = append(refs, a.Name+"="+a.Reference) - } - sort.Strings(refs) - out[b.Commit] = strings.Join(refs, " ") - } - return out, nil -} diff --git a/internal/inventory/gate.go b/internal/inventory/gate.go index 0a0c5eb..a07639e 100644 --- a/internal/inventory/gate.go +++ b/internal/inventory/gate.go @@ -2,6 +2,8 @@ package inventory import ( "context" + "crypto/sha256" + "encoding/hex" "encoding/json" "errors" "fmt" @@ -216,3 +218,30 @@ func (i *Inventory) RestoreModule(ctx context.Context, b Build) error { } return nil } + +// BuildFingerprints is, per commit, what the newest successful build of a module from it would put on a +// machine — its artifacts and its manifest, hashed — so a rebuild that changes nothing there is told +// from one that does (the bus's planned step, ADR 0236). +func (i *Inventory) BuildFingerprints(ctx context.Context, module string) (map[string]string, error) { + rows, err := i.store.Pool().Query(ctx, + `select commit_hash, made, coalesce(manifest::text, '') from build + where module = $1 and failed = '' and commit_hash <> '' order by at desc limit 50`, module) + if err != nil { + return nil, err + } + defer rows.Close() + out := map[string]string{} + for rows.Next() { + var commit, manifest string + var made []byte + if err := rows.Scan(&commit, &made, &manifest); err != nil { + return nil, err + } + if _, seen := out[commit]; seen { + continue + } + sum := sha256.Sum256(append(append(made, 0), []byte(manifest)...)) + out[commit] = hex.EncodeToString(sum[:]) + } + return out, rows.Err() +}