Documentation
¶
Overview ¶
Package action provides types and execution logic for the Actions system. Actions consume resolved data from resolvers and perform side-effect operations.
Index ¶
- Constants
- func BuildOutputData(result *ExecutionResult, executionData map[string]any) map[string]any
- func CreateIterationName(baseName string, index int) string
- func ExpandForEachItems(ctx context.Context, forEach *spec.ForEachClause, resolverData map[string]any) ([]any, error)
- func GetDeferredInputNames(values map[string]any) []string
- func GetFormat(format string) (string, error)
- func HasDeferredValues(values map[string]any) bool
- func IsForEachIteration(name string) bool
- func Materialize(ctx context.Context, v *spec.ValueRef, resolverData map[string]any) (any, error)
- func MaterializeInputs(ctx context.Context, inputs map[string]*spec.ValueRef, ...) (map[string]any, error)
- func ParseIterationName(name string) (baseName string, index int, ok bool)
- func Render(graph *Graph, opts *RenderOptions) ([]byte, error)
- func ResolveDeferredValues(ctx context.Context, values, resolverData, additionalVars map[string]any) (map[string]any, error)
- func ValidateResult(result any, schema *jsonschema.Schema) error
- func ValidateWorkflow(w *Workflow, registry RegistryInterface) error
- type Action
- type ActionResult
- type ActionStatus
- type AggregatedValidationError
- type BackoffType
- type BuildGraphOptions
- type ConfigInput
- type Context
- func (c *Context) ActionCount() int
- func (c *Context) AddIteration(actionName string, result *ForEachIterationResult)
- func (c *Context) AllActionNames() []string
- func (c *Context) Clone() *Context
- func (c *Context) FinalizeForEach(actionName string, inputs map[string]any) *ActionResult
- func (c *Context) GetIterations(actionName string) []*ForEachIterationResult
- func (c *Context) GetNamespace() map[string]any
- func (c *Context) GetResult(name string) (*ActionResult, bool)
- func (c *Context) HasResult(name string) bool
- func (c *Context) MarkCancelled(name string)
- func (c *Context) MarkFailed(name, errMsg string)
- func (c *Context) MarkRunning(name string, inputs map[string]any)
- func (c *Context) MarkSkipped(name string, reason SkipReason)
- func (c *Context) MarkStreamed(name string)
- func (c *Context) MarkSucceeded(name string, results any)
- func (c *Context) MarkTimeout(name string)
- func (c *Context) Reset()
- func (c *Context) SetResult(name string, result *ActionResult)
- type DeferredValue
- type ErrorContext
- type ExecuteFunc
- type ExecuteResult
- type ExecutionResult
- type ExecutionStatus
- type Executor
- type ExecutorOption
- func OptionsFromAppConfig(cfg ConfigInput) []ExecutorOption
- func WithCwd(cwd string) ExecutorOption
- func WithDefaultTimeout(d time.Duration) ExecutorOption
- func WithExecutionData(data map[string]any) ExecutorOption
- func WithGracePeriod(d time.Duration) ExecutorOption
- func WithIOStreams(streams *provider.IOStreams) ExecutorOption
- func WithMaxConcurrency(n int) ExecutorOption
- func WithProgressCallback(callback ProgressCallback) ExecutorOption
- func WithRegistry(registry RegistryInterface) ExecutorOption
- func WithResolverData(data map[string]any) ExecutorOption
- type ExpandedAction
- type ForEachExecuteFunc
- type ForEachExecutor
- type ForEachExecutorOption
- type ForEachExpansionMetadata
- type ForEachIterationResult
- type Graph
- func (g *Graph) GetActionsByPhase(phase int) []*ExpandedAction
- func (g *Graph) GetAllActionNames() []string
- func (g *Graph) GetFinallyActionNames() []string
- func (g *Graph) GetFinallyActionsByPhase(phase int) []*ExpandedAction
- func (g *Graph) GetForEachIterations(baseName string) []string
- func (g *Graph) GetMainActionNames() []string
- func (g *Graph) TotalFinallyPhases() int
- func (g *Graph) TotalPhases() int
- type GraphVisualization
- type HTTPError
- type NoOpProgressCallback
- func (NoOpProgressCallback) OnActionCancelled(_ string)
- func (NoOpProgressCallback) OnActionComplete(_ string, _ any)
- func (NoOpProgressCallback) OnActionFailed(_ string, _ error)
- func (NoOpProgressCallback) OnActionSkipped(_, _ string)
- func (NoOpProgressCallback) OnActionStart(_ string)
- func (NoOpProgressCallback) OnActionTimeout(_ string, _ time.Duration)
- func (NoOpProgressCallback) OnFinallyComplete()
- func (NoOpProgressCallback) OnFinallyStart()
- func (NoOpProgressCallback) OnForEachProgress(_ string, _, _ int)
- func (NoOpProgressCallback) OnPhaseComplete(_ int)
- func (NoOpProgressCallback) OnPhaseStart(_ int, _ []string)
- func (NoOpProgressCallback) OnRetryAttempt(_ string, _, _ int, _ error)
- type Observer
- type PhaseObserver
- type ProgressCallback
- type RegistryInterface
- type RenderOptions
- type RenderedAction
- type RenderedForEachMetadata
- type RenderedGraph
- type RenderedMetadata
- type RenderedRetryConfig
- type ResultSchemaMode
- type RetryCallback
- type RetryConfig
- type RetryExecutor
- func (r *RetryExecutor) CalculateDelay(attempt int) time.Duration
- func (r *RetryExecutor) ExecuteWithRetry(ctx context.Context, actionName string, execute ExecuteFunc, ...) (*provider.Output, error)
- func (r *RetryExecutor) ExecuteWithRetryDetailed(ctx context.Context, actionName string, execute ExecuteFunc, ...) *RetryResult
- func (r *RetryExecutor) MaxAttempts() int
- func (r *RetryExecutor) ShouldRetry(ctx context.Context, err error, attempt int) (bool, error)
- func (r *RetryExecutor) WithJitter(fn func(time.Duration) time.Duration) *RetryExecutor
- type RetryObserver
- type RetryResult
- type SkipReason
- type ValidationError
- type VisualizationEdge
- type VisualizationPhase
- type VisualizationStats
- type Workflow
Constants ¶
const ( // ErrorTypeHTTP indicates an HTTP-related error with a status code. ErrorTypeHTTP = "http" // ErrorTypeExec indicates a process execution error with an exit code. ErrorTypeExec = "exec" // ErrorTypeTimeout indicates a timeout or deadline exceeded error. ErrorTypeTimeout = "timeout" // ErrorTypeValidation indicates a validation error. ErrorTypeValidation = "validation" // ErrorTypeUnknown indicates an unclassified error. ErrorTypeUnknown = "unknown" )
Error type constants for categorization.
const ( // APIVersion is the version of the rendered graph format. APIVersion = "scafctl.oakwood-commons.github.io/v1alpha1" // KindActionGraph is the kind for rendered action graphs. KindActionGraph = "ActionGraph" // FormatJSON indicates JSON output format. FormatJSON = "json" // FormatYAML indicates YAML output format. FormatYAML = "yaml" )
Variables ¶
This section is empty.
Functions ¶
func BuildOutputData ¶ added in v0.6.0
func BuildOutputData(result *ExecutionResult, executionData map[string]any) map[string]any
BuildOutputData transforms an ExecutionResult and optional execution metadata into a structured map suitable for JSON/YAML output or programmatic consumption.
The returned map contains:
- "status": the final execution status string
- "startTime", "endTime": RFC3339 timestamps
- "duration": human-readable duration
- "actions": map of action name → {status, results?, error?, skipReason?}
- "failedActions", "skippedActions": lists (if non-empty)
- "__execution": execution metadata (if provided)
func CreateIterationName ¶
CreateIterationName creates the expanded name for a forEach iteration. Format: "baseName[index]" (e.g., "deploy[0]", "deploy[1]")
func ExpandForEachItems ¶
func ExpandForEachItems(ctx context.Context, forEach *spec.ForEachClause, resolverData map[string]any) ([]any, error)
ExpandForEachItems evaluates the forEach.In expression and returns the items to iterate over. This is a convenience function that wraps evaluateForEachArray for external use.
func GetDeferredInputNames ¶
GetDeferredInputNames returns the names of inputs that contain deferred values.
func HasDeferredValues ¶
HasDeferredValues checks if any values in the map are deferred.
func IsForEachIteration ¶
IsForEachIteration checks if an action name represents a forEach iteration. Returns true if the name matches the pattern "baseName[index]".
func Materialize ¶
Materialize evaluates a ValueRef, returning either a concrete value or a DeferredValue if it references __actions. This is used during the render phase to prepare action inputs.
func MaterializeInputs ¶
func MaterializeInputs(ctx context.Context, inputs map[string]*spec.ValueRef, resolverData map[string]any) (map[string]any, error)
MaterializeInputs processes all inputs for an action, materializing immediate values and preserving deferred values that reference __actions. Returns a map where concrete values are resolved and __actions references are DeferredValues.
func ParseIterationName ¶
ParseIterationName extracts the base name and index from a forEach iteration name. Returns the base name, index, and true if successful. Returns empty string, -1, false if not a valid iteration name.
func Render ¶
func Render(graph *Graph, opts *RenderOptions) ([]byte, error)
Render produces an executor-ready action graph artifact from the built graph. The output can be serialized to JSON or YAML based on options.
func ResolveDeferredValues ¶
func ResolveDeferredValues(ctx context.Context, values, resolverData, additionalVars map[string]any) (map[string]any, error)
ResolveDeferredValues evaluates all deferred values in the map using the provided additional variables. additionalVars should contain __actions namespace and any alias variables. Non-deferred values are passed through unchanged.
func ValidateResult ¶
func ValidateResult(result any, schema *jsonschema.Schema) error
ValidateResult validates a provider result against the JSON Schema. Returns nil if validation passes or schema is nil.
func ValidateWorkflow ¶
func ValidateWorkflow(w *Workflow, registry RegistryInterface) error
ValidateWorkflow validates the entire workflow definition. It checks all validation rules and returns an aggregated error if any fail. Pass nil for registry to skip provider capability checks.
Types ¶
type Action ¶
type Action struct {
// Name is the action identifier, set from the map key.
// Cannot start with "__" (reserved) or contain "[" or "]".
Name string `` /* 250-byte string literal not displayed */
// Alias provides a short name for use in CEL/template expressions.
// When set, the action's result data is available as a top-level variable
// under this alias, in addition to the standard __actions.<name> reference.
// For example, alias: config allows using config.results.endpoint instead of
// __actions.fetchConfiguration.results.endpoint.
Alias string `` /* 248-byte string literal not displayed */
// Description provides documentation for the action.
Description string `` /* 175-byte string literal not displayed */
// DisplayName is a human-friendly name for UI display.
DisplayName string `` /* 132-byte string literal not displayed */
// Sensitive indicates the action handles sensitive data (masks in logs).
Sensitive bool `json:"sensitive,omitempty" yaml:"sensitive,omitempty" doc:"If true, inputs and outputs are masked in logs"`
// Provider specifies which action provider to use for execution.
// The provider must have CapabilityAction.
Provider string `json:"provider" yaml:"provider" doc:"Action provider name" maxLength:"100" example:"shell"`
// Inputs is a map of input values passed to the provider.
// Values can be literals, resolver references, expressions, or templates.
// Expressions referencing __actions are deferred until runtime.
Inputs map[string]*spec.ValueRef `json:"inputs,omitempty" yaml:"inputs,omitempty" doc:"Input values for the provider"`
// DependsOn lists action names that must complete before this action runs.
// For regular actions, only other regular actions can be referenced.
// For finally actions, only other finally actions can be referenced.
DependsOn []string `json:"dependsOn,omitempty" yaml:"dependsOn,omitempty" doc:"Actions that must complete before this action runs" maxItems:"100"`
// Exclusive lists action names that cannot run in parallel with this action.
// Declaration is one-way: only this action needs to declare the exclusivity.
// The executor serializes execution so that this action and any listed action
// never run simultaneously, regardless of which starts first.
// exclusive does NOT imply dependsOn — order is not guaranteed.
// Referenced actions must exist in the same section (actions or finally).
Exclusive []string `` /* 127-byte string literal not displayed */
// When is a condition that must evaluate to true for the action to execute.
// If false, the action is skipped with SkipReasonCondition.
When *spec.Condition `json:"when,omitempty" yaml:"when,omitempty" doc:"Condition for execution (skipped if false)"`
// OnError defines behavior when this action fails.
// Default is "fail" which stops workflow execution.
OnError spec.OnErrorBehavior `json:"onError,omitempty" yaml:"onError,omitempty" doc:"Error handling behavior" maxLength:"16" example:"fail" default:"fail"`
// Timeout limits how long the action can run.
// If exceeded, the action fails with StatusTimeout.
Timeout *duration.Duration `json:"timeout,omitempty" yaml:"timeout,omitempty" doc:"Maximum execution duration" example:"30s"`
// Retry configures automatic retry on failure.
Retry *RetryConfig `json:"retry,omitempty" yaml:"retry,omitempty" doc:"Retry configuration for transient failures"`
// ForEach enables iteration, executing the action once per array element.
// Only allowed in workflow.actions, not workflow.finally.
ForEach *spec.ForEachClause `json:"forEach,omitempty" yaml:"forEach,omitempty" doc:"Iteration configuration (not allowed in finally)"`
// ResultSchema defines the expected structure of the action's output using JSON Schema.
// If provided, the provider's output is validated against this schema at runtime.
// Supports full JSON Schema 2020-12 specification including $ref, allOf, anyOf, oneOf, etc.
// This enables self-documenting actions and catches mismatches early.
// Use ResultSchemaMode to control validation behavior (error, warn, ignore).
ResultSchema *jsonschema.Schema `json:"resultSchema,omitempty" yaml:"resultSchema,omitempty" doc:"JSON Schema for result validation"`
// ResultSchemaMode controls behavior when result schema validation fails.
// Overrides the workflow-level default. Options: "error" (fail action), "warn" (log and continue), "ignore" (skip validation).
ResultSchemaMode ResultSchemaMode `` /* 134-byte string literal not displayed */
}
Action represents a single action definition. Actions perform side-effect operations using providers and can depend on other actions for sequencing and data flow.
type ActionResult ¶
type ActionResult struct {
// Inputs contains the resolved input values that were passed to the provider.
Inputs map[string]any `json:"inputs" yaml:"inputs" doc:"Resolved inputs passed to provider"`
// Results contains the output data from the provider.
// This is accessible as __actions.<name>.results in CEL/templates.
Results any `json:"results,omitempty" yaml:"results,omitempty" doc:"Provider output data"`
// Status is the final execution status.
Status ActionStatus `json:"status" yaml:"status" doc:"Execution status" maxLength:"16" example:"success"`
// SkipReason explains why the action was skipped (if Status is StatusSkipped).
SkipReason SkipReason `` /* 129-byte string literal not displayed */
// StartTime is when execution began.
StartTime *time.Time `json:"startTime,omitempty" yaml:"startTime,omitempty" doc:"Execution start time"`
// EndTime is when execution completed.
EndTime *time.Time `json:"endTime,omitempty" yaml:"endTime,omitempty" doc:"Execution end time"`
// Error contains the error message if Status is StatusFailed or StatusTimeout.
Error string `` /* 131-byte string literal not displayed */
// Streamed indicates the provider already wrote its output to the terminal.
// When true, the CLI output layer should not re-print the action's results.
Streamed bool `json:"streamed,omitempty" yaml:"streamed,omitempty" doc:"Whether output was streamed to terminal"`
}
ActionResult represents the result of an action execution. It is stored in the __actions namespace and accessible to dependent actions.
func AggregateForEachResults ¶
func AggregateForEachResults( _ string, iterations []*ForEachIterationResult, inputs map[string]any, ) *ActionResult
AggregateForEachResults aggregates forEach iteration results into an ActionResult. This creates the combined result that will be stored in __actions namespace.
func (*ActionResult) Duration ¶
func (r *ActionResult) Duration() time.Duration
Duration returns the execution duration, or zero if not available.
type ActionStatus ¶
type ActionStatus string
ActionStatus represents the execution status of an action.
const ( // StatusPending indicates the action has not started. StatusPending ActionStatus = "pending" // StatusRunning indicates the action is currently executing. StatusRunning ActionStatus = "running" // StatusSucceeded indicates the action completed successfully. StatusSucceeded ActionStatus = "succeeded" // StatusFailed indicates the action failed. StatusFailed ActionStatus = "failed" // StatusSkipped indicates the action was not executed. StatusSkipped ActionStatus = "skipped" // StatusTimeout indicates the action exceeded its timeout. StatusTimeout ActionStatus = "timeout" // StatusCancelled indicates the action was cancelled. StatusCancelled ActionStatus = "cancelled" )
func (ActionStatus) IsSuccess ¶
func (s ActionStatus) IsSuccess() bool
IsSuccess returns true if the status indicates successful completion.
func (ActionStatus) IsTerminal ¶
func (s ActionStatus) IsTerminal() bool
IsTerminal returns true if the status is a terminal state.
type AggregatedValidationError ¶
type AggregatedValidationError struct {
// Errors contains all validation errors found.
Errors []*ValidationError `json:"errors" yaml:"errors" doc:"All validation errors" minItems:"1"`
}
AggregatedValidationError represents multiple validation errors. This is returned when ValidateWorkflow finds multiple issues.
func (*AggregatedValidationError) AddError ¶
func (e *AggregatedValidationError) AddError(err *ValidationError)
AddError adds a validation error.
func (*AggregatedValidationError) Error ¶
func (e *AggregatedValidationError) Error() string
Error implements the error interface.
func (*AggregatedValidationError) HasErrors ¶
func (e *AggregatedValidationError) HasErrors() bool
HasErrors returns true if there are any validation errors.
func (*AggregatedValidationError) ToError ¶
func (e *AggregatedValidationError) ToError() error
ToError returns nil if no errors, or the AggregatedValidationError itself.
type BackoffType ¶
type BackoffType string
BackoffType defines the backoff strategy for retries.
const ( // BackoffFixed uses a constant delay between retries. BackoffFixed BackoffType = "fixed" // BackoffLinear increases delay linearly (initialDelay * attempt). BackoffLinear BackoffType = "linear" // BackoffExponential doubles the delay with each retry. BackoffExponential BackoffType = "exponential" )
func (BackoffType) IsValid ¶
func (b BackoffType) IsValid() bool
IsValid returns true if the backoff type is valid.
func (BackoffType) OrDefault ¶
func (b BackoffType) OrDefault() BackoffType
OrDefault returns the backoff type or the default (BackoffFixed) if empty.
type BuildGraphOptions ¶
type BuildGraphOptions struct {
// SkipInputMaterialization skips input materialization (for validation-only use cases).
SkipInputMaterialization bool
}
BuildGraphOptions configures graph building behavior.
type ConfigInput ¶
type ConfigInput struct {
// DefaultTimeout is the default timeout per action execution
DefaultTimeout time.Duration `json:"defaultTimeout" yaml:"defaultTimeout" doc:"Default timeout per action execution"`
// GracePeriod is the cancellation grace period
GracePeriod time.Duration `json:"gracePeriod" yaml:"gracePeriod" doc:"Cancellation grace period"`
// MaxConcurrency is the max concurrent actions (0 = unlimited)
MaxConcurrency int `json:"maxConcurrency" yaml:"maxConcurrency" doc:"Maximum concurrent actions (0 = unlimited)" maximum:"1000" example:"5"`
}
ConfigInput holds the configuration values for action executor initialization. This mirrors config.ActionConfig but avoids circular dependencies.
type Context ¶
type Context struct {
// contains filtered or unexported fields
}
Context manages the __actions namespace during workflow execution. It provides thread-safe storage for action results and supports forEach iteration result aggregation.
func NewContext ¶
func NewContext() *Context
NewContext creates a new action context for workflow execution.
func (*Context) ActionCount ¶
ActionCount returns the number of actions with results.
func (*Context) AddIteration ¶
func (c *Context) AddIteration(actionName string, result *ForEachIterationResult)
AddIteration records a forEach iteration result. Results are stored in order by index.
func (*Context) AllActionNames ¶
AllActionNames returns all action names that have results.
func (*Context) Clone ¶
Clone creates a deep copy of the action context. Useful for testing or creating snapshots.
func (*Context) FinalizeForEach ¶
func (c *Context) FinalizeForEach(actionName string, inputs map[string]any) *ActionResult
FinalizeForEach aggregates forEach iteration results into a single ActionResult. This should be called after all iterations complete to create the combined result.
func (*Context) GetIterations ¶
func (c *Context) GetIterations(actionName string) []*ForEachIterationResult
GetIterations retrieves all iteration results for a forEach action.
func (*Context) GetNamespace ¶
GetNamespace returns the __actions map for CEL/template evaluation. The returned map contains action results in a format suitable for expression evaluation (e.g., __actions.build.results.exitCode).
func (*Context) GetResult ¶
func (c *Context) GetResult(name string) (*ActionResult, bool)
GetResult retrieves an action's result by name. Returns the result and true if found, nil and false otherwise.
func (*Context) MarkCancelled ¶
MarkCancelled marks an action as cancelled.
func (*Context) MarkFailed ¶
MarkFailed marks an action as failed with an error message.
func (*Context) MarkRunning ¶
MarkRunning marks an action as running with the current time.
func (*Context) MarkSkipped ¶
func (c *Context) MarkSkipped(name string, reason SkipReason)
MarkSkipped marks an action as skipped with a reason.
func (*Context) MarkStreamed ¶ added in v0.4.0
MarkStreamed marks an action as having streamed its output to the terminal.
func (*Context) MarkSucceeded ¶
MarkSucceeded marks an action as successfully completed.
func (*Context) MarkTimeout ¶
MarkTimeout marks an action as timed out.
func (*Context) SetResult ¶
func (c *Context) SetResult(name string, result *ActionResult)
SetResult stores an action's result in the context. This is called after an action completes (success, failure, or skip).
type DeferredValue ¶
type DeferredValue struct {
// OriginalExpr is the original CEL expression string (if expr-based).
OriginalExpr string `json:"originalExpr,omitempty" yaml:"originalExpr,omitempty" doc:"Original CEL expression"`
// OriginalTmpl is the original Go template string (if tmpl-based).
OriginalTmpl string `json:"originalTmpl,omitempty" yaml:"originalTmpl,omitempty" doc:"Original Go template"`
// Deferred indicates this value requires runtime evaluation.
Deferred bool `json:"deferred" yaml:"deferred" doc:"If true, value requires runtime evaluation"`
}
DeferredValue represents an expression that is preserved for runtime evaluation. This is used when a ValueRef references __actions, which cannot be resolved until the referenced action has completed during workflow execution.
func (*DeferredValue) Evaluate ¶
func (d *DeferredValue) Evaluate(ctx context.Context, resolverData, additionalVars map[string]any) (any, error)
Evaluate resolves the deferred value using the provided resolver data and additional variables. The additionalVars should contain both the __actions namespace (keyed by celexp.VarActions) and any alias top-level variables pointing to individual action result data.
func (*DeferredValue) IsDeferred ¶
func (d *DeferredValue) IsDeferred() bool
IsDeferred returns true if this value requires runtime evaluation.
type ErrorContext ¶
type ErrorContext struct {
// Message is the error message string.
Message string `json:"message" yaml:"message" doc:"Error message string" maxLength:"4096" example:"connection refused"`
// Type categorizes the error source.
// Values: "http", "exec", "timeout", "validation", "unknown"
Type string `json:"type" yaml:"type" doc:"Error type classification" maxLength:"32" example:"http"`
// StatusCode is the HTTP status code (0 if not an HTTP error).
StatusCode int `json:"statusCode" yaml:"statusCode" doc:"HTTP status code (0 if not HTTP)" maximum:"599" example:"503"`
// ExitCode is the process exit code (0 if not an exec error).
ExitCode int `json:"exitCode" yaml:"exitCode" doc:"Process exit code (0 if not exec)" maximum:"255" example:"1"`
// Attempt is the current attempt number (1-based).
// First attempt is 1, first retry is 2, etc.
Attempt int `json:"attempt" yaml:"attempt" doc:"Current attempt number (1-based)" maximum:"100" example:"2"`
// MaxAttempts is the maximum attempts configured.
MaxAttempts int `json:"maxAttempts" yaml:"maxAttempts" doc:"Maximum configured attempts" maximum:"100" example:"5"`
}
ErrorContext provides error information for retryIf CEL expressions. It is exposed as __error in the CEL evaluation context.
func NewErrorContext ¶
func NewErrorContext(err error, attempt, maxAttempts int) *ErrorContext
NewErrorContext creates an ErrorContext from an error and attempt info. It inspects the error to determine the type, status code, and exit code.
func (*ErrorContext) ToMap ¶
func (e *ErrorContext) ToMap() map[string]any
ToMap converts ErrorContext to a map for CEL evaluation.
type ExecuteFunc ¶
ExecuteFunc is the function signature for action execution. It takes a context and returns the provider output and any error.
type ExecuteResult ¶
type ExecuteResult struct {
// Iterations contains results for each iteration
Iterations []*ForEachIterationResult `json:"iterations" yaml:"iterations" doc:"Results for each iteration"`
// TotalCount is the total number of iterations
TotalCount int `json:"totalCount" yaml:"totalCount" doc:"Total number of iterations"`
// SuccessCount is the number of successful iterations
SuccessCount int `json:"successCount" yaml:"successCount" doc:"Number of successful iterations"`
// FailureCount is the number of failed iterations
FailureCount int `json:"failureCount" yaml:"failureCount" doc:"Number of failed iterations"`
// AllSucceeded indicates if all iterations succeeded
AllSucceeded bool `json:"allSucceeded" yaml:"allSucceeded" doc:"Whether all iterations succeeded"`
// FirstError is the first error encountered (if any)
FirstError error `json:"-" yaml:"-"`
}
ExecuteResult contains the results of forEach execution.
func (*ExecuteResult) AggregatedResults ¶
func (r *ExecuteResult) AggregatedResults() []any
AggregatedResults returns all iteration results as a slice for __actions.name.results access.
type ExecutionResult ¶
type ExecutionResult struct {
// Actions contains results for all executed actions
Actions map[string]*ActionResult `json:"actions" yaml:"actions" doc:"Results for all actions"`
// FinalStatus is the overall execution status
FinalStatus ExecutionStatus `json:"finalStatus" yaml:"finalStatus" doc:"Overall execution status"`
// StartTime is when execution began
StartTime time.Time `json:"startTime" yaml:"startTime" doc:"Execution start time"`
// EndTime is when execution completed
EndTime time.Time `json:"endTime" yaml:"endTime" doc:"Execution end time"`
// FailedActions contains names of actions that failed
FailedActions []string `json:"failedActions,omitempty" yaml:"failedActions,omitempty" doc:"Names of failed actions"`
// SkippedActions contains names of actions that were skipped
SkippedActions []string `json:"skippedActions,omitempty" yaml:"skippedActions,omitempty" doc:"Names of skipped actions"`
}
ExecutionResult contains the final execution state.
func (*ExecutionResult) Duration ¶
func (r *ExecutionResult) Duration() time.Duration
Duration returns the total execution duration.
type ExecutionStatus ¶
type ExecutionStatus string
ExecutionStatus represents the overall execution status.
const ( // ExecutionSucceeded means all actions completed successfully. ExecutionSucceeded ExecutionStatus = "succeeded" // ExecutionFailed means one or more actions failed. ExecutionFailed ExecutionStatus = "failed" // ExecutionCancelled means execution was cancelled. ExecutionCancelled ExecutionStatus = "cancelled" // ExecutionPartialSuccess means some actions succeeded with onError:continue. ExecutionPartialSuccess ExecutionStatus = "partial-success" )
type Executor ¶
type Executor struct {
// contains filtered or unexported fields
}
Executor runs actions in dependency order with support for parallel execution, retry, timeout, and error handling.
func NewExecutor ¶
func NewExecutor(opts ...ExecutorOption) *Executor
NewExecutor creates a new action executor with the given options. It captures the current working directory at creation time for use as __cwd in action expressions.
func (*Executor) Execute ¶
Execute runs the workflow actions in dependency order. It executes main actions first, then always runs finally actions regardless of failures.
func (*Executor) GetContext ¶
GetContext returns the action context for inspection.
type ExecutorOption ¶
type ExecutorOption func(*Executor)
ExecutorOption configures the executor.
func OptionsFromAppConfig ¶
func OptionsFromAppConfig(cfg ConfigInput) []ExecutorOption
OptionsFromAppConfig creates executor options from app configuration. CLI flags can override these defaults using the returned executor options.
Example:
cfg := action.ActionConfigInput{
DefaultTimeout: 5 * time.Minute,
GracePeriod: 30 * time.Second,
MaxConcurrency: 0,
}
opts := action.OptionsFromAppConfig(cfg)
executor := action.NewExecutor(opts...)
func WithCwd ¶ added in v0.6.0
func WithCwd(cwd string) ExecutorOption
WithCwd sets the original working directory for the executor. This is exposed as __cwd in action expressions.
func WithDefaultTimeout ¶
func WithDefaultTimeout(d time.Duration) ExecutorOption
WithDefaultTimeout sets the default timeout for actions.
func WithExecutionData ¶ added in v0.7.0
func WithExecutionData(data map[string]any) ExecutorOption
WithExecutionData sets the resolver execution metadata for action contexts. When set, the data is injected as __execution into action when conditions and provider inputs, allowing actions to read resolver status, duration, and phase.
func WithGracePeriod ¶
func WithGracePeriod(d time.Duration) ExecutorOption
WithGracePeriod sets how long to wait for running actions during cancellation.
func WithIOStreams ¶ added in v0.4.0
func WithIOStreams(streams *provider.IOStreams) ExecutorOption
WithIOStreams sets the terminal IO streams for provider output streaming. When set, providers that support streaming (e.g., exec, message) can write output directly to the terminal in real-time. All actions share the same raw streams; use the message provider for structured terminal output.
func WithMaxConcurrency ¶
func WithMaxConcurrency(n int) ExecutorOption
WithMaxConcurrency limits the number of parallel actions. Set to 0 for unlimited concurrency.
func WithProgressCallback ¶
func WithProgressCallback(callback ProgressCallback) ExecutorOption
WithProgressCallback sets the progress callback for execution events.
func WithRegistry ¶
func WithRegistry(registry RegistryInterface) ExecutorOption
WithRegistry sets the provider registry for the executor.
func WithResolverData ¶
func WithResolverData(data map[string]any) ExecutorOption
WithResolverData sets the resolver data for input resolution.
type ExpandedAction ¶
type ExpandedAction struct {
// Action is the original action definition.
*Action `json:",inline" yaml:",inline"`
// ExpandedName is the name for this expanded action.
// For forEach actions, this is "baseName[index]" (e.g., "deploy[0]").
// For regular actions, this matches the action's name.
ExpandedName string `json:"expandedName" yaml:"expandedName" doc:"Name for this expanded action" example:"deploy[0]"`
// MaterializedInputs contains inputs that were fully resolved during graph building.
// These do not reference __actions and can be used directly.
MaterializedInputs map[string]any `json:"materializedInputs,omitempty" yaml:"materializedInputs,omitempty" doc:"Resolved input values"`
// DeferredInputs contains inputs that reference __actions and must be resolved at runtime.
DeferredInputs map[string]*DeferredValue `json:"deferredInputs,omitempty" yaml:"deferredInputs,omitempty" doc:"Inputs requiring runtime resolution"`
// Section indicates which workflow section this action belongs to.
Section string `json:"section" yaml:"section" doc:"Workflow section (actions or finally)" example:"actions"`
// ForEachMetadata contains expansion information if this action was expanded from a forEach.
ForEachMetadata *ForEachExpansionMetadata `json:"forEachMetadata,omitempty" yaml:"forEachMetadata,omitempty" doc:"ForEach expansion info"`
// Dependencies contains the same-section scheduling dependencies for this expanded action.
// This includes explicit dependsOn entries and any __actions references that resolve to actions
// within the same section. Only same-section deps affect ExecutionOrder / FinallyOrder phase
// computation; use CrossSectionRefs for informational traceability of cross-section reads.
// For expanded forEach actions, this includes dependencies on all iterations of referenced forEach actions.
Dependencies []string `json:"dependencies" yaml:"dependencies" doc:"Same-section scheduling dependencies"`
// CrossSectionRefs lists action names from a different section that this action reads via
// __actions references (e.g., a finally action reading results from a main actions action).
// These are informational only—they do not affect FinallyOrder or ExecutionOrder phase
// computation because cross-section ordering is guaranteed structurally (all main actions
// complete before any finally action runs).
CrossSectionRefs []string `` /* 145-byte string literal not displayed */
// WhenSkipped is true when the action's when condition was evaluated at graph-build
// time (because it only references resolver data, not __actions/aliases) and returned
// false. The executor skips this action without re-evaluating the condition.
WhenSkipped bool `json:"whenSkipped,omitempty" yaml:"whenSkipped,omitempty" doc:"Action pre-skipped by when condition during graph building"`
// ExpandedExclusive contains the effective exclusive action names for this expanded action.
// For forEach base action references, this expands to all iterations (e.g., "deploy" → "deploy[0]", "deploy[1]").
ExpandedExclusive []string `` /* 133-byte string literal not displayed */
}
ExpandedAction is an action with materialized inputs ready for execution. For forEach actions, each iteration becomes a separate ExpandedAction.
func (*ExpandedAction) GetExpandedName ¶
func (e *ExpandedAction) GetExpandedName() string
GetExpandedName returns the expanded action name. For forEach actions this is "baseName[index]", for regular actions it matches the original name.
func (*ExpandedAction) GetOriginalName ¶
func (e *ExpandedAction) GetOriginalName() string
GetOriginalName returns the original action name (before forEach expansion).
func (*ExpandedAction) HasDeferredInputs ¶
func (e *ExpandedAction) HasDeferredInputs() bool
HasDeferredInputs returns true if the action has any deferred inputs.
func (*ExpandedAction) IsForEachIteration ¶
func (e *ExpandedAction) IsForEachIteration() bool
IsForEachIteration returns true if this action is an expanded forEach iteration.
type ForEachExecuteFunc ¶
ForEachExecuteFunc is the function signature for executing a single forEach iteration. It receives the execution context, the current item, and the iteration index. Returns the provider output and any error.
type ForEachExecutor ¶
type ForEachExecutor struct {
// contains filtered or unexported fields
}
ForEachExecutor handles forEach iteration execution with concurrency control. It manages parallel execution of iterations while respecting concurrency limits and error handling policies.
func FromForEachClause ¶
func FromForEachClause(clause *spec.ForEachClause, progressCallback RetryObserver) *ForEachExecutor
FromForEachClause creates a ForEachExecutor configured from a ForEachClause.
func NewForEachExecutor ¶
func NewForEachExecutor(opts ...ForEachExecutorOption) *ForEachExecutor
NewForEachExecutor creates a new ForEachExecutor with the given options.
func (*ForEachExecutor) Execute ¶
func (e *ForEachExecutor) Execute( ctx context.Context, actionName string, items []any, execute ForEachExecuteFunc, ) (*ExecuteResult, error)
Execute runs forEach iterations with concurrency control and error handling. Items is the array to iterate over, actionName is used for naming iterations.
type ForEachExecutorOption ¶
type ForEachExecutorOption func(*ForEachExecutor)
ForEachExecutorOption configures the ForEachExecutor.
func WithForEachConcurrency ¶
func WithForEachConcurrency(n int) ForEachExecutorOption
WithForEachConcurrency sets the concurrency limit for forEach execution. Set to 0 for unlimited concurrency.
func WithForEachOnError ¶
func WithForEachOnError(behavior spec.OnErrorBehavior) ForEachExecutorOption
WithForEachOnError sets the error handling behavior.
func WithForEachProgressCallback ¶
func WithForEachProgressCallback(callback RetryObserver) ForEachExecutorOption
WithForEachProgressCallback sets the progress callback for forEach execution. It accepts a RetryObserver since forEach only reports retry and iteration progress.
type ForEachExpansionMetadata ¶
type ForEachExpansionMetadata struct {
// ExpandedFrom is the original action name before forEach expansion.
ExpandedFrom string `json:"expandedFrom" yaml:"expandedFrom" doc:"Original action name" example:"deploy"`
// Index is the iteration index (0-based) within the forEach expansion.
Index int `json:"index" yaml:"index" doc:"Iteration index" example:"0"`
// Item is the current iteration item value.
Item any `json:"item,omitempty" yaml:"item,omitempty" doc:"Current iteration item"`
}
ForEachExpansionMetadata tracks forEach expansion information.
type ForEachIterationResult ¶
type ForEachIterationResult struct {
// Index is the 0-based iteration index.
Index int `json:"index" yaml:"index" doc:"Iteration index (0-based)" maximum:"10000" example:"0"`
// Name is the expanded action name (e.g., "deploy[0]", "deploy[1]").
Name string `json:"name" yaml:"name" doc:"Expanded action name" maxLength:"150" example:"deploy[0]"`
// Results contains the output data from this iteration.
Results any `json:"results,omitempty" yaml:"results,omitempty" doc:"Iteration output data"`
// Status is the execution status of this iteration.
Status ActionStatus `json:"status" yaml:"status" doc:"Iteration execution status" maxLength:"16" example:"success"`
// StartTime is when this iteration began.
StartTime *time.Time `json:"startTime,omitempty" yaml:"startTime,omitempty" doc:"Iteration start time"`
// EndTime is when this iteration completed.
EndTime *time.Time `json:"endTime,omitempty" yaml:"endTime,omitempty" doc:"Iteration end time"`
// Error contains the error message if this iteration failed.
Error string `json:"error,omitempty" yaml:"error,omitempty" doc:"Error message (if failed)" maxLength:"4096" example:"timeout exceeded"`
}
ForEachIterationResult represents the result of a single forEach iteration. When an action uses forEach, results are collected into an array of these.
func (*ForEachIterationResult) Duration ¶
func (r *ForEachIterationResult) Duration() time.Duration
Duration returns the iteration execution duration, or zero if not available.
type Graph ¶
type Graph struct {
// Actions is a map of all expanded actions keyed by their name.
// ForEach actions are expanded with indexed names like "deploy[0]", "deploy[1]".
Actions map[string]*ExpandedAction `json:"actions" yaml:"actions" doc:"All expanded actions"`
// ExecutionOrder contains phases of action names that can run in parallel.
// Phase 0 contains actions with no dependencies, phase 1 contains actions
// that depend only on phase 0 actions, and so on.
ExecutionOrder [][]string `json:"executionOrder" yaml:"executionOrder" doc:"Parallel execution phases for main actions"`
// FinallyOrder contains phases for the finally section.
// Finally actions have an implicit dependency on all main actions completing.
FinallyOrder [][]string `json:"finallyOrder,omitempty" yaml:"finallyOrder,omitempty" doc:"Parallel execution phases for finally actions"`
// AliasMap maps action aliases to their original action names.
// This enables shorter, more readable references in CEL expressions.
// For example, alias "config" → action name "fetchConfiguration".
AliasMap map[string]string `json:"aliasMap,omitempty" yaml:"aliasMap,omitempty" doc:"Alias-to-action-name mapping"`
}
Graph represents the executable action dependency graph. It contains expanded actions with materialized inputs and execution order.
func BuildGraph ¶
func BuildGraph(ctx context.Context, w *Workflow, resolverData map[string]any, opts *BuildGraphOptions) (*Graph, error)
BuildGraph constructs the action dependency graph from a workflow. It expands forEach actions, materializes inputs (where possible), extracts dependencies, and computes execution phases.
func (*Graph) GetActionsByPhase ¶
func (g *Graph) GetActionsByPhase(phase int) []*ExpandedAction
GetActionsByPhase returns all actions in a specific execution phase.
func (*Graph) GetAllActionNames ¶
GetAllActionNames returns all action names in the graph including expanded forEach names.
func (*Graph) GetFinallyActionNames ¶
GetFinallyActionNames returns only the finally section action names.
func (*Graph) GetFinallyActionsByPhase ¶
func (g *Graph) GetFinallyActionsByPhase(phase int) []*ExpandedAction
GetFinallyActionsByPhase returns all finally actions in a specific execution phase.
func (*Graph) GetForEachIterations ¶
GetForEachIterations returns all expanded iteration names for a base action name. Returns nil if the action is not a forEach action or doesn't exist.
func (*Graph) GetMainActionNames ¶
GetMainActionNames returns only the main section action names.
func (*Graph) TotalFinallyPhases ¶
TotalFinallyPhases returns the total number of execution phases for finally actions.
func (*Graph) TotalPhases ¶
TotalPhases returns the total number of execution phases for main actions.
type GraphVisualization ¶
type GraphVisualization struct {
// Phases contains main action phases for visualization.
Phases []*VisualizationPhase `json:"phases" yaml:"phases" doc:"Main action phases for visualization" maxItems:"100"`
// FinallyPhases contains finally action phases.
FinallyPhases []*VisualizationPhase `json:"finallyPhases,omitempty" yaml:"finallyPhases,omitempty" doc:"Finally/cleanup action phases" maxItems:"100"`
// Edges represents same-section scheduling dependencies between actions.
Edges []*VisualizationEdge `json:"edges" yaml:"edges" doc:"Same-section scheduling dependencies" maxItems:"10000"`
// CrossSectionEdges represents informational cross-section references
// (e.g. finally actions reading main-section results via __actions).
CrossSectionEdges []*VisualizationEdge `` /* 131-byte string literal not displayed */
// Stats contains graph statistics.
Stats *VisualizationStats `json:"stats" yaml:"stats" doc:"Graph statistics"`
}
GraphVisualization holds visualization data for rendering.
func BuildVisualization ¶
func BuildVisualization(graph *Graph) *GraphVisualization
BuildVisualization creates visualization data from a Graph.
func (*GraphVisualization) RenderASCII ¶
func (v *GraphVisualization) RenderASCII(w io.Writer) error
RenderASCII generates ASCII art representation of the action graph.
func (*GraphVisualization) RenderDOT ¶
func (v *GraphVisualization) RenderDOT(w io.Writer) error
RenderDOT generates GraphViz DOT format.
func (*GraphVisualization) RenderMermaid ¶
func (v *GraphVisualization) RenderMermaid(w io.Writer) error
RenderMermaid generates Mermaid diagram format.
type HTTPError ¶
type HTTPError struct {
StatusCode int `json:"statusCode" yaml:"statusCode" doc:"HTTP status code" maximum:"599" example:"503"`
Message string `json:"message" yaml:"message" doc:"Error message" maxLength:"4096" example:"Service Unavailable"`
}
HTTPError represents an HTTP error with a status code. Providers can return this error type to enable status code-based retry logic.
type NoOpProgressCallback ¶
type NoOpProgressCallback struct{}
NoOpProgressCallback is a progress callback that does nothing. Useful for testing or when progress tracking is not needed.
func (NoOpProgressCallback) OnActionCancelled ¶
func (NoOpProgressCallback) OnActionCancelled(_ string)
func (NoOpProgressCallback) OnActionComplete ¶
func (NoOpProgressCallback) OnActionComplete(_ string, _ any)
func (NoOpProgressCallback) OnActionFailed ¶
func (NoOpProgressCallback) OnActionFailed(_ string, _ error)
func (NoOpProgressCallback) OnActionSkipped ¶
func (NoOpProgressCallback) OnActionSkipped(_, _ string)
func (NoOpProgressCallback) OnActionStart ¶
func (NoOpProgressCallback) OnActionStart(_ string)
func (NoOpProgressCallback) OnActionTimeout ¶
func (NoOpProgressCallback) OnActionTimeout(_ string, _ time.Duration)
func (NoOpProgressCallback) OnFinallyComplete ¶
func (NoOpProgressCallback) OnFinallyComplete()
func (NoOpProgressCallback) OnFinallyStart ¶
func (NoOpProgressCallback) OnFinallyStart()
func (NoOpProgressCallback) OnForEachProgress ¶
func (NoOpProgressCallback) OnForEachProgress(_ string, _, _ int)
func (NoOpProgressCallback) OnPhaseComplete ¶
func (NoOpProgressCallback) OnPhaseComplete(_ int)
func (NoOpProgressCallback) OnPhaseStart ¶
func (NoOpProgressCallback) OnPhaseStart(_ int, _ []string)
func (NoOpProgressCallback) OnRetryAttempt ¶
func (NoOpProgressCallback) OnRetryAttempt(_ string, _, _ int, _ error)
type Observer ¶ added in v0.6.0
type Observer interface {
// OnActionStart is called when an action begins execution.
OnActionStart(actionName string)
// OnActionComplete is called when an action completes successfully.
OnActionComplete(actionName string, results any)
// OnActionFailed is called when an action fails.
OnActionFailed(actionName string, err error)
// OnActionSkipped is called when an action is skipped.
OnActionSkipped(actionName, reason string)
// OnActionTimeout is called when an action times out.
OnActionTimeout(actionName string, timeout time.Duration)
// OnActionCancelled is called when an action is cancelled.
OnActionCancelled(actionName string)
}
Observer receives lifecycle events for individual actions. Implement this interface when you only need to track action-level events (start, complete, fail, skip, timeout, cancel).
type PhaseObserver ¶ added in v0.6.0
type PhaseObserver interface {
// OnPhaseStart is called when a new execution phase begins.
OnPhaseStart(phase int, actionNames []string)
// OnPhaseComplete is called when an execution phase completes.
OnPhaseComplete(phase int)
// OnFinallyStart is called when the finally section begins.
OnFinallyStart()
// OnFinallyComplete is called when the finally section completes.
OnFinallyComplete()
}
PhaseObserver receives lifecycle events for execution phases. Implement this interface when you only need to track phase boundaries and the finally section.
type ProgressCallback ¶
type ProgressCallback interface {
Observer
PhaseObserver
RetryObserver
}
ProgressCallback receives execution events for progress reporting. It composes ActionObserver, PhaseObserver, and RetryObserver for full lifecycle coverage. New code should prefer accepting the narrower observer interface(s) it actually needs.
type RegistryInterface ¶
type RegistryInterface interface {
// Get retrieves a provider by name.
Get(name string) (provider.Provider, bool)
// Has checks if a provider exists.
Has(name string) bool
}
RegistryInterface defines the provider registry operations needed for validation. This interface allows for mocking in tests.
type RenderOptions ¶
type RenderOptions struct {
// Format specifies the output format: "json" (default) or "yaml".
Format string `json:"format" yaml:"format" doc:"Output format" maxLength:"16" example:"json"`
// IncludeTimestamp adds a generation timestamp to metadata.
IncludeTimestamp bool `json:"includeTimestamp" yaml:"includeTimestamp" doc:"Add generation timestamp to metadata"`
// PrettyPrint enables indented output for readability.
PrettyPrint bool `json:"prettyPrint" yaml:"prettyPrint" doc:"Enable indented output"`
}
RenderOptions configures rendering behavior.
func DefaultRenderOptions ¶
func DefaultRenderOptions() *RenderOptions
DefaultRenderOptions returns the default rendering options.
type RenderedAction ¶
type RenderedAction struct {
// Name is the action name (may be expanded with index for forEach).
Name string `json:"name" yaml:"name" doc:"Action name" maxLength:"150" example:"deploy[0]"`
// OriginalName is the action name before forEach expansion (if applicable).
OriginalName string `` /* 127-byte string literal not displayed */
// Description provides documentation for the action.
Description string `json:"description,omitempty" yaml:"description,omitempty" doc:"Human-readable description" maxLength:"500"`
// DisplayName is a human-friendly name for UI display.
DisplayName string `json:"displayName,omitempty" yaml:"displayName,omitempty" doc:"Display name for UI" maxLength:"100"`
// Sensitive indicates the action handles sensitive data.
Sensitive bool `json:"sensitive,omitempty" yaml:"sensitive,omitempty" doc:"If true, mask in logs"`
// Provider specifies which action provider to use.
Provider string `json:"provider" yaml:"provider" doc:"Provider name" maxLength:"100" example:"shell"`
// DependsOn lists action names that must complete first.
DependsOn []string `json:"dependsOn,omitempty" yaml:"dependsOn,omitempty" doc:"Dependency list" maxItems:"100"`
// CrossSectionRefs lists action names from the other workflow section that this action
// reads via __actions references. Informational only — does not affect phase scheduling.
// Populated for finally actions that read from workflow.actions via __actions.<name>.
CrossSectionRefs []string `` /* 139-byte string literal not displayed */
// When contains the condition for execution.
// Can be a boolean (already evaluated) or a DeferredValue (requires runtime evaluation).
When any `json:"when,omitempty" yaml:"when,omitempty" doc:"Execution condition (bool or deferred)"`
// OnError defines behavior when this action fails.
OnError string `json:"onError,omitempty" yaml:"onError,omitempty" doc:"Error handling behavior" example:"fail"`
// Timeout is the maximum execution duration as a string.
Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty" doc:"Max duration" example:"30s"`
// Retry contains retry configuration.
Retry *RenderedRetryConfig `json:"retry,omitempty" yaml:"retry,omitempty" doc:"Retry settings"`
// Inputs contains the action inputs.
// Values are either concrete (materialized) or DeferredValue structs.
Inputs map[string]any `json:"inputs" yaml:"inputs" doc:"Action inputs (may contain deferred values)"`
// Section indicates which workflow section this action belongs to.
Section string `json:"section" yaml:"section" doc:"Workflow section" example:"actions"`
// ForEach contains forEach metadata if this is an expanded iteration.
ForEach *RenderedForEachMetadata `json:"forEach,omitempty" yaml:"forEach,omitempty" doc:"ForEach expansion info"`
}
RenderedAction is a fully rendered action ready for execution.
type RenderedForEachMetadata ¶
type RenderedForEachMetadata struct {
// ExpandedFrom is the original action name before expansion.
ExpandedFrom string `json:"expandedFrom" yaml:"expandedFrom" doc:"Original action name" example:"deploy"`
// Index is the iteration index (0-based).
Index int `json:"index" yaml:"index" doc:"Iteration index" example:"0"`
// Item is the current iteration item value.
Item any `json:"item,omitempty" yaml:"item,omitempty" doc:"Iteration item value"`
// Concurrency is the concurrency limit from the original forEach clause.
Concurrency int `json:"concurrency,omitempty" yaml:"concurrency,omitempty" doc:"Concurrency limit (0=unlimited)"`
// OnError is the error handling behavior for forEach iterations.
OnError string `json:"onError,omitempty" yaml:"onError,omitempty" doc:"ForEach error handling" example:"fail"`
}
RenderedForEachMetadata tracks forEach expansion information in rendered output.
type RenderedGraph ¶
type RenderedGraph struct {
// APIVersion identifies the schema version.
APIVersion string `json:"apiVersion" yaml:"apiVersion" doc:"Schema version" example:"scafctl.oakwood-commons.github.io/v1alpha1"`
// Kind identifies the resource type.
Kind string `json:"kind" yaml:"kind" doc:"Resource kind" example:"ActionGraph"`
// Metadata contains graph-level metadata.
Metadata *RenderedMetadata `json:"metadata,omitempty" yaml:"metadata,omitempty" doc:"Graph metadata"`
// ExecutionOrder contains phases of action names that can run in parallel.
ExecutionOrder [][]string `json:"executionOrder" yaml:"executionOrder" doc:"Parallel execution phases for main actions"`
// FinallyOrder contains phases for the finally section.
FinallyOrder [][]string `json:"finallyOrder,omitempty" yaml:"finallyOrder,omitempty" doc:"Parallel execution phases for finally actions"`
// Actions is a map of all rendered actions keyed by their name.
Actions map[string]*RenderedAction `json:"actions" yaml:"actions" doc:"All actions in the graph"`
}
RenderedGraph is the executor-ready action graph output structure. This is the serializable form that can be consumed by external executors.
func RenderToStruct ¶
func RenderToStruct(graph *Graph, opts *RenderOptions) (*RenderedGraph, error)
RenderToStruct produces a RenderedGraph struct without serializing to bytes. This is useful for programmatic access to the rendered graph.
type RenderedMetadata ¶
type RenderedMetadata struct {
// GeneratedAt is the timestamp when the graph was rendered.
GeneratedAt string `json:"generatedAt,omitempty" yaml:"generatedAt,omitempty" doc:"Render timestamp" example:"2026-01-29T12:00:00Z"`
// TotalActions is the total number of actions in the graph.
TotalActions int `json:"totalActions" yaml:"totalActions" doc:"Total action count" example:"5"`
// TotalPhases is the total number of execution phases (main + finally).
TotalPhases int `json:"totalPhases" yaml:"totalPhases" doc:"Total phase count" example:"3"`
// HasFinally indicates if the graph has finally actions.
HasFinally bool `json:"hasFinally" yaml:"hasFinally" doc:"Whether finally section exists"`
// ForEachExpansions maps original action names to their expanded names.
ForEachExpansions map[string][]string `json:"forEachExpansions,omitempty" yaml:"forEachExpansions,omitempty" doc:"ForEach expansion mapping"`
}
RenderedMetadata contains graph-level metadata.
type RenderedRetryConfig ¶
type RenderedRetryConfig struct {
// MaxAttempts is the total number of execution attempts.
MaxAttempts int `json:"maxAttempts" yaml:"maxAttempts" doc:"Total attempts" minimum:"1" example:"3"`
// Backoff defines the delay strategy between retries.
Backoff string `json:"backoff,omitempty" yaml:"backoff,omitempty" doc:"Backoff strategy" example:"exponential"`
// InitialDelay is the delay before the first retry.
InitialDelay string `json:"initialDelay,omitempty" yaml:"initialDelay,omitempty" doc:"Initial delay" example:"1s"`
// MaxDelay caps the maximum delay between retries.
MaxDelay string `json:"maxDelay,omitempty" yaml:"maxDelay,omitempty" doc:"Max delay cap" example:"30s"`
}
RenderedRetryConfig is the serializable retry configuration.
type ResultSchemaMode ¶
type ResultSchemaMode string
ResultSchemaMode defines the validation behavior when result schema validation fails.
const ( // ResultSchemaModeError fails the action when schema validation fails (default). ResultSchemaModeError ResultSchemaMode = "error" // ResultSchemaModeWarn logs a warning and continues execution. ResultSchemaModeWarn ResultSchemaMode = "warn" // ResultSchemaModeIgnore skips schema validation entirely. ResultSchemaModeIgnore ResultSchemaMode = "ignore" )
func (ResultSchemaMode) IsValid ¶
func (m ResultSchemaMode) IsValid() bool
IsValid returns true if the result schema mode is valid.
func (ResultSchemaMode) OrDefault ¶
func (m ResultSchemaMode) OrDefault() ResultSchemaMode
OrDefault returns the mode or the default (ResultSchemaModeError) if empty.
type RetryCallback ¶
type RetryCallback interface {
// OnRetryAttempt is called before each retry attempt (not for the initial attempt).
// attempt is 1-indexed (first retry is attempt 2).
// err is the error from the previous attempt.
OnRetryAttempt(actionName string, attempt, maxAttempts int, err error)
}
RetryCallback receives retry events for progress reporting.
type RetryConfig ¶
type RetryConfig struct {
// MaxAttempts is the total number of execution attempts (including initial).
// Must be >= 1.
MaxAttempts int `json:"maxAttempts" yaml:"maxAttempts" doc:"Total execution attempts (min: 1)" minimum:"1" maximum:"100" example:"3"`
// Backoff defines the delay strategy between retries.
// Default is "fixed".
Backoff BackoffType `json:"backoff,omitempty" yaml:"backoff,omitempty" doc:"Backoff strategy" maxLength:"16" example:"exponential" default:"fixed"`
// InitialDelay is the delay before the first retry.
// For exponential backoff, subsequent delays are multiplied by 2.
InitialDelay *duration.Duration `json:"initialDelay,omitempty" yaml:"initialDelay,omitempty" doc:"Delay before first retry" example:"1s"`
// MaxDelay caps the maximum delay between retries.
// Only meaningful for linear and exponential backoff.
MaxDelay *duration.Duration `json:"maxDelay,omitempty" yaml:"maxDelay,omitempty" doc:"Maximum delay between retries" example:"30s"`
// RetryIf is a CEL expression that determines whether a retry should occur.
// The expression has access to __error context with error details:
// - __error.message: Error message string
// - __error.type: Error type ("http", "exec", "timeout", "validation", "unknown")
// - __error.statusCode: HTTP status code (0 if not HTTP)
// - __error.exitCode: Process exit code (0 if not exec)
// - __error.attempt: Current attempt number (1-based)
// - __error.maxAttempts: Maximum configured attempts
// If not specified, all errors are retried (default behavior).
// If specified and evaluates to false, no retry occurs.
// Example: "${ __error.statusCode == 429 || __error.statusCode >= 500 }"
RetryIf *celexp.Expression `json:"retryIf,omitempty" yaml:"retryIf,omitempty" doc:"CEL expression to determine if retry should occur"`
}
RetryConfig defines automatic retry behavior for failed actions.
type RetryExecutor ¶
type RetryExecutor struct {
// contains filtered or unexported fields
}
RetryExecutor wraps action execution with retry logic and backoff strategies. It handles transient failures by retrying the action up to maxAttempts times with configurable delays between attempts.
func NewRetryExecutor ¶
func NewRetryExecutor(config *RetryConfig) *RetryExecutor
NewRetryExecutor creates a new retry executor with the given configuration. If config is nil, returns an executor that performs no retries (single attempt).
func (*RetryExecutor) CalculateDelay ¶
func (r *RetryExecutor) CalculateDelay(attempt int) time.Duration
CalculateDelay computes the delay before a retry attempt based on the backoff strategy. attempt is 1-indexed (first retry is attempt 2, since attempt 1 is the initial execution). Returns 0 for the first attempt or if no retry config is set.
func (*RetryExecutor) ExecuteWithRetry ¶
func (r *RetryExecutor) ExecuteWithRetry( ctx context.Context, actionName string, execute ExecuteFunc, callback RetryCallback, ) (*provider.Output, error)
ExecuteWithRetry runs an action with retry support. It executes the action up to maxAttempts times, with delays between retries based on the configured backoff strategy.
Parameters: - ctx: Context for cancellation and timeout - actionName: Name of the action (for callbacks) - execute: Function that performs the actual action execution - callback: Optional callback for retry events (can be nil)
Returns the output from a successful execution or the last error if all attempts fail.
func (*RetryExecutor) ExecuteWithRetryDetailed ¶
func (r *RetryExecutor) ExecuteWithRetryDetailed( ctx context.Context, actionName string, execute ExecuteFunc, callback RetryCallback, ) *RetryResult
ExecuteWithRetryDetailed runs an action with retry support and returns detailed results. This is useful for debugging and detailed progress reporting.
func (*RetryExecutor) MaxAttempts ¶
func (r *RetryExecutor) MaxAttempts() int
MaxAttempts returns the maximum number of execution attempts. Returns 1 if no config is set (no retries).
func (*RetryExecutor) ShouldRetry ¶
ShouldRetry determines if an execution should be retried based on the error and attempt number. Returns (shouldRetry, error). The error is non-nil if retryIf expression evaluation fails. Returns false if: - No retry config is set - Max attempts reached - Context was cancelled - The error is nil (success) - retryIf expression evaluates to false
func (*RetryExecutor) WithJitter ¶
func (r *RetryExecutor) WithJitter(fn func(time.Duration) time.Duration) *RetryExecutor
WithJitter sets a custom jitter function for testing. The jitter function receives the base delay and returns a modified delay.
type RetryObserver ¶ added in v0.6.0
type RetryObserver interface {
// OnRetryAttempt is called before each retry attempt.
OnRetryAttempt(actionName string, attempt, maxAttempts int, err error)
// OnForEachProgress is called during forEach execution.
OnForEachProgress(actionName string, completed, total int)
}
RetryObserver receives retry and iteration progress events. Implement this interface when you only need to track retries and forEach progress.
type RetryResult ¶
type RetryResult struct {
// Output is the successful output (nil if all attempts failed)
Output *provider.Output `json:"output,omitempty" yaml:"output,omitempty" doc:"Successful output (nil if all attempts failed)"`
// Attempts is the total number of attempts made
Attempts int `json:"attempts" yaml:"attempts" doc:"Total number of attempts made" maximum:"100" example:"3"`
// TotalDuration is the total time spent including delays
TotalDuration time.Duration `json:"totalDuration" yaml:"totalDuration" doc:"Total time spent including delays"`
// FinalError is the error from the last attempt (nil if succeeded)
FinalError error `json:"finalError,omitempty" yaml:"finalError,omitempty" doc:"Error from the last attempt (nil if succeeded)"`
// AttemptErrors contains errors from each attempt
AttemptErrors []error `json:"attemptErrors,omitempty" yaml:"attemptErrors,omitempty" doc:"Errors from each attempt" maxItems:"100"`
}
RetryResult contains information about a retry execution.
type SkipReason ¶
type SkipReason string
SkipReason indicates why an action was skipped.
const ( // SkipReasonCondition indicates the when condition evaluated to false. SkipReasonCondition SkipReason = "condition" // SkipReasonDependencyFailed indicates a required dependency failed. SkipReasonDependencyFailed SkipReason = "dependency-failed" )
type ValidationError ¶
type ValidationError struct {
// Section is the workflow section where the error occurred ("actions" or "finally").
Section string `json:"section,omitempty" yaml:"section,omitempty" doc:"Workflow section (actions or finally)" example:"actions"`
// ActionName is the name of the action with the validation error.
ActionName string `json:"actionName,omitempty" yaml:"actionName,omitempty" doc:"Action that failed validation" example:"deploy"`
// Field is the specific field that failed validation.
Field string `json:"field,omitempty" yaml:"field,omitempty" doc:"Field that failed validation" example:"dependsOn"`
// Message is the human-readable validation error message.
Message string `json:"message" yaml:"message" doc:"Validation failure message" maxLength:"500"`
}
ValidationError provides detailed validation failure information. It contains context about where the validation error occurred.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
Error implements the error interface.
type VisualizationEdge ¶
type VisualizationEdge struct {
From string `json:"from" yaml:"from" doc:"Source action name" maxLength:"256" example:"deploy"`
To string `json:"to" yaml:"to" doc:"Target action name" maxLength:"256" example:"build"`
Label string `json:"label,omitempty" yaml:"label,omitempty" doc:"Edge label" maxLength:"128" example:"depends_on"`
CrossSection bool `` /* 141-byte string literal not displayed */
}
VisualizationEdge represents a dependency edge.
type VisualizationPhase ¶
type VisualizationPhase struct {
Phase int `json:"phase" yaml:"phase" doc:"Phase number" maximum:"100" example:"1"`
Actions []string `json:"actions" yaml:"actions" doc:"Action names in this phase" maxItems:"1000"`
Section string `json:"section" yaml:"section" doc:"Workflow section (actions or finally)" maxLength:"16" example:"actions"`
}
VisualizationPhase represents a phase in the execution order.
type VisualizationStats ¶
type VisualizationStats struct {
TotalActions int `json:"totalActions" yaml:"totalActions" doc:"Total number of actions" maximum:"1000" example:"10"`
TotalPhases int `json:"totalPhases" yaml:"totalPhases" doc:"Total number of phases" maximum:"100" example:"3"`
MaxParallelism int `json:"maxParallelism" yaml:"maxParallelism" doc:"Maximum parallelism across all phases" maximum:"1000" example:"4"`
AvgDependencies float64 `json:"avgDependencies" yaml:"avgDependencies" doc:"Average same-section scheduling dependencies per action"`
AvgCrossSectionRefs float64 `json:"avgCrossSectionRefs,omitempty" yaml:"avgCrossSectionRefs,omitempty" doc:"Average cross-section references per action"`
HasFinally bool `json:"hasFinally" yaml:"hasFinally" doc:"Whether the graph has finally actions"`
ForEachCount int `json:"forEachCount" yaml:"forEachCount" doc:"Number of forEach actions" maximum:"1000" example:"2"`
}
VisualizationStats contains graph statistics.
type Workflow ¶
type Workflow struct {
// Actions is a map of action definitions that execute based on their dependencies.
// Actions can depend on other actions and access their results via __actions.<name>.results.
Actions map[string]*Action `json:"actions,omitempty" yaml:"actions,omitempty" doc:"Action definitions keyed by name"`
// Finally is a map of actions that execute after all regular actions complete.
// Finally actions cannot use dependsOn to reference regular actions, but can
// access all regular action results. They have an implicit dependency on all regular actions.
Finally map[string]*Action `json:"finally,omitempty" yaml:"finally,omitempty" doc:"Cleanup/finalization actions that run after all regular actions"`
// ResultSchemaMode sets the default validation behavior for resultSchema across all actions.
// Individual actions can override this setting. Default is "error".
ResultSchemaMode ResultSchemaMode `` /* 158-byte string literal not displayed */
}
Workflow contains the action execution specification. It defines two sections: regular actions that execute based on dependencies, and finally actions that execute after all regular actions complete.
func FilterWorkflowActions ¶ added in v0.8.0
FilterWorkflowActions returns a new Workflow containing only the specified actions and their transitive dependsOn dependencies. Finally actions are always included regardless of the filter. When targetNames is empty the original workflow is returned unchanged.
An error is returned if any target name does not match an action in the workflow's actions section.