ui

package
v1.228.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 6, 2026 License: Apache-2.0 Imports: 38 Imported by: 0

Documentation

Overview

Package ui provides Terraform streaming UI components.

Package ui provides a streaming TUI for Terraform operations. It parses Terraform's JSON streaming output and displays real-time resource status in a Docker-build-style inline interface.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ConfirmApply

func ConfirmApply() (bool, error)

ConfirmApply prompts the user to confirm applying changes.

func ConfirmDestroy

func ConfirmDestroy() (bool, error)

ConfirmDestroy prompts the user to confirm destroying resources.

func Execute

func Execute(ctx context.Context, opts *ExecuteOptions) error

Execute runs a terraform command with streaming UI output. Returns an error with exit code preserved via errUtils.ExitCodeError.

func ExecuteApply

func ExecuteApply(ctx context.Context, opts *ExecuteOptions) error

ExecuteApply runs terraform apply with optional confirmation. If -auto-approve is not present and not using --from-plan, it runs: (1) terraform plan -json -out=<temp> (with TUI) (2) Display dependency tree (3) Confirmation prompt (4) terraform apply -json <temp> (with TUI).

func ExecuteDestroy

func ExecuteDestroy(ctx context.Context, opts *ExecuteOptions) error

ExecuteDestroy runs terraform destroy with confirmation. It runs: (1) terraform plan -destroy -json -out=<temp> (with TUI) (2) Display dependency tree (3) Confirmation prompt (4) terraform apply -json <temp> (with TUI).

func ExecuteInit

func ExecuteInit(ctx context.Context, opts *ExecuteOptions) error

ExecuteInit runs terraform init with a spinner TUI that captures output. The output is shown in a viewport that clears when init completes.

func ExecutePlan

func ExecutePlan(ctx context.Context, opts *ExecuteOptions) error

ExecutePlan runs terraform plan with streaming UI and displays the dependency tree. It generates a temp planfile to parse for the tree, then cleans it up.

func RenderChangeSummaryBadges

func RenderChangeSummaryBadges(add, change, remove int) string

RenderChangeSummaryBadges renders a badge-style change summary. Shows "NO CHANGES" badge if all counts are zero. Format: " 1 ADD 2 CHANGE 1 DELETE" with colored badges (green/yellow/red backgrounds).

func ShouldUseStreamingUI

func ShouldUseStreamingUI(uiFlagSet, uiFlag, configEnabled bool, subCommand string) bool

ShouldUseStreamingUI determines if streaming UI should be used. This checks the flag, config, TTY availability, and CI environment.

func UIRequestedButUnsupported

func UIRequestedButUnsupported(uiFlagSet, uiFlag, configEnabled bool, subCommand string) bool

UIRequestedButUnsupported reports whether the user explicitly opted in to the streaming UI (via --ui or atmos config) for a subcommand that doesn't support it (e.g. refresh), as opposed to streaming simply being unrequested, disabled by CI, or unavailable due to no TTY. Callers use this to warn the user instead of silently falling back to the plain execution path with no explanation.

func WouldAttemptStreamingUI

func WouldAttemptStreamingUI(uiFlagSet, uiFlag, configEnabled bool) bool

WouldAttemptStreamingUI reports whether the streaming UI would actually be launched for this invocation, independent of which specific subcommand/phase is running: the user (or atmos config) opted in, and the environment can support it (a real TTY, not CI). Callers that need to reject a combination before dispatch (e.g. --ui with concurrent multi-component execution, which would race multiple full-screen TUI sessions for the same terminal) use this instead of ShouldUseStreamingUI, since the exact phase/gate isn't known yet at that point.

Types

type ApplyCompleteMessage

type ApplyCompleteMessage struct {
	BaseMessage
	Hook ApplyHook `json:"hook"`
}

ApplyCompleteMessage represents successful completion of a resource apply.

type ApplyErroredMessage

type ApplyErroredMessage struct {
	BaseMessage
	Hook ApplyHook `json:"hook"`
}

ApplyErroredMessage represents a failed resource apply.

type ApplyHook

type ApplyHook struct {
	Resource    ResourceAddr `json:"resource"`
	Action      string       `json:"action"`
	IDKey       string       `json:"id_key,omitempty"`
	IDValue     string       `json:"id_value,omitempty"`
	ElapsedSecs int          `json:"elapsed_secs,omitempty"`
}

ApplyHook contains the hook details for apply operations.

type ApplyProgressMessage

type ApplyProgressMessage struct {
	BaseMessage
	Hook ApplyHook `json:"hook"`
}

ApplyProgressMessage represents progress during apply.

type ApplyStartMessage

type ApplyStartMessage struct {
	BaseMessage
	Hook ApplyHook `json:"hook"`
}

ApplyStartMessage represents the start of a resource apply operation.

type AttributeChange

type AttributeChange struct {
	Key               string      // Attribute name.
	Before            interface{} // Value before change (nil for create).
	After             interface{} // Value after change (nil for delete).
	Unknown           bool        // True if value is "(known after apply)".
	Sensitive         bool        // True if value is sensitive.
	ForcesReplacement bool        // True if this attribute forces resource replacement.
}

AttributeChange represents a single attribute change.

type BaseMessage

type BaseMessage struct {
	Level     string      `json:"@level"`
	Message   string      `json:"@message"`
	Module    string      `json:"@module"`
	Timestamp string      `json:"@timestamp"`
	Type      MessageType `json:"type"`
}

BaseMessage contains fields common to all Terraform JSON messages.

type ChangeSummaryMessage

type ChangeSummaryMessage struct {
	BaseMessage
	Changes Changes `json:"changes"`
}

ChangeSummaryMessage represents the summary of changes.

type Changes

type Changes struct {
	Add       int    `json:"add"`
	Change    int    `json:"change"`
	Remove    int    `json:"remove"`
	Import    int    `json:"import,omitempty"`
	Operation string `json:"operation"` // plan, apply.
}

Changes contains the change counts for a summary.

type Clock

type Clock interface {
	Now() time.Time
	Since(t time.Time) time.Duration
}

Clock provides time-related operations for testability.

type DependencyTree

type DependencyTree struct {
	Root *TreeNode

	Stack     string // Atmos stack name (e.g., "plat-ue2-dev").
	Component string // Atmos component name (e.g., "vpc").
	// contains filtered or unexported fields
}

DependencyTree represents the resource hierarchy.

func BuildDependencyTree

func BuildDependencyTree(ctx context.Context, opts *TreeBuildOptions) (*DependencyTree, error)

BuildDependencyTree parses a planfile and builds the dependency tree.

func (*DependencyTree) GetChangeSummary

func (t *DependencyTree) GetChangeSummary() (add, change, remove int)

GetChangeSummary returns a summary of changes from the tree.

func (*DependencyTree) RenderTree

func (t *DependencyTree) RenderTree() string

RenderTree renders the tree as a string with box-drawing characters. Uses a two-column layout: action symbol (fixed width) | tree structure.

func (*DependencyTree) RenderTreeWithConfig

func (t *DependencyTree) RenderTreeWithConfig(config *RenderConfig) string

RenderTreeWithConfig renders the tree with custom rendering configuration.

type Diagnostic

type Diagnostic struct {
	Severity string           `json:"severity"` // error, warning.
	Summary  string           `json:"summary"`
	Detail   string           `json:"detail,omitempty"`
	Address  string           `json:"address,omitempty"`
	Range    *DiagnosticRange `json:"range,omitempty"`
}

Diagnostic contains the diagnostic details.

type DiagnosticLocation

type DiagnosticLocation struct {
	Line   int `json:"line"`
	Column int `json:"column"`
	Byte   int `json:"byte"`
}

DiagnosticLocation represents a source code location.

type DiagnosticMessage

type DiagnosticMessage struct {
	BaseMessage
	Diagnostic Diagnostic `json:"diagnostic"`
}

DiagnosticMessage represents warnings and errors.

type DiagnosticRange

type DiagnosticRange struct {
	Filename string             `json:"filename"`
	Start    DiagnosticLocation `json:"start"`
	End      DiagnosticLocation `json:"end"`
}

DiagnosticRange represents a source code range.

type ExecuteOptions

type ExecuteOptions struct {
	Command    string   // terraform or opentofu binary.
	Args       []string // Command arguments (plan, apply, etc.).
	WorkingDir string   // Component directory.
	Env        []string // Environment variables.
	Component  string   // Component name for display.
	Stack      string   // Stack name for display.
	SubCommand string   // "plan", "apply", "init", "refresh", "workspace".
	Workspace  string   // Workspace name (for workspace select/new).
	DryRun     bool     // If true, don't execute.
	// RenderConfig controls dependency-tree rendering (compact spacing, attribute bar,
	// max lines). Nil uses RenderTreeWithConfig's built-in defaults.
	RenderConfig *RenderConfig
}

ExecuteOptions configures streaming execution.

type InitModel

type InitModel struct {
	// contains filtered or unexported fields
}

InitModel is the bubbletea model for streaming terraform init/workspace output.

func NewInitModel

func NewInitModel(component, stack, subCommand string, reader io.Reader, opts ...InitModelOption) *InitModel

NewInitModel creates a new init/workspace streaming model. Use WithWorkspace to set the workspace name for workspace select/new commands.

func (InitModel) Cancelled

func (m InitModel) Cancelled() bool

Cancelled reports whether the user explicitly quit (Ctrl-C/q) rather than the underlying terraform command completing on its own. Value receiver: bubbletea returns models by value, so this must be callable on the InitModel value stored in the tea.Model interface.

func (*InitModel) GetError

func (m *InitModel) GetError() error

GetError returns any error that occurred.

func (*InitModel) GetExitCode

func (m *InitModel) GetExitCode() int

GetExitCode returns the exit code.

func (InitModel) Init

func (m InitModel) Init() tea.Cmd

Init initializes the model.

func (InitModel) Update

func (m InitModel) Update(msg tea.Msg) (tea.Model, tea.Cmd)

Update handles messages.

func (InitModel) View

func (m InitModel) View() string

View renders the model.

type InitModelOption

type InitModelOption func(*InitModel)

InitModelOption configures an InitModel.

func WithInitClock

func WithInitClock(c Clock) InitModelOption

WithInitClock sets the clock implementation for time operations.

func WithWorkspace

func WithWorkspace(workspace string) InitModelOption

WithWorkspace sets the workspace name (used for workspace select/new display).

type InitOutputMessage

type InitOutputMessage struct {
	BaseMessage
	InitOutput struct {
		// Init has various message subtypes.
		MessageType string `json:"message_type,omitempty"`
	} `json:"init_output,omitempty"`
}

InitOutputMessage represents init command output.

type LogMessage

type LogMessage struct {
	BaseMessage
}

LogMessage represents unstructured log output.

type MessageType

type MessageType string

MessageType represents the type of Terraform JSON message.

const (
	MessageTypeVersion         MessageType = "version"
	MessageTypePlannedChange   MessageType = "planned_change"
	MessageTypeChangeSummary   MessageType = "change_summary"
	MessageTypeApplyStart      MessageType = "apply_start"
	MessageTypeApplyProgress   MessageType = "apply_progress"
	MessageTypeApplyComplete   MessageType = "apply_complete"
	MessageTypeApplyErrored    MessageType = "apply_errored"
	MessageTypeRefreshStart    MessageType = "refresh_start"
	MessageTypeRefreshComplete MessageType = "refresh_complete"
	MessageTypeDiagnostic      MessageType = "diagnostic"
	MessageTypeOutputs         MessageType = "outputs"
	MessageTypeResourceDrift   MessageType = "resource_drift"
	MessageTypeInitOutput      MessageType = "init_output"
	MessageTypeLog             MessageType = "log"
)

Message types from Terraform's machine-readable UI.

type Model

type Model struct {
	// contains filtered or unexported fields
}

Model is the bubbletea model for streaming terraform output.

func NewModel

func NewModel(component, stack, command string, reader io.Reader, opts ...ModelOption) *Model

NewModel creates a new streaming model.

func (Model) Cancelled

func (m Model) Cancelled() bool

Cancelled reports whether the user explicitly quit (Ctrl-C/q) rather than the underlying terraform command completing on its own. Value receiver: bubbletea returns models by value, so this must be callable on the Model value stored in the tea.Model interface.

func (*Model) GetError

func (m *Model) GetError() error

GetError returns any error that occurred.

func (*Model) GetExitCode

func (m *Model) GetExitCode() int

GetExitCode returns the exit code after completion.

func (*Model) GetTracker

func (m *Model) GetTracker() *ResourceTracker

GetTracker returns the resource tracker.

func (Model) Init

func (m Model) Init() tea.Cmd

Init initializes the model.

func (*Model) LogDiagnostics

func (m *Model) LogDiagnostics()

LogDiagnostics sends all diagnostics to the Atmos logger at appropriate severity levels. Call this after the TUI completes to display warnings after the completion message.

func (Model) Update

func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd)

Update handles messages.

func (Model) View

func (m Model) View() string

View renders the UI.

type ModelOption

type ModelOption func(*Model)

ModelOption configures a Model.

func WithClock

func WithClock(c Clock) ModelOption

WithClock sets the clock implementation for time operations.

type OutputValue

type OutputValue struct {
	Sensitive bool   `json:"sensitive"`
	Type      any    `json:"type"`
	Value     any    `json:"value"`
	Action    string `json:"action,omitempty"`
}

OutputValue represents a single output value.

type OutputsMessage

type OutputsMessage struct {
	BaseMessage
	Outputs map[string]OutputValue `json:"outputs"`
}

OutputsMessage represents output values after successful operations.

type ParseResult

type ParseResult struct {
	Message any
	Raw     []byte
	Err     error
}

ParseResult represents a parsed message or error.

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

Parser reads and parses Terraform JSON streaming output.

func NewParser

func NewParser(r io.Reader) *Parser

NewParser creates a new parser from an io.Reader.

func (*Parser) Next

func (p *Parser) Next() (*ParseResult, error)

Next reads and parses the next JSON message. Returns io.EOF when there are no more messages.

type Phase

type Phase int

Phase represents the terraform operation phase.

const (
	PhaseInitializing Phase = iota
	PhaseRefreshing
	PhasePlanning
	PhaseApplying
	PhaseComplete
	PhaseError
)

Terraform operation phases.

func (Phase) String

func (p Phase) String() string

String returns the string representation of the phase.

type PlannedChange

type PlannedChange struct {
	Resource       ResourceAddr `json:"resource"`
	Action         string       `json:"action"`
	PreviousAction string       `json:"previous_action,omitempty"`
	Reason         string       `json:"reason,omitempty"`
}

PlannedChange contains the change details for a planned resource.

type PlannedChangeMessage

type PlannedChangeMessage struct {
	BaseMessage
	Change PlannedChange `json:"change"`
}

PlannedChangeMessage represents a planned resource change.

type RefreshCompleteMessage

type RefreshCompleteMessage struct {
	BaseMessage
	Hook RefreshHook `json:"hook"`
}

RefreshCompleteMessage represents successful completion of a resource refresh.

type RefreshHook

type RefreshHook struct {
	Resource ResourceAddr `json:"resource"`
	IDKey    string       `json:"id_key,omitempty"`
	IDValue  string       `json:"id_value,omitempty"`
}

RefreshHook contains the hook details for refresh operations.

type RefreshStartMessage

type RefreshStartMessage struct {
	BaseMessage
	Hook RefreshHook `json:"hook"`
}

RefreshStartMessage represents the start of a resource refresh.

type RenderConfig

type RenderConfig struct {
	// ShowAttributeBar shows a thick ┃ bar alongside attributes.
	ShowAttributeBar bool
	// Compact removes blank lines between resources.
	Compact bool
	// MaxLines controls collapsing of large JSON values (0 = show all).
	MaxLines int

	// CreateStyle, UpdateStyle, DeleteStyle, DimStyle, TreeStyle, and BarStyle are the
	// styles used when rendering the tree and attribute changes. Populated with defaults
	// by resolveRenderConfig when not explicitly set.
	CreateStyle lipgloss.Style
	UpdateStyle lipgloss.Style
	DeleteStyle lipgloss.Style
	DimStyle    lipgloss.Style
	TreeStyle   lipgloss.Style
	BarStyle    lipgloss.Style
}

RenderConfig holds configuration for tree rendering, including display options and the styles used to render create/update/delete attribute changes.

func BuildRenderConfig

func BuildRenderConfig(uiConfig schema.TerraformUI) *RenderConfig

BuildRenderConfig translates atmos.yaml's components.terraform.ui.{compact, show_attribute_bar,max_lines} into a RenderConfig, applying the documented defaults (compact=true, show_attribute_bar=false) when left unset.

type ResourceAddr

type ResourceAddr struct {
	Addr            string `json:"addr"`
	Module          string `json:"module"`
	Resource        string `json:"resource"`
	ResourceType    string `json:"resource_type"`
	ResourceName    string `json:"resource_name"`
	ResourceKey     string `json:"resource_key,omitempty"`
	ImpliedProvider string `json:"implied_provider"`
}

ResourceAddr contains common resource identification fields.

type ResourceOperation

type ResourceOperation struct {
	Address      string        // e.g., "aws_instance.example".
	Module       string        // Module path if applicable.
	ResourceType string        // e.g., "aws_instance".
	ResourceName string        // e.g., "example".
	Action       string        // create, update, delete, read, no-op.
	State        ResourceState // Current state.
	StartTime    time.Time     // When operation started.
	EndTime      time.Time     // When operation completed.
	ElapsedSecs  int           // Elapsed time from terraform.
	Error        string        // Error message if failed.
	IDKey        string        // For existing resources.
	IDValue      string        // For existing resources.
	LastUpdate   time.Time     // For progress updates.
}

ResourceOperation tracks the lifecycle of a single resource.

type ResourceState

type ResourceState int

ResourceState represents the current state of a resource operation.

const (
	ResourceStatePending ResourceState = iota
	ResourceStateRefreshing
	ResourceStateInProgress
	ResourceStateComplete
	ResourceStateError
)

Resource operation states.

func (ResourceState) String

func (s ResourceState) String() string

String returns the string representation of the resource state.

type ResourceTracker

type ResourceTracker struct {
	// contains filtered or unexported fields
}

ResourceTracker manages all resource operations.

func NewResourceTracker

func NewResourceTracker() *ResourceTracker

NewResourceTracker creates a new resource tracker.

func (*ResourceTracker) GetActiveCount

func (rt *ResourceTracker) GetActiveCount() int

GetActiveCount returns the number of resources currently in progress.

func (*ResourceTracker) GetChangeSummary

func (rt *ResourceTracker) GetChangeSummary() *ChangeSummaryMessage

GetChangeSummary returns the change summary if available.

func (*ResourceTracker) GetCompletedCount

func (rt *ResourceTracker) GetCompletedCount() int

GetCompletedCount returns the number of completed resources.

func (*ResourceTracker) GetCurrentActivity

func (rt *ResourceTracker) GetCurrentActivity() *ResourceOperation

GetCurrentActivity returns the first in-progress or refreshing resource, if any. Returns nil if no resource is currently active.

func (*ResourceTracker) GetDiagnostics

func (rt *ResourceTracker) GetDiagnostics() []*DiagnosticMessage

GetDiagnostics returns all diagnostic messages.

func (*ResourceTracker) GetErrorCount

func (rt *ResourceTracker) GetErrorCount() int

GetErrorCount returns the number of failures: failed resources plus error-severity diagnostics with no resource address (e.g. a plan-file write failure). Must stay in sync with HasErrors' definition of "has an error" -- otherwise a diagnostic-only failure (no resource individually errored) trips the "failed" banner while this reports 0, producing a confusing "failed: 0 error(s)" summary.

func (*ResourceTracker) GetOutputs

func (rt *ResourceTracker) GetOutputs() *OutputsMessage

GetOutputs returns the captured output values.

func (*ResourceTracker) GetPhase

func (rt *ResourceTracker) GetPhase() Phase

GetPhase returns the current operation phase.

func (*ResourceTracker) GetResources

func (rt *ResourceTracker) GetResources() []*ResourceOperation

GetResources returns a snapshot of all resources in order.

func (*ResourceTracker) GetTotalCount

func (rt *ResourceTracker) GetTotalCount() int

GetTotalCount returns the total number of resources.

func (*ResourceTracker) HandleMessage

func (rt *ResourceTracker) HandleMessage(msg any)

HandleMessage processes a Terraform JSON message and updates state.

func (*ResourceTracker) HasErrors

func (rt *ResourceTracker) HasErrors() bool

HasErrors returns true if any resources failed.

type TreeBuildOptions

type TreeBuildOptions struct {
	PlanfilePath  string
	TerraformPath string
	WorkingDir    string
	Stack         string
	Component     string
}

TreeBuildOptions groups the parameters needed to build a dependency tree from a planfile.

type TreeNode

type TreeNode struct {
	Address  string // Full Terraform address (e.g., "aws_vpc.main").
	Action   string // create, update, delete, read, no-op.
	Children []*TreeNode
	Parent   *TreeNode
	IsModule bool               // True if this is a module node.
	Changes  []*AttributeChange // Attribute-level changes.
}

TreeNode represents a resource in the dependency tree.

type VersionMessage

type VersionMessage struct {
	BaseMessage
	Terraform string `json:"terraform"`
	UI        string `json:"ui"`
}

VersionMessage represents the initial version message.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL