feat(engine): add RunOptions.Force to skip Detect and call PlanForce

This commit is contained in:
MDietermann
2026-04-14 21:51:29 +02:00
parent d525646f3a
commit 613363e993
2 changed files with 103 additions and 39 deletions

View File

@@ -14,7 +14,10 @@ type RunOptions struct {
Selected []string // module IDs to run; empty = all
DryRun bool // Detect + Plan only, no Apply/Verify
HaltOnError bool // stop at first failure instead of continuing siblings
Reporter module.Reporter
// Force, when true, skips Detect and calls PlanForce on every module
// so each one produces a from-scratch plan regardless of current state.
Force bool
Reporter module.Reporter
}
// ModuleStatus is the terminal state of a module within a run.
@@ -91,26 +94,43 @@ func Run(ctx context.Context, reg *module.Registry, opts RunOptions) (Summary, e
res := &ModuleResult{ID: id}
results[id] = res
state, err := m.Detect(ctx)
if err != nil {
res.Status = StatusFailed
res.Err = fmt.Errorf("detect: %w", err)
markFailed(metas, id, skipped)
if opts.HaltOnError {
break
var (
plan module.Plan
err error
)
if opts.Force {
plan, err = m.PlanForce(ctx)
if err != nil {
res.Status = StatusFailed
res.Err = fmt.Errorf("plan-force: %w", err)
markFailed(metas, id, skipped)
if opts.HaltOnError {
break
}
continue
}
} else {
state, derr := m.Detect(ctx)
if derr != nil {
res.Status = StatusFailed
res.Err = fmt.Errorf("detect: %w", derr)
markFailed(metas, id, skipped)
if opts.HaltOnError {
break
}
continue
}
continue
}
plan, err := m.Plan(ctx, state)
if err != nil {
res.Status = StatusFailed
res.Err = fmt.Errorf("plan: %w", err)
markFailed(metas, id, skipped)
if opts.HaltOnError {
break
plan, err = m.Plan(ctx, state)
if err != nil {
res.Status = StatusFailed
res.Err = fmt.Errorf("plan: %w", err)
markFailed(metas, id, skipped)
if opts.HaltOnError {
break
}
continue
}
continue
}
res.Plan = plan