Files
mesh-delivery/modules/mesh-delivery-checker/internal/check/renames.go
T
jschoubben 2159375873 Merge the trunk: B0's facts and checking program carry the registry's steps (issue 1921, milestone 47/G D3-D11)
B0's shape wins: the running checker asks and records facts, the checking program
decides. The registry's types win: the rules and the program read the generated
checker contract and the domain SDK, and no mesh-sdk delivery import is left.
The registry's series, renames and unparsed seat definitions become facts with
their refusals as rules; the tagged versions ride on the case. The program reads
the heads' seat definitions through sdk/seatdefs and the running checker lays them
over its reader's list by seat, reading no file of the heads: the reader's list
is larger than a run input's bound.

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
2026-11-07 02:57:21 +01:00

101 lines
3.8 KiB
Go

package check
import (
"context"
"errors"
"mesh-delivery-checker/rules"
"git.novox.be/novox/mesh-contracts/go/seats/meshconfig"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// A config value renamed (design 32 *A config value renamed*, DLV-C5): the checker asks the seat mesh-config's verb
// renames, never the module, for every change that brings `renamed-from` or drops one. A holder that does not serve the
// verb refuses `renamed-from`, naming that; while a rename's window is open, dropping its `renamed-from` is refused,
// naming the nodes holding it open; a check that cannot ask fails, saying so.
// RenamesSeat is the verb the checker asks, as its manifest's `invokes` names it.
var RenamesSeat = rules.RenamesSeat
// ErrRenamesNotServed is the answer of Renames when the seat's holder serves no verb renames.
var ErrRenamesNotServed = errors.New("the holder of the seat " + meshconfig.Seat + " does not serve its verb " + meshconfig.VerbRenames)
// Renames asks the seat mesh-config's verb renames for a module's open renames.
type Renames interface {
Renames(ctx context.Context, module string) (meshconfig.RenamesAnswer, error)
}
// renameChange is what a pull request's head does to a module's `renamed-from` against the trunk: the declarations it
// brings (key from old name) and the ones it drops (key, old name).
type renameChange struct {
brought, dropped map[string]string
}
// renamesOf compares a module's config declarations at the trunk and at the head.
func renamesOf(was, now catalogue.Manifest) renameChange {
rc := renameChange{brought: map[string]string{}, dropped: map[string]string{}}
for key, d := range now.Settings {
if d.RenamedFrom != "" && was.Settings[key].RenamedFrom != d.RenamedFrom {
rc.brought[key] = d.RenamedFrom
}
}
for key, d := range was.Settings {
if d.RenamedFrom != "" && now.Settings[key].RenamedFrom != d.RenamedFrom {
rc.dropped[key] = d.RenamedFrom
}
}
return rc
}
// judgeRenames records, of each module a member changes that brings or drops a `renamed-from`, what it brings and drops
// and how the seat mesh-config's verb renames answered for it, as a fact the rules judge (rules.JudgeRenames): a rename
// whose value cannot be moved, and the drop of one whose window is open, fail the check (design 32).
func (st *state) judgeRenames(ctx context.Context) {
if st.c.Try != nil {
return
}
for _, p := range st.c.Pulls {
for _, module := range p.Modules {
r := rules.Renames{Module: module, Key: pullKey(p)}
was, now, ok, err := st.manifestPair(ctx, p, module)
if err != nil {
r.Unread = err.Error()
st.facts = append(st.facts, rules.Step{Repository: p.Repository, Number: p.Number, Renames: &r})
continue
}
if !ok {
was = catalogue.Manifest{} // a module new on the pull request brings every rename it declares
if now, ok = st.headManifest(ctx, p, module); !ok {
continue
}
}
rc := renamesOf(was, now)
if len(rc.brought) == 0 && len(rc.dropped) == 0 {
continue
}
r.Brought, r.Dropped = rc.brought, rc.dropped
if st.j.Renames != nil {
answer, err := st.j.Renames.Renames(ctx, module)
switch {
case err != nil:
r.Unasked, r.NotServed = err.Error(), errors.Is(err, ErrRenamesNotServed)
default:
r.Answer = &answer
}
}
st.facts = append(st.facts, rules.Step{Repository: p.Repository, Number: p.Number, Renames: &r})
}
}
}
func (st *state) headManifest(ctx context.Context, p Pull, module string) (catalogue.Manifest, bool) {
if digest := p.Fps[module].Manifest; digest != "" && st.j.Read != nil {
if st.j.Manifests != nil && st.j.Manifests.ManifestDigests()[module] == digest {
return catalogue.Manifest{}, false // unchanged
}
m, err := st.j.Read.Manifest(ctx, digest)
return m, err == nil
}
return catalogue.Manifest{}, false
}