Use one execution plan throughout the runner

This commit is contained in:
2026-08-29 20:49:43 +00:00
parent 0dc8ff9b52
commit fd5ccc668b
12 changed files with 83 additions and 53 deletions

View File

@@ -11,7 +11,6 @@ import (
"gitea.maximumdirect.net/eric/narratio/internal/config" "gitea.maximumdirect.net/eric/narratio/internal/config"
"gitea.maximumdirect.net/eric/narratio/internal/manifest" "gitea.maximumdirect.net/eric/narratio/internal/manifest"
"gitea.maximumdirect.net/eric/narratio/internal/stage"
) )
func TestExecuteRunStageArtifactsUnsupportedStageFails(t *testing.T) { func TestExecuteRunStageArtifactsUnsupportedStageFails(t *testing.T) {
@@ -43,8 +42,8 @@ func TestExecuteRunStagePublishPropagatesSelectedArtifacts(t *testing.T) {
t.Cleanup(func() { t.Cleanup(func() {
executeStagesFn = origExecuteStagesFn executeStagesFn = origExecuteStagesFn
}) })
executeStagesFn = func(_ context.Context, _ *config.Config, stages []stage.Stage, opts RunOptions) (*RunSummary, error) { executeStagesFn = func(_ context.Context, _ *config.Config, plan BoundedPlan, opts RunOptions) (*RunSummary, error) {
for _, s := range stages { for _, s := range plan.Stages() {
capturedStages = append(capturedStages, s.Name()) capturedStages = append(capturedStages, s.Name())
} }
capturedArtifacts = append([]string(nil), opts.SelectedArtifacts...) capturedArtifacts = append([]string(nil), opts.SelectedArtifacts...)
@@ -159,8 +158,8 @@ func TestExecuteAnalyzeForceRunsAnalyze(t *testing.T) {
t.Cleanup(func() { t.Cleanup(func() {
executeStagesFn = origExecuteStagesFn executeStagesFn = origExecuteStagesFn
}) })
executeStagesFn = func(_ context.Context, _ *config.Config, stages []stage.Stage, opts RunOptions) (*RunSummary, error) { executeStagesFn = func(_ context.Context, _ *config.Config, plan BoundedPlan, opts RunOptions) (*RunSummary, error) {
for _, s := range stages { for _, s := range plan.Stages() {
capturedStages = append(capturedStages, s.Name()) capturedStages = append(capturedStages, s.Name())
} }
capturedForce = opts.Force capturedForce = opts.Force
@@ -200,7 +199,7 @@ func TestExecuteAnalyzePropagatesSelectedArtifacts(t *testing.T) {
t.Cleanup(func() { t.Cleanup(func() {
executeStagesFn = origExecuteStagesFn executeStagesFn = origExecuteStagesFn
}) })
executeStagesFn = func(_ context.Context, _ *config.Config, _ []stage.Stage, opts RunOptions) (*RunSummary, error) { executeStagesFn = func(_ context.Context, _ *config.Config, _ BoundedPlan, opts RunOptions) (*RunSummary, error) {
capturedArtifacts = append([]string(nil), opts.SelectedArtifacts...) capturedArtifacts = append([]string(nil), opts.SelectedArtifacts...)
return &RunSummary{ManifestPath: filepath.Join(workspaceRoot, "manifest.json"), Executed: []string{"analyze"}}, nil return &RunSummary{ManifestPath: filepath.Join(workspaceRoot, "manifest.json"), Executed: []string{"analyze"}}, nil
} }
@@ -293,8 +292,8 @@ func TestExecutePublishForceRunsPublish(t *testing.T) {
t.Cleanup(func() { t.Cleanup(func() {
executeStagesFn = origExecuteStagesFn executeStagesFn = origExecuteStagesFn
}) })
executeStagesFn = func(_ context.Context, _ *config.Config, stages []stage.Stage, opts RunOptions) (*RunSummary, error) { executeStagesFn = func(_ context.Context, _ *config.Config, plan BoundedPlan, opts RunOptions) (*RunSummary, error) {
for _, s := range stages { for _, s := range plan.Stages() {
capturedStages = append(capturedStages, s.Name()) capturedStages = append(capturedStages, s.Name())
} }
capturedForce = opts.Force capturedForce = opts.Force

View File

@@ -54,9 +54,9 @@ func TestAssembledCanonicalAndAliasArtifactRegenerationRequestsMatch(t *testing.
var captured []capturedRequest var captured []capturedRequest
original := executeStagesFn original := executeStagesFn
t.Cleanup(func() { executeStagesFn = original }) t.Cleanup(func() { executeStagesFn = original })
executeStagesFn = func(_ context.Context, _ *config.Config, stages []stage.Stage, options RunOptions) (*RunSummary, error) { executeStagesFn = func(_ context.Context, _ *config.Config, plan BoundedPlan, options RunOptions) (*RunSummary, error) {
captured = append(captured, capturedRequest{ captured = append(captured, capturedRequest{
stages: stageNames(stages), artifacts: append([]string(nil), options.SelectedArtifacts...), force: options.Force, stages: plan.Names(), artifacts: append([]string(nil), options.SelectedArtifacts...), force: options.Force,
}) })
return &RunSummary{SessionID: "2026-05-03", ManifestPath: manifestPathForConfig(workspaceRoot)}, nil return &RunSummary{SessionID: "2026-05-03", ManifestPath: manifestPathForConfig(workspaceRoot)}, nil
} }
@@ -99,9 +99,8 @@ func TestAssembledForcedSiblingIndependenceAndFailureBoundary(t *testing.T) {
seedAllStagesSucceeded(t, cfg) seedAllStagesSucceeded(t, cfg)
plan := mustBoundedPlan(t, selected, selected) plan := mustBoundedPlan(t, selected, selected)
runs := 0 runs := 0
summary, err := executeStages(context.Background(), cfg, []stage.Stage{ plan.stages = []stage.Stage{countingStage{name: selected, runs: &runs}}
countingStage{name: selected, runs: &runs}, summary, err := executePlan(context.Background(), cfg, plan, RunOptions{Force: true})
}, RunOptions{Plan: plan, Force: true})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -132,9 +131,8 @@ func TestAssembledForcedSiblingIndependenceAndFailureBoundary(t *testing.T) {
cfg := testConfig(t) cfg := testConfig(t)
seedAllStagesSucceeded(t, cfg) seedAllStagesSucceeded(t, cfg)
plan := mustBoundedPlan(t, "render", "render") plan := mustBoundedPlan(t, "render", "render")
_, err := executeStages(context.Background(), cfg, []stage.Stage{ plan.stages = []stage.Stage{failingStage{name: "render", err: context.Canceled}}
failingStage{name: "render", err: context.Canceled}, _, err := executePlan(context.Background(), cfg, plan, RunOptions{Force: true})
}, RunOptions{Plan: plan, Force: true})
if err == nil { if err == nil {
t.Fatal("forced render failure returned nil") t.Fatal("forced render failure returned nil")
} }

View File

@@ -94,8 +94,8 @@ func TestExecuteStagesRejectsBoundedPrerequisitesBeforePersistentMutation(t *tes
store := &prerequisiteMutationSpy{local: &manifest.LocalStore{}} store := &prerequisiteMutationSpy{local: &manifest.LocalStore{}}
runs := 0 runs := 0
_, err = executeStages(context.Background(), cfg, []stage.Stage{countingStage{name: "render", runs: &runs}}, RunOptions{ plan.stages = []stage.Stage{countingStage{name: "render", runs: &runs}}
Plan: plan, _, err = executePlan(context.Background(), cfg, plan, RunOptions{
Env: &Env{ManifestStore: store}, Env: &Env{ManifestStore: store},
}) })
if err == nil || !strings.Contains(err.Error(), `stage "prepare" has unusable status "running"`) { if err == nil || !strings.Contains(err.Error(), `stage "prepare" has unusable status "running"`) {
@@ -126,8 +126,8 @@ func TestExecuteStagesRechecksBoundedPrerequisitesUnderSessionLock(t *testing.T)
store := &prerequisiteChangingStore{local: &manifest.LocalStore{}} store := &prerequisiteChangingStore{local: &manifest.LocalStore{}}
runs := 0 runs := 0
_, err := executeStages(context.Background(), cfg, []stage.Stage{countingStage{name: "render", runs: &runs}}, RunOptions{ plan.stages = []stage.Stage{countingStage{name: "render", runs: &runs}}
Plan: plan, _, err := executePlan(context.Background(), cfg, plan, RunOptions{
Env: &Env{ManifestStore: store}, Env: &Env{ManifestStore: store},
}) })
if err == nil || !strings.Contains(err.Error(), `stage "prepare" has unusable status "running"`) { if err == nil || !strings.Contains(err.Error(), `stage "prepare" has unusable status "running"`) {
@@ -191,7 +191,8 @@ func TestExecuteStagesBoundedCompositionUsesOnlySelectedCollaborators(t *testing
saveBoundedManifest(t, cfg, m) saveBoundedManifest(t, cfg, m)
var captured *stage.Env var captured *stage.Env
_, err := executeStages(context.Background(), cfg, []stage.Stage{collaboratorProbeStage{name: test.stageName, captured: &captured}}, RunOptions{Plan: plan}) plan.stages = []stage.Stage{collaboratorProbeStage{name: test.stageName, captured: &captured}}
_, err := executePlan(context.Background(), cfg, plan, RunOptions{})
if err != nil { if err != nil {
t.Fatalf("executeStages() error = %v", err) t.Fatalf("executeStages() error = %v", err)
} }
@@ -213,7 +214,8 @@ func TestExecuteStagesBoundedForceStalesButDoesNotRunDependentsOutsideRange(t *t
} }
saveBoundedManifest(t, cfg, m) saveBoundedManifest(t, cfg, m)
runs := 0 runs := 0
_, err := executeStages(context.Background(), cfg, []stage.Stage{countingStage{name: "render", runs: &runs}}, RunOptions{Plan: plan, Force: true}) plan.stages = []stage.Stage{countingStage{name: "render", runs: &runs}}
_, err := executePlan(context.Background(), cfg, plan, RunOptions{Force: true})
if err != nil { if err != nil {
t.Fatalf("executeStages() error = %v", err) t.Fatalf("executeStages() error = %v", err)
} }
@@ -242,10 +244,11 @@ func TestExecuteStagesBoundedFailureStopsWithinSelectedRange(t *testing.T) {
markPrefixSucceeded(m, plan) markPrefixSucceeded(m, plan)
saveBoundedManifest(t, cfg, m) saveBoundedManifest(t, cfg, m)
extractRuns := 0 extractRuns := 0
_, err := executeStages(context.Background(), cfg, []stage.Stage{ plan.stages = []stage.Stage{
failingStage{name: "render", err: errors.New("render failed")}, failingStage{name: "render", err: errors.New("render failed")},
countingStage{name: "extract", runs: &extractRuns}, countingStage{name: "extract", runs: &extractRuns},
}, RunOptions{Plan: plan}) }
_, err := executePlan(context.Background(), cfg, plan, RunOptions{})
if err == nil || !strings.Contains(err.Error(), "render failed") { if err == nil || !strings.Contains(err.Error(), "render failed") {
t.Fatalf("executeStages() error = %v", err) t.Fatalf("executeStages() error = %v", err)
} }

View File

@@ -12,7 +12,6 @@ import (
"gitea.maximumdirect.net/eric/narratio/internal/config" "gitea.maximumdirect.net/eric/narratio/internal/config"
"gitea.maximumdirect.net/eric/narratio/internal/manifest" "gitea.maximumdirect.net/eric/narratio/internal/manifest"
"gitea.maximumdirect.net/eric/narratio/internal/stage"
) )
func TestBoundedRunParsingIsSharedByRunAndPlan(t *testing.T) { func TestBoundedRunParsingIsSharedByRunAndPlan(t *testing.T) {
@@ -112,11 +111,13 @@ func TestRunPassesBoundedPlanToRunner(t *testing.T) {
pipelinePath, campaignPath, sessionPath := writeValidConfigFiles(t, workspaceRoot) pipelinePath, campaignPath, sessionPath := writeValidConfigFiles(t, workspaceRoot)
var capturedStages []string var capturedStages []string
var capturedPlan BoundedPlan
var capturedOptions RunOptions var capturedOptions RunOptions
original := executeStagesFn original := executeStagesFn
t.Cleanup(func() { executeStagesFn = original }) t.Cleanup(func() { executeStagesFn = original })
executeStagesFn = func(_ context.Context, _ *config.Config, stages []stage.Stage, options RunOptions) (*RunSummary, error) { executeStagesFn = func(_ context.Context, _ *config.Config, plan BoundedPlan, options RunOptions) (*RunSummary, error) {
capturedStages = stageNames(stages) capturedStages = plan.Names()
capturedPlan = plan
capturedOptions = options capturedOptions = options
return &RunSummary{SessionID: "2026-05-03", ManifestPath: filepath.Join(workspaceRoot, "manifest.json")}, nil return &RunSummary{SessionID: "2026-05-03", ManifestPath: filepath.Join(workspaceRoot, "manifest.json")}, nil
} }
@@ -135,7 +136,7 @@ func TestRunPassesBoundedPlanToRunner(t *testing.T) {
t.Fatalf("Run() error = %v", err) t.Fatalf("Run() error = %v", err)
} }
want := []string{"render", "extract"} want := []string{"render", "extract"}
if !reflect.DeepEqual(capturedStages, want) || !reflect.DeepEqual(capturedOptions.Plan.Names(), want) || !capturedOptions.Force { if !reflect.DeepEqual(capturedStages, want) || !reflect.DeepEqual(capturedPlan.Names(), want) || !capturedOptions.Force {
t.Fatalf("stages = %#v options = %#v", capturedStages, capturedOptions) t.Fatalf("stages = %#v options = %#v", capturedStages, capturedOptions)
} }
} }

View File

@@ -140,3 +140,22 @@ func BuildSingleStagePlan(name string) ([]stage.Stage, error) {
} }
return []stage.Stage{s}, nil return []stage.Stage{s}, nil
} }
// buildSingleStageExecutionPlan selects one canonical stage without applying
// bounded-run prefix prerequisites. The run-stage family validates the stage's
// concrete inputs and intentionally retains its established direct-execution
// semantics.
func buildSingleStageExecutionPlan(name string) (BoundedPlan, error) {
stages, err := BuildSingleStagePlan(name)
if err != nil {
return BoundedPlan{}, err
}
plan, err := BuildBoundedPlan(name, name)
if err != nil {
return BoundedPlan{}, fmt.Errorf("build stage plan: %w", err)
}
plan.stages = stages
plan.explicitFrom = false
plan.explicitThrough = false
return plan, nil
}

View File

@@ -13,7 +13,6 @@ import (
"gitea.maximumdirect.net/eric/narratio/internal/adapters/storage" "gitea.maximumdirect.net/eric/narratio/internal/adapters/storage"
"gitea.maximumdirect.net/eric/narratio/internal/artifacts" "gitea.maximumdirect.net/eric/narratio/internal/artifacts"
"gitea.maximumdirect.net/eric/narratio/internal/config" "gitea.maximumdirect.net/eric/narratio/internal/config"
"gitea.maximumdirect.net/eric/narratio/internal/stage"
) )
func TestExecuteRemoteSessionFallbackLoadsFromObjectStore(t *testing.T) { func TestExecuteRemoteSessionFallbackLoadsFromObjectStore(t *testing.T) {
@@ -85,7 +84,7 @@ inputs:
`, `,
command: []string{"run", "2026-05-03"}, command: []string{"run", "2026-05-03"},
configureRun: func() { configureRun: func() {
executeStagesFn = func(context.Context, *config.Config, []stage.Stage, RunOptions) (*RunSummary, error) { executeStagesFn = func(context.Context, *config.Config, BoundedPlan, RunOptions) (*RunSummary, error) {
return nil, errors.New("adapter failed") return nil, errors.New("adapter failed")
} }
}, },
@@ -99,7 +98,7 @@ inputs:
`, `,
command: []string{"run", "2026-05-03"}, command: []string{"run", "2026-05-03"},
configureRun: func() { configureRun: func() {
executeStagesFn = func(context.Context, *config.Config, []stage.Stage, RunOptions) (*RunSummary, error) { executeStagesFn = func(context.Context, *config.Config, BoundedPlan, RunOptions) (*RunSummary, error) {
return nil, context.Canceled return nil, context.Canceled
} }
}, },

View File

@@ -14,7 +14,6 @@ import (
"gitea.maximumdirect.net/eric/narratio/internal/artifacts" "gitea.maximumdirect.net/eric/narratio/internal/artifacts"
"gitea.maximumdirect.net/eric/narratio/internal/config" "gitea.maximumdirect.net/eric/narratio/internal/config"
"gitea.maximumdirect.net/eric/narratio/internal/manifest" "gitea.maximumdirect.net/eric/narratio/internal/manifest"
"gitea.maximumdirect.net/eric/narratio/internal/stage"
) )
func TestRestoreThenRunStageForceAnalyzeUsesRestoredDurableState(t *testing.T) { func TestRestoreThenRunStageForceAnalyzeUsesRestoredDurableState(t *testing.T) {
@@ -34,12 +33,12 @@ func TestRestoreThenRunStageForceAnalyzeUsesRestoredDurableState(t *testing.T) {
t.Cleanup(func() { t.Cleanup(func() {
executeStagesFn = origExecuteStagesFn executeStagesFn = origExecuteStagesFn
}) })
executeStagesFn = func(ctx context.Context, cfg *config.Config, stages []stage.Stage, opts RunOptions) (*RunSummary, error) { executeStagesFn = func(ctx context.Context, cfg *config.Config, plan BoundedPlan, opts RunOptions) (*RunSummary, error) {
if opts.Env == nil { if opts.Env == nil {
opts.Env = &Env{} opts.Env = &Env{}
} }
opts.Env.Scriptorium = &scriptorium.NoopRunner{} opts.Env.Scriptorium = &scriptorium.NoopRunner{}
return executeStages(ctx, cfg, stages, opts) return executePlan(ctx, cfg, plan, opts)
} }
var stdout bytes.Buffer var stdout bytes.Buffer
@@ -224,12 +223,12 @@ previous_session_id: 2026-04-26
executeStagesFn = origExecuteStagesFn executeStagesFn = origExecuteStagesFn
newObjectStoreFromConfigFn = origObjectStoreFn newObjectStoreFromConfigFn = origObjectStoreFn
}) })
executeStagesFn = func(ctx context.Context, cfg *config.Config, stages []stage.Stage, opts RunOptions) (*RunSummary, error) { executeStagesFn = func(ctx context.Context, cfg *config.Config, plan BoundedPlan, opts RunOptions) (*RunSummary, error) {
if opts.Env == nil { if opts.Env == nil {
opts.Env = &Env{} opts.Env = &Env{}
} }
opts.Env.Scriptorium = scriptoriumFake opts.Env.Scriptorium = scriptoriumFake
return executeStages(ctx, cfg, stages, opts) return executePlan(ctx, cfg, plan, opts)
} }
newObjectStoreFromConfigFn = func(context.Context, *config.Config) (storage.ObjectStore, error) { newObjectStoreFromConfigFn = func(context.Context, *config.Config) (storage.ObjectStore, error) {
objectStoreConstructed = true objectStoreConstructed = true

View File

@@ -33,12 +33,10 @@ func Run(ctx context.Context, args []string, out io.Writer) error {
if err != nil { if err != nil {
return fmt.Errorf("run: %w", err) return fmt.Errorf("run: %w", err)
} }
stages := request.Plan.Stages() summary, err := executeStagesFn(ctx, cfg, request.Plan, RunOptions{
summary, err := executeStagesFn(ctx, cfg, stages, RunOptions{
Force: request.Force, Force: request.Force,
SelectedArtifacts: request.SelectedArtifacts, SelectedArtifacts: request.SelectedArtifacts,
EffectiveArtifacts: effectiveArtifacts, EffectiveArtifacts: effectiveArtifacts,
Plan: request.Plan,
}) })
if err != nil { if err != nil {
return fmt.Errorf("run: %w", err) return fmt.Errorf("run: %w", err)

View File

@@ -199,7 +199,7 @@ type singleStageCommand struct {
} }
func runSingleStageCommand(ctx context.Context, req singleStageCommand) (*RunSummary, error) { func runSingleStageCommand(ctx context.Context, req singleStageCommand) (*RunSummary, error) {
stages, err := BuildSingleStagePlan(req.StageName) plan, err := buildSingleStageExecutionPlan(req.StageName)
if err != nil { if err != nil {
return nil, fmt.Errorf("%s: %w", req.CommandName, err) return nil, fmt.Errorf("%s: %w", req.CommandName, err)
} }
@@ -220,7 +220,7 @@ func runSingleStageCommand(ctx context.Context, req singleStageCommand) (*RunSum
if err != nil { if err != nil {
return nil, fmt.Errorf("%s: %w", req.CommandName, err) return nil, fmt.Errorf("%s: %w", req.CommandName, err)
} }
summary, err := executeStagesFn(ctx, cfg, stages, RunOptions{ summary, err := executeStagesFn(ctx, cfg, plan, RunOptions{
Force: req.Force, Force: req.Force,
SelectedArtifacts: req.SelectedArtifacts, SelectedArtifacts: req.SelectedArtifacts,
EffectiveArtifacts: effectiveArtifacts, EffectiveArtifacts: effectiveArtifacts,

View File

@@ -26,7 +26,6 @@ type RunOptions struct {
Force bool Force bool
SelectedArtifacts []string SelectedArtifacts []string
EffectiveArtifacts artifacts.EffectiveArtifactSet EffectiveArtifacts artifacts.EffectiveArtifactSet
Plan BoundedPlan
Env *Env Env *Env
RunManifestStore manifest.RunStore RunManifestStore manifest.RunStore
} }
@@ -41,14 +40,15 @@ type RunSummary struct {
Skipped []string Skipped []string
} }
var executeStagesFn = executeStages var executeStagesFn = executePlan
func executeStages(ctx context.Context, cfg *config.Config, stages []stage.Stage, opts RunOptions) (summary *RunSummary, resultErr error) { func executePlan(ctx context.Context, cfg *config.Config, plan BoundedPlan, opts RunOptions) (summary *RunSummary, resultErr error) {
stages := plan.Stages()
var prerequisiteStore manifest.Store var prerequisiteStore manifest.Store
if opts.Env != nil { if opts.Env != nil {
prerequisiteStore = opts.Env.ManifestStore prerequisiteStore = opts.Env.ManifestStore
} }
if err := inspectBoundedPrerequisites(ctx, cfg, opts.Plan, prerequisiteStore); err != nil { if err := inspectBoundedPrerequisites(ctx, cfg, plan, prerequisiteStore); err != nil {
return nil, fmt.Errorf("validate bounded run prerequisites: %w", err) return nil, fmt.Errorf("validate bounded run prerequisites: %w", err)
} }
effectiveArtifacts := opts.EffectiveArtifacts effectiveArtifacts := opts.EffectiveArtifacts
@@ -143,7 +143,7 @@ func executeStages(ctx context.Context, cfg *config.Config, stages []stage.Stage
// already-invalid request. Recheck the manifest protected by the session // already-invalid request. Recheck the manifest protected by the session
// lock because another invocation may have changed prerequisite state while // lock because another invocation may have changed prerequisite state while
// this invocation waited to acquire the lock. // this invocation waited to acquire the lock.
if err := validateBoundedPrerequisites(opts.Plan, m); err != nil { if err := validateBoundedPrerequisites(plan, m); err != nil {
return nil, fmt.Errorf("validate bounded run prerequisites under session lock: %w", err) return nil, fmt.Errorf("validate bounded run prerequisites under session lock: %w", err)
} }
identity.applyToSessionManifest(m) identity.applyToSessionManifest(m)

View File

@@ -0,0 +1,15 @@
package app
import (
"context"
"gitea.maximumdirect.net/eric/narratio/internal/config"
"gitea.maximumdirect.net/eric/narratio/internal/stage"
)
// executeStages keeps runner tests focused on controlled stage doubles. The
// production command path always supplies one validated BoundedPlan directly.
func executeStages(ctx context.Context, cfg *config.Config, stages []stage.Stage, opts RunOptions) (*RunSummary, error) {
plan := BoundedPlan{stages: append([]stage.Stage(nil), stages...)}
return executePlan(ctx, cfg, plan, opts)
}

View File

@@ -11,7 +11,6 @@ import (
"gitea.maximumdirect.net/eric/narratio/internal/adapters/storage" "gitea.maximumdirect.net/eric/narratio/internal/adapters/storage"
"gitea.maximumdirect.net/eric/narratio/internal/artifacts" "gitea.maximumdirect.net/eric/narratio/internal/artifacts"
"gitea.maximumdirect.net/eric/narratio/internal/config" "gitea.maximumdirect.net/eric/narratio/internal/config"
"gitea.maximumdirect.net/eric/narratio/internal/stage"
) )
func TestExecuteRunAcceptsPositionalSessionID(t *testing.T) { func TestExecuteRunAcceptsPositionalSessionID(t *testing.T) {
@@ -21,7 +20,7 @@ func TestExecuteRunAcceptsPositionalSessionID(t *testing.T) {
var capturedSessionID string var capturedSessionID string
origExecuteStagesFn := executeStagesFn origExecuteStagesFn := executeStagesFn
t.Cleanup(func() { executeStagesFn = origExecuteStagesFn }) t.Cleanup(func() { executeStagesFn = origExecuteStagesFn })
executeStagesFn = func(_ context.Context, cfg *config.Config, _ []stage.Stage, _ RunOptions) (*RunSummary, error) { executeStagesFn = func(_ context.Context, cfg *config.Config, _ BoundedPlan, _ RunOptions) (*RunSummary, error) {
capturedSessionID = cfg.Session.SessionID capturedSessionID = cfg.Session.SessionID
return &RunSummary{ return &RunSummary{
SessionID: cfg.Session.SessionID, SessionID: cfg.Session.SessionID,
@@ -117,7 +116,7 @@ inputs:
`) `)
origExecuteStagesFn := executeStagesFn origExecuteStagesFn := executeStagesFn
t.Cleanup(func() { executeStagesFn = origExecuteStagesFn }) t.Cleanup(func() { executeStagesFn = origExecuteStagesFn })
executeStagesFn = func(_ context.Context, cfg *config.Config, _ []stage.Stage, _ RunOptions) (*RunSummary, error) { executeStagesFn = func(_ context.Context, cfg *config.Config, _ BoundedPlan, _ RunOptions) (*RunSummary, error) {
return &RunSummary{ return &RunSummary{
SessionID: cfg.Session.SessionID, SessionID: cfg.Session.SessionID,
ManifestPath: filepath.Join(workspaceRoot, "manifest.json"), ManifestPath: filepath.Join(workspaceRoot, "manifest.json"),
@@ -194,8 +193,8 @@ func TestExecuteWorkflowCommandsAcceptPositionalSessionID(t *testing.T) {
var capturedArtifacts []string var capturedArtifacts []string
origExecuteStagesFn := executeStagesFn origExecuteStagesFn := executeStagesFn
t.Cleanup(func() { executeStagesFn = origExecuteStagesFn }) t.Cleanup(func() { executeStagesFn = origExecuteStagesFn })
executeStagesFn = func(_ context.Context, _ *config.Config, stages []stage.Stage, opts RunOptions) (*RunSummary, error) { executeStagesFn = func(_ context.Context, _ *config.Config, plan BoundedPlan, opts RunOptions) (*RunSummary, error) {
for _, s := range stages { for _, s := range plan.Stages() {
capturedStages = append(capturedStages, s.Name()) capturedStages = append(capturedStages, s.Name())
} }
capturedForce = opts.Force capturedForce = opts.Force