Say why assign finds no module, and keep an assignment pending on its build

A merge asks for a new module's build, and assign answered "no module of that
name" until the build registered it, which read as a module nobody registered
(hq issue 325). Keep every build request, tell a build in flight, a module
known and not built, and an unknown name apart, and make an assignment made
while the build runs when the build registers the module.
This commit is contained in:
jochen
2026-10-08 16:38:11 +02:00
parent fe00fec52c
commit 7d63d2e68c
15 changed files with 1303 additions and 9 deletions
+59 -1
View File
@@ -4,6 +4,7 @@ import (
"context"
"flag"
"fmt"
"os"
"sort"
"strings"
"time"
@@ -143,6 +144,8 @@ func printStatus(asked answers) error {
len(quiet), strings.Join(said, "\n "))
}
printPending(asked.pending, asked.pendingUnread)
if open, late := openPlans(asked.plans, time.Now(), asked.paused, asked.tierBounds); len(open) > 0 {
fmt.Printf("%d plan(s) open", len(open))
if late > 0 {
@@ -466,6 +469,15 @@ func theThreeQuestions(ctx context.Context, open *stores) (answers, error) {
if out.conditions, err = openConditions(ctx); err != nil {
out.conditionsUnread = err.Error()
}
// And the assignments waiting for their module's build (novox/hq issue 325): what a missed outcome left
// waiting is settled first, so one never waits silently past its build.
for _, line := range settleStalePending(ctx, open, time.Now()) {
fmt.Fprintln(os.Stderr, line)
}
if out.pending, err = inv.Pending(ctx, time.Now().Add(-pendingShownFor)); err != nil {
out.pendingUnread = err.Error()
err = nil
}
out.plans, err = inv.RecentPlans(ctx, 5)
if err != nil {
return answers{}, err
@@ -598,7 +610,53 @@ func (a answers) well() bool {
return len(a.wrong) == 0 && len(a.quiet) == 0 && len(a.behind) == 0 &&
len(a.waiting) == 0 && len(a.refused) == 0 && a.network == "" && len(a.untaken) == 0 &&
len(a.filtered) == 0 && len(a.unheld) == 0 && len(a.overflowing) == 0 &&
len(a.conditions) == 0 && a.conditionsUnread == ""
len(a.conditions) == 0 && a.conditionsUnread == "" && a.pendingUnread == "" && !pendingNotWell(a.pending)
}
// pendingNotWell is whether any pending assignment is waiting, or ended without being made.
func pendingNotWell(pending []inventory.PendingAssignment) bool {
for _, p := range pending {
if p.State != inventory.PendingApplied && p.State != inventory.PendingWithdrawn {
return true
}
}
return false
}
// printPending says the assignments waiting for their module's build, and those ended in the last day
// (novox/hq issue 325).
func printPending(pending []inventory.PendingAssignment, unread string) {
if unread != "" {
fmt.Printf("the assignments waiting for a build could not be read: %s\n\n", unread)
return
}
var waiting, ended []inventory.PendingAssignment
for _, p := range pending {
if p.State == inventory.PendingWaiting {
waiting = append(waiting, p)
} else {
ended = append(ended, p)
}
}
if len(waiting) > 0 {
fmt.Printf("%d assignment(s) wait for their module's build to register it:\n", len(waiting))
for _, p := range waiting {
fmt.Printf(" %-12s %-20s build %s of %s %s, since %s\n", p.Node, p.Module, p.Build, p.Repository,
orRoot(p.Path), clock(p.Since))
}
fmt.Printf("\n each is made when its build registers the module; `unassign <node> <module>` withdraws it\n\n")
}
if len(ended) > 0 {
fmt.Printf("%d pending assignment(s) ended in the last day:\n", len(ended))
for _, p := range ended {
at := ""
if p.Settled != nil {
at = clock(*p.Settled)
}
fmt.Printf(" %-12s %-20s %-9s %s\n %-12s %s\n", p.Node, p.Module, p.State, at, "", p.Note)
}
fmt.Println()
}
}
// hostSplit is which machines report which host version, for every version more than one machine