package rules import ( "fmt" "maps" "slices" "strings" "git.novox.be/novox/mesh-contracts/go/seats/meshconfig" ) // The refusals of what the running checker asked of other seats for a check (milestone 47/G): it asks and records the // answers as facts, and these rules decide what fails. // RenamesSeat is the verb a change that brings or drops a `renamed-from` is asked of (design 32). var RenamesSeat = "seat:" + meshconfig.Seat + "." + meshconfig.VerbRenames // Renames is what one module of a member brings and drops of `renamed-from` (key to the old key), and how the seat // mesh-config's verb renames answered for it: Answer when it answered; else Unasked says why it was not asked or did not // answer, NotServed that its holder does not serve the verb. Unread says the module's manifests could not be read. type Renames struct { Module string `json:"module"` Key string `json:"key"` Brought map[string]string `json:"brought,omitempty"` Dropped map[string]string `json:"dropped,omitempty"` Answer *meshconfig.RenamesAnswer `json:"answer,omitempty"` Unasked string `json:"unasked,omitempty"` NotServed bool `json:"not-served,omitempty"` Unread string `json:"unread,omitempty"` } // JudgeRenames fails a rename the seat cannot move the value of, and the drop of a `renamed-from` while its window is // open on a node; it says which module the seat answered for. func JudgeRenames(r Renames) (failed []FailedFirst, notes []string) { at := func(words string) { failed = append(failed, FailedFirst{Machine: meshconfig.Seat, Words: words}) } switch { case r.Unread != "": at(fmt.Sprintf("%s (%s): its config renames cannot be judged: %s", r.Module, r.Key, r.Unread)) return failed, nil case r.NotServed: for _, key := range slices.Sorted(maps.Keys(r.Brought)) { at(fmt.Sprintf("%s (%s) renames %s from %s: refused, %s, so the value cannot be moved", r.Module, r.Key, key, r.Brought[key], r.Unasked)) } for _, key := range slices.Sorted(maps.Keys(r.Dropped)) { at(fmt.Sprintf("%s (%s) drops renamed-from %s of %s: refused, %s, so whether its window is open is not known", r.Module, r.Key, r.Dropped[key], key, r.Unasked)) } return failed, nil case r.Answer == nil && r.Unasked == "": at(fmt.Sprintf("%s (%s) changes a renamed-from, and this checker cannot ask %s", r.Module, r.Key, RenamesSeat)) return failed, nil case r.Answer == nil: at(fmt.Sprintf("%s (%s) changes a renamed-from, and the check cannot ask %s: %s", r.Module, r.Key, RenamesSeat, r.Unasked)) return failed, nil } for _, key := range slices.Sorted(maps.Keys(r.Dropped)) { for _, n := range r.Answer.Renames { if n.Module == r.Module && n.From == r.Dropped[key] && n.To == key && len(n.Open) > 0 { open := slices.Sorted(slices.Values(n.Open)) at(fmt.Sprintf("%s (%s) drops renamed-from %s of %s while its rename window is open on %s", r.Module, r.Key, n.From, key, strings.Join(open, ", "))) } } } return failed, []string{fmt.Sprintf("%s.%s answered for %s (%s)", meshconfig.Seat, meshconfig.VerbRenames, r.Module, r.Key)} } // SeatDefinitionsMachine names what refused a seat definition in a verdict's failure. const SeatDefinitionsMachine = "seat-definitions" // UnparsedSeat is one seat definition of a pull request's head that does not parse, as the indexer keeps it in its state // seat-definitions: the seat (the contracts module's name when its index did not parse), its module's directory and the // indexer's words of why. type UnparsedSeat struct { Seat string `json:"seat"` Module string `json:"module"` Directory string `json:"directory"` Why string `json:"why"` } // Unparsed is what the indexer keeps of one pull request's seat definitions that do not parse; Unread says why its state // could not be read. type Unparsed struct { Key string `json:"key"` Seats []UnparsedSeat `json:"seats,omitempty"` Unread string `json:"unread,omitempty"` } // JudgeUnparsed fails a pull request whose head's seat definition does not parse, naming the seat and where it lives // (design 26; the lead's ruling on A2i's finding 1), and one whose seat definitions cannot be read, since none is then // known to parse. func JudgeUnparsed(u Unparsed) []FailedFirst { if u.Unread != "" { return []FailedFirst{{Machine: SeatDefinitionsMachine, Words: fmt.Sprintf("%s: the indexer's seat definitions of it cannot be read, so none is known to parse: %s", u.Key, u.Unread)}} } var out []FailedFirst for _, s := range u.Seats { out = append(out, FailedFirst{Machine: SeatDefinitionsMachine, Words: fmt.Sprintf("%s: the seat definition of %s (module %s, %s) does not parse: %s", u.Key, s.Seat, s.Module, s.Directory, s.Why)}) } return out }