Merge pull request 'Promise the delivery seat's checks verb, optional until its holder serves it (hq ADR 0239)' (#117) from feat/delivery-checks-verb into main
This commit was merged in pull request #117.
This commit is contained in:
@@ -9,7 +9,7 @@ package catalogue
|
|||||||
// DeliverySeat is the seat mesh-delivery holds.
|
// DeliverySeat is the seat mesh-delivery holds.
|
||||||
const DeliverySeat = "mesh-delivery"
|
const DeliverySeat = "mesh-delivery"
|
||||||
|
|
||||||
// deliveryVerbs are the delivery seat's tools: five that read, and the acts of a person and of healer H2.
|
// deliveryVerbs are the delivery seat's tools: six that read, and the acts of a person and of healer H2.
|
||||||
func deliveryVerbs() []Verb {
|
func deliveryVerbs() []Verb {
|
||||||
return []Verb{
|
return []Verb{
|
||||||
{Name: "deliveries", Description: "Every delivery not final, and those that ended in the last day, one line " +
|
{Name: "deliveries", Description: "Every delivery not final, and those that ended in the last day, one line " +
|
||||||
@@ -32,6 +32,16 @@ func deliveryVerbs() []Verb {
|
|||||||
Input: schema(map[string]string{"repository": "owner/repository",
|
Input: schema(map[string]string{"repository": "owner/repository",
|
||||||
"paths": "the files it changes, comma-separated, from the repository's root",
|
"paths": "the files it changes, comma-separated, from the repository's root",
|
||||||
"base": "the branch it merges into (default main)"}, []string{"repository", "paths"})},
|
"base": "the branch it merges into (default main)"}, []string{"repository", "paths"})},
|
||||||
|
{Name: "checks", Description: "What the mesh's checks said of a pull request's head or of one commit: each " +
|
||||||
|
"of the commit's mesh statuses (mesh/merge-gate, mesh/repo-check, mesh/delivery, …) with its state, " +
|
||||||
|
"description and when it was set; the merge check's full verdict as the controller said it — each " +
|
||||||
|
"layer's summary, the machine that ran it, when, its build id and its report; and whether the branch's " +
|
||||||
|
"protection would let it merge, every required status being success.",
|
||||||
|
Input: schema(map[string]string{"repository": "owner/repository",
|
||||||
|
"number": "a pull request's number: its head is read",
|
||||||
|
"commit": "a commit's sha, or the start of one, instead of a pull request"}, []string{"repository"}),
|
||||||
|
// Added after the seat's first holder shipped: optional until mesh-delivery serves it everywhere.
|
||||||
|
Optional: true},
|
||||||
{Name: "table", Description: "The state table every delivery runs by: each transition with its guard, " +
|
{Name: "table", Description: "The state table every delivery runs by: each transition with its guard, " +
|
||||||
"each state's bound and what healer H2 may do once it has passed; and the machine steps' table.",
|
"each state's bound and what healer H2 may do once it has passed; and the machine steps' table.",
|
||||||
Input: schema(map[string]string{}, nil)},
|
Input: schema(map[string]string{}, nil)},
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package catalogue
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The delivery seat answers "what did the mesh's checks say of this pull request?" as a verb of its own,
|
||||||
|
// `checks` (novox/hq ADR 0239): read by repository and a pull request's number or a commit.
|
||||||
|
func TestTheDeliverySeatPromisesChecks(t *testing.T) {
|
||||||
|
seat, ok := SeatNamed(DeliverySeat)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("the delivery seat is not in the set")
|
||||||
|
}
|
||||||
|
var checks *Verb
|
||||||
|
for i := range seat.Serves {
|
||||||
|
if seat.Serves[i].Name == "checks" {
|
||||||
|
checks = &seat.Serves[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if checks == nil {
|
||||||
|
t.Fatalf("the delivery seat promises %v and not checks", VerbNames(seat.Serves))
|
||||||
|
}
|
||||||
|
props, _ := checks.Input["properties"].(map[string]any)
|
||||||
|
for _, arg := range []string{"repository", "number", "commit"} {
|
||||||
|
if _, has := props[arg]; !has {
|
||||||
|
t.Errorf("checks takes no %q", arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req, _ := checks.Input["required"].([]string); !reflect.DeepEqual(req, []string{"repository"}) {
|
||||||
|
t.Errorf("checks requires %v, wanted only the repository", req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added after the seat's holder shipped, it is optional: the holder serving the ten verbs before it still
|
||||||
|
// holds the seat, and one serving all eleven does too — so the controller and the catalogue can move in
|
||||||
|
// either order, and no check of the catalogue fails on a module nobody touched between the two.
|
||||||
|
if !checks.Optional {
|
||||||
|
t.Fatal("checks is a condition of holding before its holder serves it")
|
||||||
|
}
|
||||||
|
var before []string
|
||||||
|
for _, v := range VerbNames(seat.Serves) {
|
||||||
|
if v != "checks" {
|
||||||
|
before = append(before, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m := Manifest{Module: "mesh-delivery", Claims: []Claim{{Name: DeliverySeat, Scope: ScopeMesh, Serves: before}}}
|
||||||
|
if err := CanHold(m, seat); err != nil {
|
||||||
|
t.Fatalf("a holder without checks yet: %v", err)
|
||||||
|
}
|
||||||
|
m.Claims[0].Serves = VerbNames(seat.Serves)
|
||||||
|
if err := CanHold(m, seat); err != nil {
|
||||||
|
t.Fatalf("a holder serving every verb: %v", err)
|
||||||
|
}
|
||||||
|
// Every other verb is still a condition of holding.
|
||||||
|
m.Claims[0].Serves = append([]string{"checks"}, before[1:]...)
|
||||||
|
if err := CanHold(m, seat); err == nil || !strings.Contains(err.Error(), before[0]) {
|
||||||
|
t.Fatalf("a holder without %s: %v", before[0], err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,14 @@ type Verb struct {
|
|||||||
Description string `json:"description,omitempty"`
|
Description string `json:"description,omitempty"`
|
||||||
Input map[string]any `json:"input,omitempty"`
|
Input map[string]any `json:"input,omitempty"`
|
||||||
Output map[string]any `json:"output,omitempty"`
|
Output map[string]any `json:"output,omitempty"`
|
||||||
|
// Optional marks a verb added to a mesh seat whose holder lives in another repository (design 33 §7,
|
||||||
|
// additive within a version): a holder that serves it is accepted, and one that does not yet still
|
||||||
|
// holds the seat. Without it the addition would be a deadlock — this controller refusing the holder that
|
||||||
|
// does not serve the verb, the controller before it refusing the holder that does — and every check of
|
||||||
|
// the catalogue between the two would fail on a module nobody touched. Once every holder serves it,
|
||||||
|
// the mark is removed and the verb is a condition of holding like the rest. Never stored or said: the
|
||||||
|
// seat set's protocol is the compiled one.
|
||||||
|
Optional bool `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Verb) UnmarshalJSON(raw []byte) error {
|
func (v *Verb) UnmarshalJSON(raw []byte) error {
|
||||||
@@ -442,7 +450,7 @@ func unservedVerbs(tools []string, promised []Verb) []string {
|
|||||||
}
|
}
|
||||||
var missing []string
|
var missing []string
|
||||||
for _, v := range promised {
|
for _, v := range promised {
|
||||||
if !has[v.Name] {
|
if !has[v.Name] && !v.Optional {
|
||||||
missing = append(missing, v.Name)
|
missing = append(missing, v.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user