From 97f96bd13f342d3e9f55359538cc8ddeeb3928c9 Mon Sep 17 00:00:00 2001 From: Dmitriy Derepko Date: Tue, 4 Aug 2026 12:38:49 +0400 Subject: [PATCH] feat(coverage): dump LCOV after 'wippy test' when WIPPY_COVERAGE set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calls the go-lua coverage collector's WriteCoverageLCOV/CoverageSummary right after shutdown.Perform in runWithUseCase — covering both the clean-exit and the os.Exit(exitCode!=0) paths, so coverage is captured even when tests fail. Configured via env: WIPPY_COVERAGE (enable, read by go-lua at init), WIPPY_COVERAGE_FILE (output, default coverage.info), WIPPY_COVERAGE_FILTER (source-name substring, e.g. 'app.'). Requires the go-lua coverage collector (CoverageEnabled/WriteCoverageLCOV/ CoverageSummary) — not in upstream go-lua v1.5.16. Build with: go mod edit -replace github.com/wippyai/go-lua=/path/to/go-lua@feature/coverage-collector No-op (single bool check) when WIPPY_COVERAGE is unset. --- cmd/wippy/cmd/run.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/cmd/wippy/cmd/run.go b/cmd/wippy/cmd/run.go index 78b91e6f8..71fffdb0a 100644 --- a/cmd/wippy/cmd/run.go +++ b/cmd/wippy/cmd/run.go @@ -33,6 +33,7 @@ import ( "github.com/wippyai/runtime/cmd/internal/shutdown" embedpkg "github.com/wippyai/runtime/service/fs/embed" supervisorpkg "github.com/wippyai/runtime/system/supervisor" + lua "github.com/wippyai/go-lua" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -289,6 +290,9 @@ func runWithUseCase(cmd *cobra.Command, args []string, useCase string) error { waitForShutdownSignal(sigChan, logger, nil) exitCode := shutdown.Perform(ctx, loader, logger, silentLogs) + if lua.CoverageEnabled() { + dumpCoverage() + } if exitCode != 0 { _ = logger.Sync() os.Exit(exitCode) @@ -297,6 +301,33 @@ func runWithUseCase(cmd *cobra.Command, args []string, useCase string) error { return nil } +// dumpCoverage writes an LCOV tracefile when WIPPY_COVERAGE is set. It runs both +// on a clean exit (return nil) and before os.Exit on a failing run, so coverage +// is captured even when tests fail. Configured via env: +// +// WIPPY_COVERAGE_FILE output path (default: coverage.info) +// WIPPY_COVERAGE_FILTER substring the source name must contain (default: all) +func dumpCoverage() { + prefix := os.Getenv("WIPPY_COVERAGE_FILTER") + filter := func(src string) bool { + return prefix == "" || strings.Contains(src, prefix) + } + path := os.Getenv("WIPPY_COVERAGE_FILE") + if path == "" { + path = "coverage.info" + } + if err := lua.WriteCoverageLCOV(path, filter); err != nil { + fmt.Fprintf(os.Stderr, "coverage: write failed: %v\n", err) + return + } + lf, lh := lua.CoverageSummary(filter) + pct := 0.0 + if lf > 0 { + pct = float64(lh) / float64(lf) * 100 + } + fmt.Fprintf(os.Stderr, "coverage: %d/%d lines (%.1f%%) filter=%q -> %s\n", lh, lf, pct, prefix, path) +} + // loadRuntimeConfig resolves the effective runtime configuration for run-like // commands by merging: // 1) config file/defaults,