New plans.Quality type for display-relevant facts about a plan

This commit replaces the existing jsonformat.PlanRendererOpt type with a new
type with identical semantics, located in the plans package.

We needed to be able to exchange the facts represented by
`jsonformat.PlanRendererOpt` across some package boundaries, but the jsonformat
package is implicated in too many dependency chains to be safe for that purpose!
So, we had to make a new one. The plans package seems safe to import from all
the places that must emit or accept this info, and already contains plans.Mode,
which is effectively a sibling of this type.
This commit is contained in:
Nick Fagerlund 2023-06-30 12:24:57 -07:00 committed by Sebastian Rivera
parent da963a13b9
commit 0df3c143bb
6 changed files with 56 additions and 17 deletions

View File

@ -19,14 +19,9 @@ import (
"github.com/hashicorp/terraform/internal/plans"
)
type PlanRendererOpt int
const (
detectedDrift string = "drift"
proposedChange string = "change"
Errored PlanRendererOpt = iota
CanNotApply
)
type Plan struct {
@ -51,8 +46,8 @@ func (plan Plan) getSchema(change jsonplan.ResourceChange) *jsonprovider.Schema
}
}
func (plan Plan) renderHuman(renderer Renderer, mode plans.Mode, opts ...PlanRendererOpt) {
checkOpts := func(target PlanRendererOpt) bool {
func (plan Plan) renderHuman(renderer Renderer, mode plans.Mode, opts ...plans.Quality) {
checkOpts := func(target plans.Quality) bool {
for _, opt := range opts {
if opt == target {
return true
@ -102,7 +97,7 @@ func (plan Plan) renderHuman(renderer Renderer, mode plans.Mode, opts ...PlanRen
// the plan is "applyable" and, if so, whether it had refresh changes
// that we already would've presented above.
if checkOpts(Errored) {
if checkOpts(plans.Errored) {
if haveRefreshChanges {
renderer.Streams.Print(format.HorizontalRule(renderer.Colorize, renderer.Streams.Stdout.Columns()))
renderer.Streams.Println()
@ -143,7 +138,7 @@ func (plan Plan) renderHuman(renderer Renderer, mode plans.Mode, opts ...PlanRen
)
if haveRefreshChanges {
if !checkOpts(CanNotApply) {
if !checkOpts(plans.NoChanges) {
// In this case, applying this plan will not change any
// remote objects but _will_ update the state to match what
// we detected during refresh, so we'll reassure the user
@ -210,7 +205,7 @@ func (plan Plan) renderHuman(renderer Renderer, mode plans.Mode, opts ...PlanRen
}
if len(changes) > 0 {
if checkOpts(Errored) {
if checkOpts(plans.Errored) {
renderer.Streams.Printf("\nTerraform planned the following actions, but then encountered a problem:\n")
} else {
renderer.Streams.Printf("\nTerraform will perform the following actions:\n")

View File

@ -82,7 +82,7 @@ type Renderer struct {
RunningInAutomation bool
}
func (renderer Renderer) RenderHumanPlan(plan Plan, mode plans.Mode, opts ...PlanRendererOpt) {
func (renderer Renderer) RenderHumanPlan(plan Plan, mode plans.Mode, opts ...plans.Quality) {
if incompatibleVersions(jsonplan.FormatVersion, plan.PlanFormatVersion) || incompatibleVersions(jsonprovider.FormatVersion, plan.ProviderFormatVersion) {
renderer.Streams.Println(format.WordWrap(
renderer.Colorize.Color("\n[bold][red]Warning:[reset][bold] This plan was generated using a different version of Terraform, the diff presented here may be missing representations of recent features."),

View File

@ -115,12 +115,12 @@ func (v *OperationHuman) Plan(plan *plans.Plan, schemas *terraform.Schemas) {
}
// Side load some data that we can't extract from the JSON plan.
var opts []jsonformat.PlanRendererOpt
var opts []plans.Quality
if !plan.CanApply() {
opts = append(opts, jsonformat.CanNotApply)
opts = append(opts, plans.NoChanges)
}
if plan.Errored {
opts = append(opts, jsonformat.Errored)
opts = append(opts, plans.Errored)
}
renderer.RenderHumanPlan(jplan, plan.UIMode, opts...)

View File

@ -67,12 +67,12 @@ func (v *ShowHuman) Display(config *configs.Config, plan *plans.Plan, stateFile
RelevantAttributes: attrs,
}
var opts []jsonformat.PlanRendererOpt
var opts []plans.Quality
if !plan.CanApply() {
opts = append(opts, jsonformat.CanNotApply)
opts = append(opts, plans.NoChanges)
}
if plan.Errored {
opts = append(opts, jsonformat.Errored)
opts = append(opts, plans.Errored)
}
renderer.RenderHumanPlan(jplan, plan.UIMode, opts...)

20
internal/plans/quality.go Normal file
View File

@ -0,0 +1,20 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package plans
// Quality represents facts about the nature of a plan that might be relevant
// when rendering it, like whether it errored or contains no changes. A plan can
// have multiple qualities.
type Quality int
//go:generate go run golang.org/x/tools/cmd/stringer -type Quality
const (
// Errored plans did not successfully complete, and cannot be applied.
Errored Quality = iota
// NoChanges plans won't result in any actions on infrastructure, or any
// semantically meaningful updates to state. They can sometimes still affect
// the format of state if applied.
NoChanges
)

View File

@ -0,0 +1,24 @@
// Code generated by "stringer -type Quality"; DO NOT EDIT.
package plans
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[Errored-0]
_ = x[NoChanges-1]
}
const _Quality_name = "ErroredNoChanges"
var _Quality_index = [...]uint8{0, 7, 16}
func (i Quality) String() string {
if i < 0 || i >= Quality(len(_Quality_index)-1) {
return "Quality(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Quality_name[_Quality_index[i]:_Quality_index[i+1]]
}