Implement resume, skip, and stage selection

This commit is contained in:
2026-05-02 11:38:42 -05:00
parent 77f421feef
commit bec784f1ec
11 changed files with 518 additions and 23 deletions

View File

@@ -32,6 +32,18 @@ func (s failingStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest)
return nil, s.err
}
type countingStage struct {
name string
runs *int
}
func (s countingStage) Name() string { return s.name }
func (s countingStage) Declares() stage.IODecl { return stage.IODecl{} }
func (s countingStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) {
*s.runs = *s.runs + 1
return &stage.StageResult{Metadata: map[string]any{"counting": true}}, nil
}
func TestExecuteStagesPlaceholderSuccessUpdatesManifest(t *testing.T) {
cfg := testConfig(t)
@@ -39,8 +51,8 @@ func TestExecuteStagesPlaceholderSuccessUpdatesManifest(t *testing.T) {
if err != nil {
t.Fatalf("executeStages() error = %v", err)
}
if len(summary.StageNames) != 8 {
t.Fatalf("stage count = %d, want 8", len(summary.StageNames))
if len(summary.StageNames) != 8 || len(summary.Executed) != 8 || len(summary.Skipped) != 0 {
t.Fatalf("summary = %#v, want all 8 executed", summary)
}
store := &manifest.LocalStore{}
@@ -76,6 +88,75 @@ func TestExecuteStagesPlaceholderSuccessUpdatesManifest(t *testing.T) {
}
}
func TestExecuteStagesSkipSucceededWhenNotForced(t *testing.T) {
cfg := testConfig(t)
manifestPath := manifestPathFor(cfg)
store := &manifest.LocalStore{}
existing := manifest.New(cfg.Session.SessionID, time.Date(2026, 5, 3, 1, 0, 0, 0, time.UTC))
existing.MarkStageSucceeded("transcribe", time.Date(2026, 5, 3, 1, 1, 0, 0, time.UTC), []manifest.ArtifactRecord{{Kind: "transcript_raw", LocalPath: "existing.json"}})
existing.Stages["transcribe"].Metadata = map[string]any{"kept": true}
if err := os.MkdirAll(filepath.Dir(manifestPath), 0o755); err != nil {
t.Fatalf("MkdirAll() error = %v", err)
}
if err := store.Save(context.Background(), manifestPath, existing); err != nil {
t.Fatalf("Save manifest error = %v", err)
}
runs := 0
stageToRun := countingStage{name: "transcribe", runs: &runs}
summary, err := executeStages(context.Background(), cfg, []stage.Stage{stageToRun}, RunOptions{})
if err != nil {
t.Fatalf("executeStages() error = %v", err)
}
if runs != 0 {
t.Fatalf("runs = %d, want 0 due to skip", runs)
}
if len(summary.Executed) != 0 || len(summary.Skipped) != 1 || summary.Skipped[0] != "transcribe" {
t.Fatalf("summary = %#v, want skipped transcribe", summary)
}
loaded, err := store.Load(context.Background(), manifestPath)
if err != nil {
t.Fatalf("Load manifest error = %v", err)
}
sr := loaded.Stages["transcribe"]
if sr == nil || sr.Status != manifest.StatusSucceeded {
t.Fatalf("transcribe status = %#v, want succeeded", sr)
}
if sr.Metadata == nil || sr.Metadata["kept"] != true {
t.Fatalf("transcribe metadata = %#v, want preserved", sr.Metadata)
}
}
func TestExecuteStagesForceRerunsSucceeded(t *testing.T) {
cfg := testConfig(t)
manifestPath := manifestPathFor(cfg)
store := &manifest.LocalStore{}
existing := manifest.New(cfg.Session.SessionID, time.Date(2026, 5, 3, 1, 0, 0, 0, time.UTC))
existing.MarkStageSucceeded("transcribe", time.Date(2026, 5, 3, 1, 1, 0, 0, time.UTC), nil)
if err := os.MkdirAll(filepath.Dir(manifestPath), 0o755); err != nil {
t.Fatalf("MkdirAll() error = %v", err)
}
if err := store.Save(context.Background(), manifestPath, existing); err != nil {
t.Fatalf("Save manifest error = %v", err)
}
runs := 0
stageToRun := countingStage{name: "transcribe", runs: &runs}
summary, err := executeStages(context.Background(), cfg, []stage.Stage{stageToRun}, RunOptions{Force: true})
if err != nil {
t.Fatalf("executeStages() error = %v", err)
}
if runs != 1 {
t.Fatalf("runs = %d, want 1 with force", runs)
}
if len(summary.Executed) != 1 || summary.Executed[0] != "transcribe" || len(summary.Skipped) != 0 {
t.Fatalf("summary = %#v, want executed transcribe", summary)
}
}
func TestExecuteStagesFailureUpdatesManifest(t *testing.T) {
cfg := testConfig(t)