Add Today report to morning batch
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
const (
|
||||
CommandNameDaily = "daily"
|
||||
CommandNameToday = "today"
|
||||
CommandNameTomorrow = "tomorrow"
|
||||
CommandNameHourly = "hourly"
|
||||
CommandNameThreeDay = "three-day"
|
||||
@@ -21,6 +22,8 @@ func IDForCommandName(name string) (ID, error) {
|
||||
switch name {
|
||||
case CommandNameDaily:
|
||||
return DailyToday, nil
|
||||
case CommandNameToday:
|
||||
return Today, nil
|
||||
case CommandNameTomorrow:
|
||||
return Tomorrow, nil
|
||||
case CommandNameHourly:
|
||||
@@ -39,6 +42,7 @@ func IDForCommandName(name string) (ID, error) {
|
||||
func CommandNames() []string {
|
||||
return []string{
|
||||
CommandNameDaily,
|
||||
CommandNameToday,
|
||||
CommandNameTomorrow,
|
||||
CommandNameHourly,
|
||||
CommandNameThreeDay,
|
||||
@@ -52,6 +56,8 @@ func IDForConfigKey(key string) (ID, error) {
|
||||
switch normalized {
|
||||
case "daily", "daily_today":
|
||||
return DailyToday, nil
|
||||
case "today":
|
||||
return Today, nil
|
||||
case "tomorrow":
|
||||
return Tomorrow, nil
|
||||
case "hourly":
|
||||
|
||||
@@ -26,7 +26,7 @@ func (r Registry) BatchReports(batch Batch, req ResolveRequest) ([]Resolved, err
|
||||
}
|
||||
switch batch {
|
||||
case Morning:
|
||||
ids := []ID{DailyToday, ThreeDay}
|
||||
ids := []ID{Today, ThreeDay}
|
||||
if req.Now.In(req.Location).Weekday() != time.Sunday {
|
||||
ids = append(ids, Weekend)
|
||||
}
|
||||
|
||||
@@ -33,6 +33,41 @@ func TestDailyValidPeriodCanUseExplicitDate(t *testing.T) {
|
||||
assertPeriod(t, resolved.ValidPeriod, "2026-05-31T00:00:00-05:00", "2026-06-01T00:00:00-05:00")
|
||||
}
|
||||
|
||||
func TestTodayValidPeriod(t *testing.T) {
|
||||
location := mustLoadLocation(t)
|
||||
now := mustParse("2026-05-29T17:45:00-05:00")
|
||||
|
||||
resolved, err := Resolve(Today, ResolveRequest{Now: now, Location: location})
|
||||
if err != nil {
|
||||
t.Fatalf("Resolve() error = %v", err)
|
||||
}
|
||||
assertPeriod(t, resolved.ValidPeriod, "2026-05-29T00:00:00-05:00", "2026-05-30T00:00:00-05:00")
|
||||
if resolved.Definition.PromptID != "weather.today_generated_text" {
|
||||
t.Fatalf("PromptID = %q, want weather.today_generated_text", resolved.Definition.PromptID)
|
||||
}
|
||||
if resolved.Definition.GenerationMode != GenerationModeGeneratedTextTemplate {
|
||||
t.Fatalf("GenerationMode = %q, want generated_text_template", resolved.Definition.GenerationMode)
|
||||
}
|
||||
if resolved.Definition.TemplateID != "today" {
|
||||
t.Fatalf("TemplateID = %q, want today", resolved.Definition.TemplateID)
|
||||
}
|
||||
if resolved.Definition.GeneratedTextSchemaID != "today" {
|
||||
t.Fatalf("GeneratedTextSchemaID = %q, want today", resolved.Definition.GeneratedTextSchemaID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTodayValidPeriodCanUseExplicitDate(t *testing.T) {
|
||||
location := mustLoadLocation(t)
|
||||
now := mustParse("2026-05-29T17:45:00-05:00")
|
||||
date := mustParse("2026-05-31T12:00:00-05:00")
|
||||
|
||||
resolved, err := Resolve(Today, ResolveRequest{Now: now, Location: location, Date: date})
|
||||
if err != nil {
|
||||
t.Fatalf("Resolve() error = %v", err)
|
||||
}
|
||||
assertPeriod(t, resolved.ValidPeriod, "2026-05-31T00:00:00-05:00", "2026-06-01T00:00:00-05:00")
|
||||
}
|
||||
|
||||
func TestTomorrowValidPeriodFromEveningGeneration(t *testing.T) {
|
||||
location := mustLoadLocation(t)
|
||||
now := mustParse("2026-05-29T20:00:00-05:00")
|
||||
@@ -201,8 +236,8 @@ func TestMorningBatchSkipsWeekendOnSunday(t *testing.T) {
|
||||
t.Fatalf("BatchReports() error = %v", err)
|
||||
}
|
||||
ids := resolvedIDs(resolved)
|
||||
if strings.Join(ids, ",") != "daily_today,three_day" {
|
||||
t.Fatalf("ids = %v, want daily_today and three_day", ids)
|
||||
if strings.Join(ids, ",") != "today,three_day" {
|
||||
t.Fatalf("ids = %v, want today and three_day", ids)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,6 +281,7 @@ func TestIDForCommandName(t *testing.T) {
|
||||
want ID
|
||||
}{
|
||||
{name: "daily", want: DailyToday},
|
||||
{name: "today", want: Today},
|
||||
{name: "tomorrow", want: Tomorrow},
|
||||
{name: "hourly", want: Hourly},
|
||||
{name: "three-day", want: ThreeDay},
|
||||
@@ -263,9 +299,20 @@ func TestIDForCommandName(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
if names := strings.Join(CommandNames(), ","); names != "daily,tomorrow,hourly,three-day,weekend,storm" {
|
||||
if names := strings.Join(CommandNames(), ","); names != "daily,today,tomorrow,hourly,three-day,weekend,storm" {
|
||||
t.Fatalf("CommandNames() = %s, want stable command names", names)
|
||||
}
|
||||
dailyID, err := IDForCommandName("daily")
|
||||
if err != nil {
|
||||
t.Fatalf("IDForCommandName(daily) error = %v", err)
|
||||
}
|
||||
todayID, err := IDForCommandName("today")
|
||||
if err != nil {
|
||||
t.Fatalf("IDForCommandName(today) error = %v", err)
|
||||
}
|
||||
if dailyID == todayID {
|
||||
t.Fatalf("daily and today both resolve to %q, want distinct report IDs", dailyID)
|
||||
}
|
||||
if _, err := IDForCommandName("near-term"); err == nil || !strings.Contains(err.Error(), `unknown report command "near-term"`) {
|
||||
t.Fatalf("IDForCommandName(near-term) error = %v, want unknown command", err)
|
||||
}
|
||||
@@ -278,6 +325,7 @@ func TestIDForConfigKey(t *testing.T) {
|
||||
}{
|
||||
{key: "daily", want: DailyToday},
|
||||
{key: "daily_today", want: DailyToday},
|
||||
{key: "today", want: Today},
|
||||
{key: "tomorrow", want: Tomorrow},
|
||||
{key: "hourly", want: Hourly},
|
||||
{key: "three_day", want: ThreeDay},
|
||||
@@ -303,6 +351,17 @@ func TestIDForConfigKey(t *testing.T) {
|
||||
if _, err := IDForConfigKey("daily_tomorrow"); err == nil || !strings.Contains(err.Error(), `report config key "daily_tomorrow" is not a known report`) {
|
||||
t.Fatalf("IDForConfigKey(daily_tomorrow) error = %v, want unknown key", err)
|
||||
}
|
||||
dailyID, err := IDForConfigKey("daily")
|
||||
if err != nil {
|
||||
t.Fatalf("IDForConfigKey(daily) error = %v", err)
|
||||
}
|
||||
todayID, err := IDForConfigKey("today")
|
||||
if err != nil {
|
||||
t.Fatalf("IDForConfigKey(today) error = %v", err)
|
||||
}
|
||||
if dailyID == todayID {
|
||||
t.Fatalf("daily and today config keys both resolve to %q, want distinct report IDs", dailyID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBatchForCommandName(t *testing.T) {
|
||||
@@ -342,7 +401,7 @@ func TestMorningBatchReportOrder(t *testing.T) {
|
||||
t.Fatalf("BatchReports() error = %v", err)
|
||||
}
|
||||
ids := resolvedIDs(resolved)
|
||||
if strings.Join(ids, ",") != "daily_today,three_day,weekend" {
|
||||
if strings.Join(ids, ",") != "today,three_day,weekend" {
|
||||
t.Fatalf("ids = %v, want morning report order", ids)
|
||||
}
|
||||
}
|
||||
@@ -359,7 +418,7 @@ func TestRegistryLookupErrorIsActionable(t *testing.T) {
|
||||
|
||||
func TestRegistryAllIncludesHourlyInStableOrder(t *testing.T) {
|
||||
ids := resolvedDefinitionIDs(DefaultRegistry().All())
|
||||
want := []string{"daily_today", "tomorrow", "hourly", "three_day", "weekend", "storm"}
|
||||
want := []string{"daily_today", "today", "tomorrow", "hourly", "three_day", "weekend", "storm"}
|
||||
if strings.Join(ids, ",") != strings.Join(want, ",") {
|
||||
t.Fatalf("All() ids = %#v, want %#v", ids, want)
|
||||
}
|
||||
@@ -384,7 +443,7 @@ func TestRegistryDefinitionsDeclareGenerationMetadata(t *testing.T) {
|
||||
if !definition.Generated {
|
||||
continue
|
||||
}
|
||||
if definition.ID == Hourly || definition.ID == Tomorrow {
|
||||
if definition.ID == Hourly || definition.ID == Today || definition.ID == Tomorrow {
|
||||
wantTemplate := string(definition.ID)
|
||||
if definition.GenerationMode != GenerationModeGeneratedTextTemplate {
|
||||
t.Fatalf("%s GenerationMode = %q, want %q", definition.ID, definition.GenerationMode, GenerationModeGeneratedTextTemplate)
|
||||
@@ -426,6 +485,14 @@ func TestRegistryDefinitionsDeclarePathAndCompatibilityPolicy(t *testing.T) {
|
||||
compatiblePriorIDs: []ID{DailyToday},
|
||||
comparisonStrategy: CompareSameValidDate,
|
||||
},
|
||||
{
|
||||
id: Today,
|
||||
artifactGroup: "today",
|
||||
batchOutputName: "today.md",
|
||||
generated: true,
|
||||
compatiblePriorIDs: []ID{Today},
|
||||
comparisonStrategy: CompareSameValidDate,
|
||||
},
|
||||
{
|
||||
id: Tomorrow,
|
||||
artifactGroup: "tomorrow",
|
||||
@@ -522,6 +589,25 @@ func TestRegistryDefinitionsDeclareDefaultModules(t *testing.T) {
|
||||
module.HourlyForecast,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: Today,
|
||||
want: []module.ID{
|
||||
module.Metadata,
|
||||
module.CurrentConditions,
|
||||
module.NarrativeForecast,
|
||||
module.DerivedDailySummary,
|
||||
module.DerivedDaypartSummaries,
|
||||
module.PrecipTiming,
|
||||
module.AlertDigest,
|
||||
module.SPCConvectiveOutlooks,
|
||||
module.AreaForecastDiscussion,
|
||||
module.SPCConvectiveDiscussion,
|
||||
module.WeatherStory,
|
||||
module.OutdoorWindows,
|
||||
module.HourlyForecast,
|
||||
module.TodayPlanning,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: Tomorrow,
|
||||
want: []module.ID{
|
||||
|
||||
@@ -13,6 +13,7 @@ type Registry struct {
|
||||
func DefaultRegistry() Registry {
|
||||
definitions := []Definition{
|
||||
dailyTodayDefinition(),
|
||||
todayDefinition(),
|
||||
tomorrowDefinition(),
|
||||
hourlyDefinition(),
|
||||
threeDayDefinition(),
|
||||
@@ -74,7 +75,7 @@ func (r Registry) MustLookup(id ID) Definition {
|
||||
}
|
||||
|
||||
func (r Registry) All() []Definition {
|
||||
ids := []ID{DailyToday, Tomorrow, Hourly, ThreeDay, Weekend, Storm}
|
||||
ids := []ID{DailyToday, Today, Tomorrow, Hourly, ThreeDay, Weekend, Storm}
|
||||
out := make([]Definition, 0, len(ids))
|
||||
for _, id := range ids {
|
||||
if definition, ok := r.definitions[id]; ok {
|
||||
|
||||
51
internal/report/today_report.go
Normal file
51
internal/report/today_report.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package report
|
||||
|
||||
import (
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/module"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/timeutil"
|
||||
)
|
||||
|
||||
func todayDefinition() Definition {
|
||||
return Definition{
|
||||
ID: Today,
|
||||
Name: "Today Report",
|
||||
PromptID: "weather.today_generated_text",
|
||||
GenerationMode: GenerationModeGeneratedTextTemplate,
|
||||
TemplateID: "today",
|
||||
GeneratedTextSchemaID: "today",
|
||||
ComparisonStrategy: CompareSameValidDate,
|
||||
ArtifactGroup: "today",
|
||||
BatchOutputName: "today.md",
|
||||
Generated: true,
|
||||
CompatiblePriorIDs: []ID{Today},
|
||||
Modules: todayModules(),
|
||||
Morning: true,
|
||||
resolve: resolveToday,
|
||||
}
|
||||
}
|
||||
|
||||
func todayModules() []module.ConfigItem {
|
||||
return moduleItems(
|
||||
module.Metadata,
|
||||
module.CurrentConditions,
|
||||
module.NarrativeForecast,
|
||||
module.DerivedDailySummary,
|
||||
module.DerivedDaypartSummaries,
|
||||
module.PrecipTiming,
|
||||
module.AlertDigest,
|
||||
module.SPCConvectiveOutlooks,
|
||||
module.AreaForecastDiscussion,
|
||||
module.SPCConvectiveDiscussion,
|
||||
module.WeatherStory,
|
||||
module.OutdoorWindows,
|
||||
module.HourlyForecast,
|
||||
module.TodayPlanning,
|
||||
)
|
||||
}
|
||||
|
||||
func resolveToday(req ResolveRequest) (timeutil.Period, error) {
|
||||
if !req.Date.IsZero() {
|
||||
return timeutil.CivilDay(req.Date, req.Location), nil
|
||||
}
|
||||
return timeutil.CivilDay(req.Now, req.Location), nil
|
||||
}
|
||||
Reference in New Issue
Block a user