- Verify() pokreće build, vet, test sa merenjem trajanja - Ako build padne, ostalo se preskače - parseTestCount parsira go test -v output - FormatResult za čitljiv ispis - 10 checker testova — svi prolaze Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
114 lines
3.1 KiB
Go
114 lines
3.1 KiB
Go
package supervisor
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// CheckResult holds the result of a single verification check.
|
|
type CheckResult struct {
|
|
Name string // "build", "test", "vet"
|
|
Status string // "pass", "fail"
|
|
Output string // stdout + stderr
|
|
Duration time.Duration
|
|
TestCount int // only for test (parsed from output)
|
|
}
|
|
|
|
// VerifyResult holds the combined result of all verification checks.
|
|
type VerifyResult struct {
|
|
Build CheckResult
|
|
Vet CheckResult
|
|
Test CheckResult
|
|
AllPassed bool
|
|
}
|
|
|
|
// Verify runs build, vet, and test checks on the given Go project path.
|
|
// If build fails, vet and test are skipped.
|
|
func Verify(projectPath string) VerifyResult {
|
|
var result VerifyResult
|
|
|
|
result.Build = runCheck("build", "go build ./...", projectPath)
|
|
if result.Build.Status == "fail" {
|
|
result.Vet = CheckResult{Name: "vet", Status: "fail", Output: "skipped: build failed"}
|
|
result.Test = CheckResult{Name: "test", Status: "fail", Output: "skipped: build failed"}
|
|
return result
|
|
}
|
|
|
|
result.Vet = runCheck("vet", "go vet ./...", projectPath)
|
|
|
|
result.Test = runCheck("test", "go test ./... -count=1 -v", projectPath)
|
|
result.Test.TestCount = parseTestCount(result.Test.Output)
|
|
|
|
result.AllPassed = result.Build.Status == "pass" &&
|
|
result.Vet.Status == "pass" &&
|
|
result.Test.Status == "pass"
|
|
|
|
return result
|
|
}
|
|
|
|
// runCheck executes a single shell command in the given directory and returns
|
|
// a CheckResult with the output, status, and duration.
|
|
func runCheck(name, command, projectPath string) CheckResult {
|
|
start := time.Now()
|
|
|
|
parts := strings.Fields(command)
|
|
cmd := exec.Command(parts[0], parts[1:]...)
|
|
cmd.Dir = projectPath
|
|
|
|
output, err := cmd.CombinedOutput()
|
|
duration := time.Since(start)
|
|
|
|
status := "pass"
|
|
if err != nil {
|
|
status = "fail"
|
|
}
|
|
|
|
return CheckResult{
|
|
Name: name,
|
|
Status: status,
|
|
Output: string(output),
|
|
Duration: duration,
|
|
}
|
|
}
|
|
|
|
// testCountRegex matches lines like:
|
|
//
|
|
// ok github.com/dal/kaos/internal/config 0.003s
|
|
// ok github.com/dal/kaos/internal/supervisor 0.008s
|
|
var testCountRegex = regexp.MustCompile(`(?m)^---\s+(PASS|FAIL):\s+`)
|
|
|
|
// passLineRegex matches "ok" lines from go test output.
|
|
var passLineRegex = regexp.MustCompile(`(?m)^ok\s+\S+\s+[\d.]+s`)
|
|
|
|
// parseTestCount counts the number of individual test results in go test -v output.
|
|
// It counts lines matching "--- PASS:" or "--- FAIL:".
|
|
func parseTestCount(output string) int {
|
|
matches := testCountRegex.FindAllString(output, -1)
|
|
return len(matches)
|
|
}
|
|
|
|
// FormatResult returns a human-readable summary of the verification.
|
|
func FormatResult(r VerifyResult) string {
|
|
var b strings.Builder
|
|
for _, c := range []CheckResult{r.Build, r.Vet, r.Test} {
|
|
icon := "✅"
|
|
if c.Status == "fail" {
|
|
icon = "❌"
|
|
}
|
|
line := fmt.Sprintf("%s %s: %s (%s)", icon, c.Name, c.Status, c.Duration.Round(time.Millisecond))
|
|
if c.Name == "test" && c.TestCount > 0 {
|
|
line += fmt.Sprintf(" [%d tests]", c.TestCount)
|
|
}
|
|
b.WriteString(line + "\n")
|
|
}
|
|
if r.AllPassed {
|
|
b.WriteString("\nAll checks passed.")
|
|
} else {
|
|
b.WriteString("\nSome checks failed.")
|
|
}
|
|
return b.String()
|
|
}
|