doctor: collapse healthy output to one line, add --verbose
A healthy host triggered ~20 PASS rows with details — too noisy for the common case. Default now prints only fail/warn rows plus a summary footer; an all-pass run collapses to a single line. Pass --verbose / -v for the full per-check output. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
09a3ef812f
commit
9b5cbed32d
4 changed files with 142 additions and 7 deletions
|
|
@ -71,7 +71,8 @@ to diagnose host readiness problems.
|
|||
}
|
||||
|
||||
func (d *deps) newDoctorCommand() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
var verbose bool
|
||||
cmd := &cobra.Command{
|
||||
Use: "doctor",
|
||||
Short: "Check host and runtime readiness",
|
||||
Long: strings.TrimSpace(`
|
||||
|
|
@ -85,8 +86,10 @@ Run 'banger doctor':
|
|||
- after upgrading the host kernel or banger itself
|
||||
- when 'banger vm run' fails with an unclear error
|
||||
|
||||
Exit code is non-zero if any check fails. Warnings are reported but
|
||||
do not fail the run.
|
||||
By default, prints failing and warning checks only and a summary
|
||||
footer; a healthy host collapses to a single line. Pass --verbose to
|
||||
print every check with its details. Exit code is non-zero if any
|
||||
check fails. Warnings are reported but do not fail the run.
|
||||
`),
|
||||
Args: noArgsUsage("usage: banger doctor"),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
|
@ -94,7 +97,7 @@ do not fail the run.
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := printDoctorReport(cmd.OutOrStdout(), report); err != nil {
|
||||
if err := printDoctorReport(cmd.OutOrStdout(), report, verbose); err != nil {
|
||||
return err
|
||||
}
|
||||
if report.HasFailures() {
|
||||
|
|
@ -103,6 +106,8 @@ do not fail the run.
|
|||
return nil
|
||||
},
|
||||
}
|
||||
cmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "show every check (default: only failures and warnings)")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func newVersionCommand() *cobra.Command {
|
||||
|
|
|
|||
|
|
@ -133,12 +133,15 @@ func TestDoctorCommandPrintsReportAndFailsOnHardFailures(t *testing.T) {
|
|||
t.Fatalf("Execute() error = %v, want doctor failure", err)
|
||||
}
|
||||
output := stdout.String()
|
||||
if !strings.Contains(output, "PASS\truntime bundle") {
|
||||
t.Fatalf("output = %q, want runtime bundle pass", output)
|
||||
if strings.Contains(output, "PASS\truntime bundle") {
|
||||
t.Fatalf("output = %q, brief default should hide PASS rows", output)
|
||||
}
|
||||
if !strings.Contains(output, "FAIL\tfeature nat") {
|
||||
t.Fatalf("output = %q, want feature nat fail", output)
|
||||
}
|
||||
if !strings.Contains(output, "1 passed, 0 warnings, 1 failure") {
|
||||
t.Fatalf("output = %q, want summary footer", output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoctorCommandReturnsUnderlyingError(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -272,9 +272,34 @@ func printKernelCatalogTable(out anyWriter, entries []api.KernelCatalogEntry) er
|
|||
|
||||
// -- doctor printer -------------------------------------------------
|
||||
|
||||
func printDoctorReport(out anyWriter, report system.Report) error {
|
||||
func printDoctorReport(out anyWriter, report system.Report, verbose bool) error {
|
||||
colorWriter, _ := out.(io.Writer)
|
||||
|
||||
var passes, warns, fails int
|
||||
for _, c := range report.Checks {
|
||||
switch c.Status {
|
||||
case system.CheckStatusPass:
|
||||
passes++
|
||||
case system.CheckStatusWarn:
|
||||
warns++
|
||||
case system.CheckStatusFail:
|
||||
fails++
|
||||
}
|
||||
}
|
||||
|
||||
if !verbose && warns == 0 && fails == 0 {
|
||||
msg := fmt.Sprintf("all %d checks passed", passes)
|
||||
if colorWriter != nil {
|
||||
msg = style.Pass(colorWriter, msg)
|
||||
}
|
||||
_, err := fmt.Fprintln(out, msg)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, check := range report.Checks {
|
||||
if !verbose && check.Status == system.CheckStatusPass {
|
||||
continue
|
||||
}
|
||||
status := strings.ToUpper(string(check.Status))
|
||||
if colorWriter != nil {
|
||||
switch check.Status {
|
||||
|
|
@ -295,5 +320,19 @@ func printDoctorReport(out anyWriter, report system.Report) error {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !verbose {
|
||||
if _, err := fmt.Fprintf(out, "\n%d passed, %s, %s\n", passes, pluralCount(warns, "warning"), pluralCount(fails, "failure")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func pluralCount(n int, word string) string {
|
||||
if n == 1 {
|
||||
return fmt.Sprintf("%d %s", n, word)
|
||||
}
|
||||
return fmt.Sprintf("%d %ss", n, word)
|
||||
}
|
||||
|
|
|
|||
88
internal/cli/printers_test.go
Normal file
88
internal/cli/printers_test.go
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"banger/internal/system"
|
||||
)
|
||||
|
||||
func TestPrintDoctorReport_BriefAllPass(t *testing.T) {
|
||||
report := system.Report{}
|
||||
report.AddPass("first", "detail one")
|
||||
report.AddPass("second", "detail two")
|
||||
report.AddPass("third")
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := printDoctorReport(&buf, report, false); err != nil {
|
||||
t.Fatalf("printDoctorReport: %v", err)
|
||||
}
|
||||
|
||||
got := buf.String()
|
||||
want := "all 3 checks passed\n"
|
||||
if got != want {
|
||||
t.Fatalf("brief all-pass output\n got: %q\nwant: %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintDoctorReport_BriefHidesPassDetails(t *testing.T) {
|
||||
report := system.Report{}
|
||||
report.AddPass("first", "detail one")
|
||||
report.AddWarn("second", "warn detail")
|
||||
report.AddPass("third", "detail three")
|
||||
report.AddFail("fourth", "fail detail")
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := printDoctorReport(&buf, report, false); err != nil {
|
||||
t.Fatalf("printDoctorReport: %v", err)
|
||||
}
|
||||
|
||||
got := buf.String()
|
||||
if strings.Contains(got, "PASS") || strings.Contains(got, "first") || strings.Contains(got, "third") {
|
||||
t.Fatalf("brief mode leaked PASS rows: %q", got)
|
||||
}
|
||||
for _, want := range []string{"WARN\tsecond", "warn detail", "FAIL\tfourth", "fail detail"} {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Fatalf("missing %q in brief output: %q", want, got)
|
||||
}
|
||||
}
|
||||
if !strings.Contains(got, "2 passed, 1 warning, 1 failure") {
|
||||
t.Fatalf("missing summary footer in: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintDoctorReport_BriefSummaryPlurals(t *testing.T) {
|
||||
report := system.Report{}
|
||||
report.AddPass("a")
|
||||
report.AddWarn("b")
|
||||
report.AddWarn("c")
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := printDoctorReport(&buf, report, false); err != nil {
|
||||
t.Fatalf("printDoctorReport: %v", err)
|
||||
}
|
||||
if !strings.Contains(buf.String(), "1 passed, 2 warnings, 0 failures") {
|
||||
t.Fatalf("plural counts wrong: %q", buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintDoctorReport_VerboseShowsEverything(t *testing.T) {
|
||||
report := system.Report{}
|
||||
report.AddPass("first", "detail one")
|
||||
report.AddWarn("second", "warn detail")
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := printDoctorReport(&buf, report, true); err != nil {
|
||||
t.Fatalf("printDoctorReport: %v", err)
|
||||
}
|
||||
got := buf.String()
|
||||
for _, want := range []string{"PASS\tfirst", "detail one", "WARN\tsecond", "warn detail"} {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Fatalf("verbose mode missing %q: %q", want, got)
|
||||
}
|
||||
}
|
||||
if strings.Contains(got, "passed,") {
|
||||
t.Fatalf("verbose mode should not print summary footer: %q", got)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue