Add report artifact inspection commands

This commit is contained in:
2026-05-29 18:33:24 +00:00
parent 18fe82f441
commit 88aaae3661
8 changed files with 633 additions and 4 deletions

View File

@@ -726,6 +726,132 @@ func TestGenerateStormReportWritesReport(t *testing.T) {
}
}
func TestInspectGeneratedReportArtifacts(t *testing.T) {
server := dailyBundleServer(t)
cfg := config.Defaults()
cfg.WeatherAPI.BaseURL = server.URL + "/"
cfg.WeatherAPI.Timezone = "America/Chicago"
cfg.Workspace.Root = t.TempDir()
resolved, err := ResolveGenerate(GenerateRequest{
Config: cfg,
Report: ReportDaily,
Date: mustParse("2026-05-29T12:00:00-05:00"),
}, mustParse("2026-05-29T05:00:00-05:00"))
if err != nil {
t.Fatalf("ResolveGenerate() error = %v", err)
}
renderer := &recordingRenderer{
renderResult: &scriptorium.RenderResult{ExitCode: 0},
runResult: &scriptorium.RunResult{ExitCode: 0},
runBody: "# Daily Report\n",
}
result, err := GenerateReport(context.Background(), ReportRequest{
Config: cfg,
Resolved: resolved,
Renderer: renderer,
})
if err != nil {
t.Fatalf("GenerateReport() error = %v", err)
}
records, err := InspectReports(context.Background(), InspectReportsRequest{Config: cfg, Limit: 1})
if err != nil {
t.Fatalf("InspectReports() error = %v", err)
}
if len(records) != 1 || records[0].RunID != result.Metadata.RunID {
t.Fatalf("records = %#v, want generated run", records)
}
metadata, err := InspectMetadata(context.Background(), InspectRunRequest{Config: cfg, RunID: result.Metadata.RunID})
if err != nil {
t.Fatalf("InspectMetadata() error = %v", err)
}
if metadata.BriefingPath != result.BriefingPath || metadata.DataPackagePath != result.DataPackagePath {
t.Fatalf("metadata paths = %#v, want generated artifact paths", metadata)
}
briefingPackage, err := InspectBriefing(context.Background(), InspectRunRequest{Config: cfg, RunID: result.Metadata.RunID})
if err != nil {
t.Fatalf("InspectBriefing() error = %v", err)
}
if briefingPackage.Metadata.RunID != result.Metadata.RunID {
t.Fatalf("briefing RunID = %q, want %q", briefingPackage.Metadata.RunID, result.Metadata.RunID)
}
dataPackage, err := InspectDataPackage(context.Background(), InspectRunRequest{Config: cfg, RunID: result.Metadata.RunID})
if err != nil {
t.Fatalf("InspectDataPackage() error = %v", err)
}
if dataPackage.RunID != result.Metadata.RunID {
t.Fatalf("data package RunID = %q, want %q", dataPackage.RunID, result.Metadata.RunID)
}
sources, err := InspectSources(context.Background(), InspectRunRequest{Config: cfg, RunID: result.Metadata.RunID})
if err != nil {
t.Fatalf("InspectSources() error = %v", err)
}
if len(sources.Sources) == 0 || len(sources.Warnings) == 0 {
t.Fatalf("sources = %#v, want provenance and warnings", sources)
}
}
func TestInspectPriorSnapshot(t *testing.T) {
server := dailyBundleServer(t)
cfg := config.Defaults()
cfg.WeatherAPI.BaseURL = server.URL + "/"
cfg.WeatherAPI.Timezone = "America/Chicago"
cfg.Workspace.Root = t.TempDir()
store, err := state.NewFilesystemStore(cfg.Workspace)
if err != nil {
t.Fatalf("NewFilesystemStore() error = %v", err)
}
priorResolved, err := ResolveGenerate(GenerateRequest{
Config: cfg,
Report: ReportDaily,
Date: mustParse("2026-05-29T12:00:00-05:00"),
}, mustParse("2026-05-29T04:00:00-05:00"))
if err != nil {
t.Fatalf("ResolveGenerate(prior) error = %v", err)
}
currentResolved, err := ResolveGenerate(GenerateRequest{
Config: cfg,
Report: ReportDaily,
Date: mustParse("2026-05-29T12:00:00-05:00"),
}, mustParse("2026-05-29T05:00:00-05:00"))
if err != nil {
t.Fatalf("ResolveGenerate(current) error = %v", err)
}
renderer := &recordingRenderer{
renderResult: &scriptorium.RenderResult{ExitCode: 0},
runResult: &scriptorium.RunResult{ExitCode: 0},
runBody: "# Daily Report\n",
}
if _, err := GenerateReport(context.Background(), ReportRequest{Config: cfg, Resolved: priorResolved, Renderer: renderer, Store: store}); err != nil {
t.Fatalf("GenerateReport(prior) error = %v", err)
}
current, err := GenerateReport(context.Background(), ReportRequest{Config: cfg, Resolved: currentResolved, Renderer: renderer, Store: store})
if err != nil {
t.Fatalf("GenerateReport(current) error = %v", err)
}
prior, err := InspectPriorSnapshot(context.Background(), InspectRunRequest{Config: cfg, RunID: current.Metadata.RunID})
if err != nil {
t.Fatalf("InspectPriorSnapshot() error = %v", err)
}
if prior == nil || prior.Metadata.RunID != priorResolved.Metadata().RunID {
t.Fatalf("prior = %#v, want previous generated run", prior)
}
}
func TestInspectMissingMetadata(t *testing.T) {
cfg := config.Defaults()
cfg.Workspace.Root = t.TempDir()
_, err := InspectMetadata(context.Background(), InspectRunRequest{Config: cfg, RunID: "missing"})
if err == nil {
t.Fatal("InspectMetadata() error = nil, want missing metadata error")
}
if !strings.Contains(err.Error(), "metadata for run id") {
t.Fatalf("error = %q, want missing run id context", err.Error())
}
}
func TestResolveGenerateMapsCommandToReportDefinition(t *testing.T) {
cfg := config.Defaults()
cfg.WeatherAPI.Timezone = "America/Chicago"

123
internal/app/inspect.go Normal file
View File

@@ -0,0 +1,123 @@
package app
import (
"context"
"fmt"
"gitea.maximumdirect.net/eric/weatherreporter/internal/briefing"
"gitea.maximumdirect.net/eric/weatherreporter/internal/config"
"gitea.maximumdirect.net/eric/weatherreporter/internal/forecast"
"gitea.maximumdirect.net/eric/weatherreporter/internal/promptinput"
"gitea.maximumdirect.net/eric/weatherreporter/internal/report"
"gitea.maximumdirect.net/eric/weatherreporter/internal/state"
"gitea.maximumdirect.net/eric/weatherreporter/internal/timeutil"
)
type InspectReportsRequest struct {
Config config.Config
Limit int
}
type InspectRunRequest struct {
Config config.Config
RunID string
}
type SourceInspection struct {
RunID string `json:"runId"`
ReportID report.ID `json:"reportId"`
SourceLocation string `json:"sourceLocation,omitempty"`
Sources []briefing.SourceMetadata `json:"sources,omitempty"`
Warnings []forecast.SourceWarning `json:"warnings,omitempty"`
}
func InspectReports(ctx context.Context, req InspectReportsRequest) ([]state.ReportRecord, error) {
store, err := defaultStore(req.Config)
if err != nil {
return nil, err
}
return store.ListReports(ctx, req.Limit)
}
func InspectMetadata(ctx context.Context, req InspectRunRequest) (state.Metadata, error) {
store, err := defaultStore(req.Config)
if err != nil {
return state.Metadata{}, err
}
metadata, _, err := store.LoadMetadataByRunID(ctx, req.RunID)
return metadata, err
}
func InspectBriefing(ctx context.Context, req InspectRunRequest) (briefing.Package, error) {
store, err := defaultStore(req.Config)
if err != nil {
return briefing.Package{}, err
}
metadata, _, err := store.LoadMetadataByRunID(ctx, req.RunID)
if err != nil {
return briefing.Package{}, err
}
return store.LoadBriefing(ctx, metadata.BriefingPath)
}
func InspectDataPackage(ctx context.Context, req InspectRunRequest) (promptinput.Package, error) {
store, err := defaultStore(req.Config)
if err != nil {
return promptinput.Package{}, err
}
metadata, _, err := store.LoadMetadataByRunID(ctx, req.RunID)
if err != nil {
return promptinput.Package{}, err
}
return store.LoadDataPackage(ctx, metadata.DataPackagePath)
}
func InspectPriorSnapshot(ctx context.Context, req InspectRunRequest) (*state.PriorSnapshot, error) {
store, err := defaultStore(req.Config)
if err != nil {
return nil, err
}
metadata, _, err := store.LoadMetadataByRunID(ctx, req.RunID)
if err != nil {
return nil, err
}
resolved, err := resolvedFromMetadata(metadata)
if err != nil {
return nil, err
}
return store.FindPriorSnapshot(ctx, resolved)
}
func InspectSources(ctx context.Context, req InspectRunRequest) (SourceInspection, error) {
metadata, err := InspectMetadata(ctx, req)
if err != nil {
return SourceInspection{}, err
}
return SourceInspection{
RunID: metadata.RunID,
ReportID: metadata.ReportID,
SourceLocation: metadata.SourceLocation,
Sources: metadata.Sources,
Warnings: metadata.SourceWarnings,
}, nil
}
func resolvedFromMetadata(metadata state.Metadata) (report.Resolved, error) {
definition, err := report.DefaultRegistry().Lookup(metadata.ReportID)
if err != nil {
return report.Resolved{}, err
}
location, err := timeutil.LoadLocation(metadata.Timezone)
if err != nil {
return report.Resolved{}, err
}
if !metadata.ValidPeriod.IsValid() {
return report.Resolved{}, fmt.Errorf("metadata valid period for run id %q is invalid", metadata.RunID)
}
return report.Resolved{
Definition: definition,
GeneratedAt: metadata.GeneratedAt,
Timezone: location.String(),
ValidPeriod: metadata.ValidPeriod,
}, nil
}