mirror of
https://github.com/Quad4-Software/Reticulum-Go
synced 2026-08-29 23:48:44 -04:00
144 lines
3.5 KiB
Go
144 lines
3.5 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright (c) 2024-2026 Quad4.io
|
|
|
|
package selfcheck
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
|
|
"quad4/reticulum-go/pkg/term"
|
|
)
|
|
|
|
// Severity classifies a single check outcome.
|
|
type Severity string
|
|
|
|
const (
|
|
SeverityPass Severity = "pass"
|
|
SeverityWarn Severity = "warn"
|
|
SeverityFail Severity = "fail"
|
|
SeveritySkip Severity = "skip"
|
|
)
|
|
|
|
// Result is one named check outcome.
|
|
type Result struct {
|
|
Name string `json:"name"`
|
|
Severity Severity `json:"severity"`
|
|
Detail string `json:"detail,omitempty"`
|
|
Platform string `json:"platform,omitempty"`
|
|
}
|
|
|
|
// Report aggregates host self-check results.
|
|
type Report struct {
|
|
GOOS string `json:"goos"`
|
|
GOARCH string `json:"goarch"`
|
|
GoVersion string `json:"go_version"`
|
|
Results []Result `json:"results"`
|
|
}
|
|
|
|
// Counts returns pass, warn, skip, and fail totals.
|
|
func (r Report) Counts() (pass, warn, skip, fail int) {
|
|
for _, res := range r.Results {
|
|
switch res.Severity {
|
|
case SeverityPass:
|
|
pass++
|
|
case SeverityWarn:
|
|
warn++
|
|
case SeveritySkip:
|
|
skip++
|
|
case SeverityFail:
|
|
fail++
|
|
}
|
|
}
|
|
return pass, warn, skip, fail
|
|
}
|
|
|
|
// ExitCode returns 0 when there are no failures.
|
|
// When strict is true, warnings also yield exit code 1.
|
|
func (r Report) ExitCode(strict bool) int {
|
|
_, warn, _, fail := r.Counts()
|
|
if fail > 0 {
|
|
return 1
|
|
}
|
|
if strict && warn > 0 {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func severityLabel(w io.Writer, sev Severity) string {
|
|
switch sev {
|
|
case SeverityPass:
|
|
return term.GreenW(w, "pass")
|
|
case SeverityWarn:
|
|
return term.YellowW(w, "warn")
|
|
case SeverityFail:
|
|
return term.RedW(w, "fail")
|
|
case SeveritySkip:
|
|
return term.DimW(w, "skip")
|
|
default:
|
|
return string(sev)
|
|
}
|
|
}
|
|
|
|
// FormatText writes a human-readable report to w.
|
|
func (r Report) FormatText(w io.Writer) error {
|
|
header := fmt.Sprintf("reticulum-go self-check %s/%s %s", r.GOOS, r.GOARCH, r.GoVersion)
|
|
if _, err := fmt.Fprintln(w, term.BoldW(w, header)); err != nil {
|
|
return err
|
|
}
|
|
for _, res := range r.Results {
|
|
line := fmt.Sprintf(" [%s] %s", severityLabel(w, res.Severity), res.Name)
|
|
if res.Detail != "" {
|
|
line += ": " + res.Detail
|
|
}
|
|
if _, err := fmt.Fprintln(w, line); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
pass, warn, skip, fail := r.Counts()
|
|
summary := fmt.Sprintf("Summary: %d pass, %d warn, %d skip, %d fail",
|
|
pass, warn, skip, fail)
|
|
summary = strings.Replace(summary, fmt.Sprintf("%d pass", pass), term.GreenW(w, fmt.Sprintf("%d pass", pass)), 1)
|
|
summary = strings.Replace(summary, fmt.Sprintf("%d warn", warn), term.YellowW(w, fmt.Sprintf("%d warn", warn)), 1)
|
|
summary = strings.Replace(summary, fmt.Sprintf("%d skip", skip), term.DimW(w, fmt.Sprintf("%d skip", skip)), 1)
|
|
summary = strings.Replace(summary, fmt.Sprintf("%d fail", fail), term.RedW(w, fmt.Sprintf("%d fail", fail)), 1)
|
|
_, err := fmt.Fprintln(w, term.BoldW(w, summary))
|
|
return err
|
|
}
|
|
|
|
// FormatJSON writes an indented JSON report to w.
|
|
func (r Report) FormatJSON(w io.Writer) error {
|
|
pass, warn, skip, fail := r.Counts()
|
|
out := struct {
|
|
Report
|
|
Pass int `json:"pass"`
|
|
Warn int `json:"warn"`
|
|
Skip int `json:"skip"`
|
|
Fail int `json:"fail"`
|
|
}{
|
|
Report: r,
|
|
Pass: pass,
|
|
Warn: warn,
|
|
Skip: skip,
|
|
Fail: fail,
|
|
}
|
|
enc := json.NewEncoder(w)
|
|
enc.SetIndent("", " ")
|
|
return enc.Encode(out)
|
|
}
|
|
|
|
func platformTag() string {
|
|
return fmt.Sprintf("%s/%s", goos(), goarch())
|
|
}
|
|
|
|
func result(name string, sev Severity, detail string) Result {
|
|
return Result{
|
|
Name: name,
|
|
Severity: sev,
|
|
Detail: strings.TrimSpace(detail),
|
|
Platform: platformTag(),
|
|
}
|
|
}
|