Keep batch notification failures out of report counts

This commit is contained in:
2026-08-01 21:54:53 +00:00
parent bf1746a756
commit 76cd399c76
5 changed files with 96 additions and 13 deletions

View File

@@ -40,10 +40,11 @@ Options:
`
type Runner struct {
Clock timeutil.Clock
ExecutorFactory ExecutorFactory
Version string
WorkingDir string
Clock timeutil.Clock
ExecutorFactory ExecutorFactory
Version string
WorkingDir string
runBatchDetailed func(context.Context, app.BatchRequest) (*app.BatchResult, error)
}
func Run(ctx context.Context, args []string, stdout io.Writer, stderr io.Writer) error {
@@ -89,7 +90,11 @@ func (r Runner) Run(ctx context.Context, args []string, stdout io.Writer, stderr
if err != nil {
return err
}
result, err := app.RunBatchDetailed(ctx, req)
runBatchDetailed := r.runBatchDetailed
if runBatchDetailed == nil {
runBatchDetailed = app.RunBatchDetailed
}
result, err := runBatchDetailed(ctx, req)
if result != nil {
summary := newBatchSummary(result)
if encodeErr := writeActionResult(stdout, stderr, summary, outputOptions{Quiet: opts.Quiet}, func(w io.Writer) {

View File

@@ -3,12 +3,15 @@ package cli
import (
"bytes"
"context"
"encoding/json"
"errors"
"os"
"path/filepath"
"strings"
"testing"
"time"
"gitea.maximumdirect.net/eric/weatherreporter/internal/app"
"gitea.maximumdirect.net/eric/weatherreporter/internal/promptexec"
"gitea.maximumdirect.net/eric/weatherreporter/internal/timeutil"
)
@@ -80,6 +83,43 @@ func TestResolveGenerateActionUsesInjectedWorkingDirectoryForOutputOverrides(t *
}
}
func TestRunActionReturnsFailureForBatchNotificationFailure(t *testing.T) {
configPath := filepath.Join(t.TempDir(), "config.yml")
if err := os.WriteFile(configPath, []byte("weather_api:\n base_url: https://weather.api.example.com/\n"), 0o600); err != nil {
t.Fatal(err)
}
result := &app.BatchResult{
Batch: app.BatchMorning, Total: 2, Succeeded: 2,
Reports: []app.BatchReportResult{
{ReportID: "today", Status: "succeeded", OutputPath: "/reports/today.md"},
{ReportID: "tomorrow", Status: "succeeded", OutputPath: "/reports/tomorrow.md"},
},
Notification: &app.BatchNotificationResult{Status: "failed", Error: "distributor unavailable"},
}
var stdout, stderr bytes.Buffer
runner := Runner{
Clock: timeutil.FixedClock{Time: time.Date(2026, 5, 29, 8, 0, 0, 0, time.UTC)},
ExecutorFactory: func(PromptExecutorConfig) (promptexec.Executor, error) {
return &factoryExecutor{}, nil
},
runBatchDetailed: func(context.Context, app.BatchRequest) (*app.BatchResult, error) {
return result, nil
},
}
err := runner.Run(context.Background(), []string{"run", "morning", "--config", configPath}, &stdout, &stderr)
var batchErr app.BatchError
if !errors.As(err, &batchErr) || !strings.Contains(err.Error(), "notification failed") {
t.Fatalf("Run() error = %v", err)
}
var summary batchSummary
if err := json.Unmarshal(stdout.Bytes(), &summary); err != nil {
t.Fatalf("decode summary: %v", err)
}
if summary.Status != summaryStatusFailed || summary.Total != 2 || summary.Succeeded != 2 || summary.Failed != 0 || summary.Notification == nil || summary.Notification.Status != "failed" {
t.Fatalf("summary = %#v", summary)
}
}
func TestInspectCommandIsUnknownAndAbsentFromHelp(t *testing.T) {
var stdout, stderr bytes.Buffer
err := (Runner{}).Run(context.Background(), []string{"inspect", "reports"}, &stdout, &stderr)