Unify application configuration loading

This commit is contained in:
2026-08-30 13:32:45 +00:00
parent f302488075
commit f86b17045d
9 changed files with 163 additions and 56 deletions

View File

@@ -88,11 +88,7 @@ func cleanAllLocal(flags commonConfigFlags, dryRun, clearCache bool, out io.Writ
strings.TrimSpace(flags.previousSessionID) != "" {
return fmt.Errorf("clean: --all cannot be combined with --campaign, --campaign-file, --session, a session_id, or --previous-session-id")
}
resolvedPipelinePath, err := resolvePipelineConfigPath(flags.pipelinePath)
if err != nil {
return fmt.Errorf("clean: %w", err)
}
pipelineCfg, err := config.LoadPipeline(resolvedPipelinePath)
_, pipelineCfg, err := loadPipelineConfig(flags.pipelinePath)
if err != nil {
return fmt.Errorf("clean: %w", err)
}

View File

@@ -14,14 +14,10 @@ import (
"gitea.maximumdirect.net/eric/narratio/internal/fileops"
)
type pipelineCampaignConfig struct {
PipelinePath string
CampaignPath string
Pipeline *config.PipelineConfig
Campaign *config.CampaignConfig
}
type pipelineCampaignConfig = config.LoadedPipelineCampaign
var downloadObjectToTempFn = storage.DownloadObjectToTemp
var loadPipelineConfigFn = config.LoadPipeline
type commandConfig struct {
Config *config.Config
@@ -58,7 +54,7 @@ func loadCommandConfig(ctx context.Context, pipelineFlag, campaignFlag, campaign
}
if explicitSession := strings.TrimSpace(sessionFlag); explicitSession != "" {
cfg, err := config.LoadWithSessionOptions(base.PipelinePath, base.CampaignPath, explicitSession, sessionOpts)
cfg, err := config.LoadSessionWithPipelineCampaignOptions(*base, explicitSession, sessionOpts)
if err != nil {
return nil, err
}
@@ -70,7 +66,7 @@ func loadCommandConfig(ctx context.Context, pipelineFlag, campaignFlag, campaign
return nil, err
}
if discoveredSession.Path != "" {
cfg, err := config.LoadWithSessionOptions(base.PipelinePath, base.CampaignPath, discoveredSession.Path, sessionOpts)
cfg, err := config.LoadSessionWithPipelineCampaignOptions(*base, discoveredSession.Path, sessionOpts)
if err != nil {
return nil, err
}
@@ -88,11 +84,9 @@ func loadCommandConfig(ctx context.Context, pipelineFlag, campaignFlag, campaign
}
sessionPrefix := artifacts.S3SessionPrefix(rootPrefix, config.CampaignID(base.Campaign), sessionID)
remoteKey := artifacts.S3SessionConfigKey(sessionPrefix)
partialCfg := &config.Config{
Pipeline: base.Pipeline,
Campaign: base.Campaign,
PipelinePath: base.PipelinePath,
CampaignPath: base.CampaignPath,
partialCfg, err := config.ResolveLoadedPipelineCampaign(*base, "", nil, config.SessionSource{})
if err != nil {
return nil, err
}
store, err := newCommandObjectStore(ctx, partialCfg, nil)
if err != nil {
@@ -122,11 +116,8 @@ func loadCommandConfig(ctx context.Context, pipelineFlag, campaignFlag, campaign
return nil, err
}
cfg, err := config.Resolve(
base.PipelinePath,
base.Pipeline,
base.CampaignPath,
base.Campaign,
cfg, err := config.ResolveLoadedPipelineCampaign(
*base,
sessionTempPath,
sessionCfg,
config.SessionSource{
@@ -147,11 +138,7 @@ func loadCommandConfig(ctx context.Context, pipelineFlag, campaignFlag, campaign
}
func loadPipelineCampaignConfig(pipelineFlag, campaignFlag, campaignFileFlag string) (*pipelineCampaignConfig, error) {
resolvedPipelinePath, err := resolvePipelineConfigPath(pipelineFlag)
if err != nil {
return nil, err
}
pipelineCfg, err := config.LoadPipeline(resolvedPipelinePath)
loadedPipelinePath, pipelineCfg, err := loadPipelineConfig(pipelineFlag)
if err != nil {
return nil, err
}
@@ -169,13 +156,25 @@ func loadPipelineCampaignConfig(pipelineFlag, campaignFlag, campaignFileFlag str
}
}
return &pipelineCampaignConfig{
PipelinePath: resolvedPipelinePath,
PipelinePath: loadedPipelinePath,
CampaignPath: resolvedCampaignPath,
Pipeline: pipelineCfg,
Campaign: campaignCfg,
}, nil
}
func loadPipelineConfig(pipelineFlag string) (string, *config.PipelineConfig, error) {
resolvedPipelinePath, err := resolvePipelineConfigPath(pipelineFlag)
if err != nil {
return "", nil, err
}
pipelineCfg, err := loadPipelineConfigFn(resolvedPipelinePath)
if err != nil {
return "", nil, err
}
return resolvedPipelinePath, pipelineCfg, nil
}
func findRemoteSessionConfig(ctx context.Context, store storage.ObjectStore, sessionPrefix, remoteKey string) (storage.ObjectInfo, error) {
objects, err := store.List(ctx, sessionPrefix)
if err != nil {

View File

@@ -0,0 +1,50 @@
package app
import (
"context"
"os"
"strings"
"testing"
"gitea.maximumdirect.net/eric/narratio/internal/config"
)
func TestLoadCommandConfigRetainsInitiallyLoadedPipeline(t *testing.T) {
workspaceRoot := t.TempDir()
pipelinePath, campaignPath, sessionPath := writeValidConfigFiles(t, workspaceRoot)
originalLoader := loadPipelineConfigFn
loadCalls := 0
loadPipelineConfigFn = func(path string) (*config.PipelineConfig, error) {
loaded, err := originalLoader(path)
if err != nil {
return nil, err
}
loadCalls++
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
changedRoot := workspaceRoot + "-changed"
updated := strings.ReplaceAll(string(data), workspaceRoot, changedRoot)
if err := os.WriteFile(path, []byte(updated), 0o644); err != nil {
return nil, err
}
return loaded, nil
}
t.Cleanup(func() { loadPipelineConfigFn = originalLoader })
loaded, err := loadCommandConfig(context.Background(), pipelinePath, "", campaignPath, sessionPath, config.SessionLoadOptions{SessionID: "2026-05-03"})
if err != nil {
t.Fatalf("loadCommandConfig() error = %v", err)
}
defer func() { _ = loaded.Close() }()
if loadCalls != 1 {
t.Fatalf("pipeline load calls = %d, want 1", loadCalls)
}
if got := loaded.Config.Pipeline.Workspace.Root; got != workspaceRoot {
t.Fatalf("resolved workspace root = %q, want originally loaded %q", got, workspaceRoot)
}
}

View File

@@ -79,7 +79,7 @@ func SessionInit(ctx context.Context, args []string, out io.Writer) error {
if err != nil {
return fmt.Errorf("session init: %w", err)
}
cfg, err := config.Resolve(base.PipelinePath, base.Pipeline, base.CampaignPath, base.Campaign, label, sessionCfg, config.SessionSource{Source: "session_config", LocalPath: label})
cfg, err := config.ResolveLoadedPipelineCampaign(*base, label, sessionCfg, config.SessionSource{Source: "session_config", LocalPath: label})
if err != nil {
return fmt.Errorf("session init: %w", err)
}

View File

@@ -166,6 +166,9 @@ inputs:
if err := loaded.Close(); err != nil {
t.Fatalf("second Close() error = %v", err)
}
if loaded.Config == nil || loaded.Config.Pipeline == nil || loaded.Config.Campaign == nil || loaded.Config.Session == nil {
t.Fatal("closing remote session cleanup discarded retained configuration")
}
if _, err := os.Stat(downloadedPath); !errors.Is(err, os.ErrNotExist) {
t.Fatalf("downloaded remote session path still exists or could not be inspected: %q, err=%v", downloadedPath, err)
}