The plans verb: what the last merges produced and where each stands (hq ADR 0162)

The mesh's seat answers plans — the recent plans with their tier, what each waits for and since when,
or one plan whole given its id — so the console reads a merge's progress where it reads everything
else, instead of a person reading the daemon's log.
This commit is contained in:
2026-10-01 17:58:49 +02:00
parent d2ed6d50c9
commit 09b636e628
4 changed files with 71 additions and 0 deletions
+2
View File
@@ -72,6 +72,8 @@ func run() error {
return askCommand(ctx, args[1:]) return askCommand(ctx, args[1:])
case "builds": case "builds":
return buildsCommand(ctx, args[1:]) return buildsCommand(ctx, args[1:])
case "plans":
return plansCommand(ctx, args[1:])
case "pin": case "pin":
return pinCommand(ctx, args[1:], true) return pinCommand(ctx, args[1:], true)
case "unpin": case "unpin":
+61
View File
@@ -2,6 +2,7 @@ package main
import ( import (
"context" "context"
"flag"
"fmt" "fmt"
"sort" "sort"
"strings" "strings"
@@ -524,3 +525,63 @@ func openPlans(plans []inventory.Plan) ([]inventory.Plan, int) {
} }
return open, late return open, late
} }
// plansCommand says what the last merges produced and where each stands; given an id, one plan
// tier by tier with every module's state.
func plansCommand(ctx context.Context, args []string) error {
set := flag.NewFlagSet("plans", flag.ContinueOnError)
limit := set.Int("n", 10, "how many to show")
positionals, err := parseAround(set, args)
if err != nil {
return err
}
open, err := openStores(ctx)
if err != nil {
return err
}
defer open.Close()
inv := open.inventory
now := time.Now()
if len(positionals) == 1 {
p, err := inv.PlanByID(ctx, positionals[0])
if err != nil {
return err
}
fmt.Printf("%s — %s\n", p.ID, planLine(p, now))
for i, tier := range p.Tiers {
marker := " "
if i == p.Tier && p.Open() {
marker = ">"
}
fmt.Printf("%s tier %d\n", marker, i)
for _, m := range tier {
s := p.Modules[m]
state := "not yet asked"
if s != nil && s.State != "" {
state = s.State
if s.Commit != "" {
state += " from " + short(s.Commit)
}
if s.Why != "" {
state += ": " + s.Why
}
}
fmt.Printf(" %-22s %s\n", m, state)
}
}
return nil
}
plans, err := inv.RecentPlans(ctx, *limit)
if err != nil {
return err
}
if len(plans) == 0 {
fmt.Println("no merge has produced a plan yet")
return nil
}
for _, p := range plans {
fmt.Printf("%-28s %s\n", p.ID, planLine(p, now))
}
return nil
}
+5
View File
@@ -69,6 +69,11 @@ func argvFor(verb string, args map[string]any) ([]string, error) {
return []string{"builds", m}, nil return []string{"builds", m}, nil
} }
return []string{"builds"}, nil return []string{"builds"}, nil
case "plans":
if id := str("id"); id != "" {
return []string{"plans", id}, nil
}
return []string{"plans"}, nil
case "plan": case "plan":
if err := need("node"); err != nil { if err := need("node"); err != nil {
return nil, err return nil, err
+3
View File
@@ -91,6 +91,9 @@ var ControllerVerbs = []Verb{
"module": "one module's name; every module when absent", "module": "one module's name; every module when absent",
"log": "a build's id (as `builds` lists it): print what the build machine said, line by line", "log": "a build's id (as `builds` lists it): print what the build machine said, line by line",
}, nil)}, }, nil)},
{Name: "plans", Description: "What the last merges produced and where each stands (novox/hq ADR 0162): " +
"the tiers, the tier a plan is at, what it waits for and since when; one plan whole, given its id.",
Input: schema(map[string]string{"id": "a plan's id (as `plans` lists them): that plan, tier by tier"}, nil)},
{Name: "plan", Description: "What one machine would run, and why: the declaration the mesh would send it.", {Name: "plan", Description: "What one machine would run, and why: the declaration the mesh would send it.",
Input: schema(map[string]string{"node": "the machine's name"}, []string{"node"})}, Input: schema(map[string]string{"node": "the machine's name"}, []string{"node"})},
{Name: "assign", Description: "Put a module on a machine. Refused with the mesh's own words when it cannot resolve there.", {Name: "assign", Description: "Put a module on a machine. Refused with the mesh's own words when it cannot resolve there.",