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
101 lines
3.8 KiB
Go
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
|
|
}
|