Answer the verbs release 6 removed by name, and drop the merge window and push settings from the manifest (release 6, issue 1945 B10)
This commit is contained in:
@@ -360,6 +360,9 @@ func connectionName(command, verb string) string {
|
|||||||
// removedByName refuses a command the controller no longer has, naming what replaced it (novox/hq ADR 0501 §4, §5;
|
// removedByName refuses a command the controller no longer has, naming what replaced it (novox/hq ADR 0501 §4, §5;
|
||||||
// ADR 0429 §18; ADR 0503 §3; issue 1851, A11, and issue 1318).
|
// ADR 0429 §18; ADR 0503 §3; issue 1851, A11, and issue 1318).
|
||||||
func removedByName(command string) error {
|
func removedByName(command string) error {
|
||||||
|
if why, removed := removedInRelease6(command); removed {
|
||||||
|
return &removedCommand{msg: fmt.Sprintf("`%s` no longer exists: %s", command, why)}
|
||||||
|
}
|
||||||
replacement := map[string]string{
|
replacement := map[string]string{
|
||||||
"build": "the controller asks no build (ADR 0501 §5): the builder builds every fingerprint the indexer writes, a " +
|
"build": "the controller asks no build (ADR 0501 §5): the builder builds every fingerprint the indexer writes, a " +
|
||||||
"module is registered from its done key, and a branch is tried with `try`; a module from a repository the " +
|
"module is registered from its done key, and a branch is tried with `try`; a module from a repository the " +
|
||||||
@@ -382,6 +385,8 @@ func removedByName(command string) error {
|
|||||||
"resume, or its capacity",
|
"resume, or its capacity",
|
||||||
"forget-checks": "build-agent makes no check build from R4e (ADR 0503 §3), so there is nothing to let go of",
|
"forget-checks": "build-agent makes no check build from R4e (ADR 0503 §3), so there is nothing to let go of",
|
||||||
"delivery-plan": "a delivery's plan is read with `delivery-order` and the checker's verdict (ADR 0503 §3)",
|
"delivery-plan": "a delivery's plan is read with `delivery-order` and the checker's verdict (ADR 0503 §3)",
|
||||||
|
"durations": "the controller measures no sends, tiers or applies since release 6 (ADR 0539 §17): the haves and wants " +
|
||||||
|
"on the bus carry what a delivery took",
|
||||||
"delivery-check": "the checker judges every head and every delivery group (ADR 0503 §3, ADR 0527): the controller asks " +
|
"delivery-check": "the checker judges every head and every delivery group (ADR 0503 §3, ADR 0527): the controller asks " +
|
||||||
"nothing and says no verdict of a pull request",
|
"nothing and says no verdict of a pull request",
|
||||||
}[command]
|
}[command]
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ func argvFor(verb string, args map[string]any) ([]string, error) {
|
|||||||
if removedVerbs[verb] {
|
if removedVerbs[verb] {
|
||||||
return nil, removedByName(verb)
|
return nil, removedByName(verb)
|
||||||
}
|
}
|
||||||
|
if why, removed := removedInRelease6(verb); removed {
|
||||||
|
return nil, &removedCommand{msg: fmt.Sprintf("`%s` no longer exists: %s", verb, why)}
|
||||||
|
}
|
||||||
a, err := readArguments(verb, args)
|
a, err := readArguments(verb, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -93,13 +96,15 @@ type verbArguments struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// removedVerbs are the controller seat's verbs R4e removed, kept in its table with no input so a caller is answered
|
// removedVerbs are the controller seat's verbs R4e removed, kept in its table with no input so a caller is answered
|
||||||
// by name (ADR 0501 §5, ADR 0503 §3, ADR 0450 §8).
|
// by name (ADR 0501 §5, ADR 0503 §3, ADR 0450 §8). The verbs release 6 removed are catalogue.RemovedControllerVerbs.
|
||||||
var removedVerbs = map[string]bool{"build": true, "rebuild": true, "forget-checks": true, "delivery-plan": true,
|
var removedVerbs = map[string]bool{"build": true, "rebuild": true, "forget-checks": true, "delivery-plan": true,
|
||||||
"delivery-check": true, "queue": true, "cancel": true, "clear": true, "kill": true, "replay": true, "pause": true, "resume": true,
|
"delivery-check": true, "queue": true, "cancel": true, "clear": true, "kill": true, "replay": true, "pause": true, "resume": true}
|
||||||
// Release 6 (ADR 0539 §5): a delivery is each machine following its wants, so the verbs that planned, started, stopped,
|
|
||||||
// retried or closed one are gone.
|
// removedInRelease6 says a verb is one release 6 removed (ADR 0539, ADR 0429 §8): refused by name, with its replacement.
|
||||||
"plans": true, "plan": true, "push": true, "deliver": true, "delivery-stop": true, "delivery-backups-again": true,
|
func removedInRelease6(verb string) (string, bool) {
|
||||||
"delivery-walks": true, "delivery-order": true}
|
why, removed := catalogue.RemovedControllerVerbs[verb]
|
||||||
|
return why, removed
|
||||||
|
}
|
||||||
|
|
||||||
// controllerVerb is this binary's own definition of a verb: what it runs is what it declares, so the
|
// controllerVerb is this binary's own definition of a verb: what it runs is what it declares, so the
|
||||||
// arguments are checked against the table compiled beside argvFor, not a row a newer or older build
|
// arguments are checked against the table compiled beside argvFor, not a row a newer or older build
|
||||||
@@ -1187,47 +1192,6 @@ var inProcess = map[string]bool{"tools": true, "calls": true, "doctor": true,
|
|||||||
// issue 1937).
|
// issue 1937).
|
||||||
"held": true}
|
"held": true}
|
||||||
|
|
||||||
// pushFileVar names the file the controller's push settings are written to (module.json, `push-wait`).
|
|
||||||
const pushFileVar = "MESH_PUSH_FILE"
|
|
||||||
|
|
||||||
// pushWait is how long a push to a named machine waits for its answer (novox/hq issue 629): the call's own
|
|
||||||
// `wait` when given, else the controller's setting `push-wait`, else nothing. No length is written here: the
|
|
||||||
// setting's default is the module's, and a setting that cannot be read waits for nothing, as a push did
|
|
||||||
// before, and is said.
|
|
||||||
func pushWait(given string) (time.Duration, error) {
|
|
||||||
if strings.TrimSpace(given) != "" {
|
|
||||||
d, ok := durationSetting(given)
|
|
||||||
if !ok {
|
|
||||||
return 0, fmt.Errorf("push: wait %q is no duration: say it as \"90s\", \"2m\", or \"0\" to wait for nothing", given)
|
|
||||||
}
|
|
||||||
return d, nil
|
|
||||||
}
|
|
||||||
path := os.Getenv(pushFileVar)
|
|
||||||
if path == "" {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
raw, err := os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "the push settings cannot be read (%v); a push waits for nothing\n", err)
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
var values map[string]any
|
|
||||||
if err := json.Unmarshal(raw, &values); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "the push settings are not JSON (%v); a push waits for nothing\n", err)
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
v, has := values["push-wait"]
|
|
||||||
if !has || v == "" {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
d, ok := durationSetting(v)
|
|
||||||
if !ok {
|
|
||||||
fmt.Fprintf(os.Stderr, "the setting push-wait=%v is no duration; a push waits for nothing\n", v)
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
return d, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// answersFirst is a command line whose caller is answered before it runs: a push, by its verb or
|
// answersFirst is a command line whose caller is answered before it runs: a push, by its verb or
|
||||||
// through `command`. A push sends the machine holding the bus first when its user list changed, the
|
// through `command`. A push sends the machine holding the bus first when its user list changed, the
|
||||||
// broker reloads, and a reload forgets every answer the bus was about to permit — so an answer
|
// broker reloads, and a reload forgets every answer the bus was about to permit — so an answer
|
||||||
|
|||||||
@@ -3,8 +3,13 @@ package main
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// `builds` given a build's id no longer reads a log from the bus: the build seat is retired (ADR 0525 clause 7).
|
// `builds` given a build's id no longer reads a log from the bus: the build seat is retired (ADR 0525 clause 7).
|
||||||
@@ -226,3 +231,58 @@ func TestAQuotedValueRoundTrips(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// **A verb release 6 removed is refused by name, with what replaces it** (ADR 0539, ADR 0429 §8, issue 1945 B10): every
|
||||||
|
// verb of catalogue.RemovedControllerVerbs is answered "no longer exists" naming itself and its replacement, whatever
|
||||||
|
// arguments it is given, and the tool-call path and the terminal's command line give the same words.
|
||||||
|
func TestTheVerbsReleaseSixRemovedAreRefusedByName(t *testing.T) {
|
||||||
|
if len(catalogue.RemovedControllerVerbs) == 0 {
|
||||||
|
t.Fatal("the SDK lists no removed controller verb")
|
||||||
|
}
|
||||||
|
for verb, why := range catalogue.RemovedControllerVerbs {
|
||||||
|
argv, err := argvFor(verb, map[string]any{"node": "anchor", "why": "w"})
|
||||||
|
if err == nil || len(argv) != 0 {
|
||||||
|
t.Errorf("%s was composed into %v", verb, argv)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, want := range []string{"`" + verb + "`", "no longer exists", why} {
|
||||||
|
if !strings.Contains(err.Error(), want) {
|
||||||
|
t.Errorf("%s: the refusal %q lacks %q", verb, err, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cmd := removedByName(verb); cmd == nil || cmd.Error() != err.Error() {
|
||||||
|
t.Errorf("%s: the terminal says %v, the tool says %v", verb, cmd, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The controller's size, printed against the 111,386 non-test lines its repository held before release 6 (acceptance test 20, ADR
|
||||||
|
// 0539 §17): raw lines of every non-test Go file of the module, which the pull request reports.
|
||||||
|
func TestTheControllersNonTestLinesArePrinted(t *testing.T) {
|
||||||
|
const before = 111386
|
||||||
|
total := 0
|
||||||
|
err := filepath.WalkDir("../..", func(path string, d fs.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if d.IsDir() && (d.Name() == ".git" || d.Name() == "testdata") {
|
||||||
|
return filepath.SkipDir
|
||||||
|
}
|
||||||
|
if d.IsDir() || !strings.HasSuffix(path, ".go") || strings.HasSuffix(path, "_test.go") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
raw, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
total += strings.Count(string(raw), "\n")
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Logf("non-test Go lines: %d against %d before release 6 (%+d)", total, before, total-before)
|
||||||
|
if total >= before {
|
||||||
|
t.Errorf("the controller holds %d non-test lines, no fewer than the %d it held before release 6", total, before)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+1
-37
@@ -25,23 +25,6 @@
|
|||||||
},
|
},
|
||||||
"secrets-owner": "mesh-controller",
|
"secrets-owner": "mesh-controller",
|
||||||
"prepares": true,
|
"prepares": true,
|
||||||
"settings": {
|
|
||||||
"merge-window": {
|
|
||||||
"kind": "preference",
|
|
||||||
"default": "90s",
|
|
||||||
"why": "merges are collected while they keep coming, and a batch is planned once no merge came for this long (novox/hq ADR 0276)"
|
|
||||||
},
|
|
||||||
"merge-window-at-most": {
|
|
||||||
"kind": "preference",
|
|
||||||
"default": "10m",
|
|
||||||
"why": "a busy period never holds a batch longer than this after its first merge (novox/hq ADR 0276)"
|
|
||||||
},
|
|
||||||
"push-wait": {
|
|
||||||
"kind": "preference",
|
|
||||||
"default": "2m",
|
|
||||||
"why": "how long a push to a named machine waits for that machine's answer, so its call says how it went; a call's own wait overrides it, and 0 waits for nothing (novox/hq issue 629)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tools": [
|
"tools": [
|
||||||
"tools",
|
"tools",
|
||||||
"calls",
|
"calls",
|
||||||
@@ -124,23 +107,6 @@
|
|||||||
"place": "mesh",
|
"place": "mesh",
|
||||||
"owner": "mesh-controller"
|
"owner": "mesh-controller"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "merge-window",
|
|
||||||
"type": "file",
|
|
||||||
"path": "${dir:mesh-state}/merge-window.json",
|
|
||||||
"mode": "0600",
|
|
||||||
"owner": "mesh-controller",
|
|
||||||
"content": "{\n \"merge-window\": \"${setting:merge-window}\",\n \"merge-window-at-most\": \"${setting:merge-window-at-most}\"\n}\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "push",
|
|
||||||
"trusted": false,
|
|
||||||
"type": "file",
|
|
||||||
"path": "${dir:mesh-state}/push.json",
|
|
||||||
"mode": "0600",
|
|
||||||
"owner": "mesh-controller",
|
|
||||||
"content": "{\n \"push-wait\": \"${setting:push-wait}\"\n}\n"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "controller",
|
"id": "controller",
|
||||||
"type": "process",
|
"type": "process",
|
||||||
@@ -164,9 +130,7 @@
|
|||||||
"MESH_BROKER_MANAGEMENT_PORT": "${seat:mesh-broker:15672}",
|
"MESH_BROKER_MANAGEMENT_PORT": "${seat:mesh-broker:15672}",
|
||||||
"MESH_BROKER_ADDRESS_PORT": "${seat:mesh-broker:5671}",
|
"MESH_BROKER_ADDRESS_PORT": "${seat:mesh-broker:5671}",
|
||||||
"MESH_BUS_NATS_FILE": "${dir:mesh-state}/bus",
|
"MESH_BUS_NATS_FILE": "${dir:mesh-state}/bus",
|
||||||
"MESH_CONTROLLER_VERSION": "${version}",
|
"MESH_CONTROLLER_VERSION": "${version}"
|
||||||
"MESH_MERGE_WINDOW_FILE": "${dir:mesh-state}/merge-window.json",
|
|
||||||
"MESH_PUSH_FILE": "${dir:mesh-state}/push.json"
|
|
||||||
},
|
},
|
||||||
"replaces": [
|
"replaces": [
|
||||||
"server"
|
"server"
|
||||||
|
|||||||
Reference in New Issue
Block a user