Skip to content

Commit

Permalink
command/format: improve consistency of plan results
Browse files Browse the repository at this point in the history
Previously the rendered plan output was constructed directly from the
core plan and then annotated with counts derived from the count hook.
At various places we applied little adjustments to deal with the fact that
the user-facing diff model is not identical to the internal diff model,
including the special handling of data source reads and destroys. Since
this logic was just muddled into the rendering code, it behaved
inconsistently with the tally of adds, updates and deletes.

This change reworks the plan formatter so that it happens in two stages:
- First, we produce a specialized Plan object that is tailored for use
  in the UI. This applies all the relevant logic to transform the
  physical model into the user model.
- Second, we do a straightforward visual rendering of the display-oriented
  plan object.

For the moment this is slightly overkill since there's only one rendering
path, but it does give us the benefit of letting the counts be derived
from the same data as the full detailed diff, ensuring that they'll stay
consistent.

Later we may choose to have other UIs for plans, such as a
machine-readable output intended to drive a web UI. In that case, we'd
want the web UI to consume a serialization of the _display-oriented_ plan
so that it doesn't need to re-implement all of these UI special cases.

This introduces to core a new diff action type for "refresh". Currently
this is used _only_ in the UI layer, to represent data source reads.
Later it would be good to use this type for the core diff as well, to
improve consistency, but that is left for another day to keep this change
focused on the UI.
  • Loading branch information
apparentlymart committed Aug 23, 2017
1 parent f040176 commit 99a2697
Show file tree
Hide file tree
Showing 6 changed files with 296 additions and 256 deletions.
28 changes: 6 additions & 22 deletions backend/local/backend_apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,28 +96,16 @@ func (b *Local) opApply(
return
}

trivialPlan := plan.Diff == nil || plan.Diff.Empty()
dispPlan := format.NewPlan(plan)
trivialPlan := dispPlan.Empty()
hasUI := op.UIOut != nil && op.UIIn != nil
if hasUI && ((op.Destroy && !op.DestroyForce) ||
(!op.Destroy && !op.AutoApprove && !trivialPlan)) {
mustConfirm := hasUI && ((op.Destroy && !op.DestroyForce) || (!op.Destroy && !op.AutoApprove && !trivialPlan))
if mustConfirm {
var desc, query string
if op.Destroy {
// Default destroy message
desc = "Terraform will delete all your managed infrastructure, as shown above.\n" +
desc = "Terraform will destroy all your managed infrastructure, as shown above.\n" +
"There is no undo. Only 'yes' will be accepted to confirm."

// If targets are specified, list those to user
if op.Targets != nil {
var descBuffer bytes.Buffer
descBuffer.WriteString("Terraform will delete the following infrastructure:\n")
for _, target := range op.Targets {
descBuffer.WriteString("\t")
descBuffer.WriteString(target)
descBuffer.WriteString("\n")
}
descBuffer.WriteString("There is no undo. Only 'yes' will be accepted to confirm")
desc = descBuffer.String()
}
query = "Do you really want to destroy?"
} else {
desc = "Terraform will apply the changes described above.\n" +
Expand All @@ -132,11 +120,7 @@ func (b *Local) opApply(
} else {
op.UIOut.Output("\n" + strings.TrimSpace(approvePlanHeader) + "\n")
}
op.UIOut.Output(format.Plan(&format.PlanOpts{
Plan: plan,
Color: b.Colorize(),
ModuleDepth: -1,
}))
op.UIOut.Output(dispPlan.Format(b.Colorize()))
}

v, err := op.UIIn.Input(&terraform.InputOpts{
Expand Down
15 changes: 6 additions & 9 deletions backend/local/backend_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ func (b *Local) opPlan(

// Perform some output tasks if we have a CLI to output to.
if b.CLI != nil {
if plan.Diff.Empty() {
dispPlan := format.NewPlan(plan)
if dispPlan.Empty() {
b.CLI.Output(b.Colorize().Color(strings.TrimSpace(planNoChanges)))
return
}
Expand All @@ -146,18 +147,14 @@ func (b *Local) opPlan(
path))
}

b.CLI.Output(format.Plan(&format.PlanOpts{
Plan: plan,
Color: b.Colorize(),
ModuleDepth: -1,
}))
b.CLI.Output(dispPlan.Format(b.Colorize()))

stats := dispPlan.Stats()
b.CLI.Output(b.Colorize().Color(fmt.Sprintf(
"[reset][bold]Plan:[reset] "+
"%d to add, %d to change, %d to destroy.",
countHook.ToAdd+countHook.ToRemoveAndAdd,
countHook.ToChange,
countHook.ToRemove+countHook.ToRemoveAndAdd)))
stats.ToAdd, stats.ToChange, stats.ToDestroy,
)))
}
}

Expand Down
Loading

0 comments on commit 99a2697

Please sign in to comment.