Merge pull request #27760 from hashicorp/alisdair/command-views-ui-hook
cli: Migrate Terraform UI hook to command views
This commit is contained in:
commit
1ae3d30383
|
@ -183,6 +183,10 @@ type Operation struct {
|
|||
// configuration from ConfigDir.
|
||||
ConfigLoader *configload.Loader
|
||||
|
||||
// Hooks can be used to perform actions triggered by various events during
|
||||
// the operation's lifecycle.
|
||||
Hooks []terraform.Hook
|
||||
|
||||
// Plan is a plan that was passed as an argument. This is valid for
|
||||
// plan and apply arguments but may not work for all backends.
|
||||
PlanFile *planfile.Reader
|
||||
|
|
|
@ -40,12 +40,7 @@ func (b *Local) opApply(
|
|||
}
|
||||
|
||||
stateHook := new(StateHook)
|
||||
if b.ContextOpts == nil {
|
||||
b.ContextOpts = new(terraform.ContextOpts)
|
||||
}
|
||||
old := b.ContextOpts.Hooks
|
||||
defer func() { b.ContextOpts.Hooks = old }()
|
||||
b.ContextOpts.Hooks = append(b.ContextOpts.Hooks, stateHook)
|
||||
op.Hooks = append(op.Hooks, stateHook)
|
||||
|
||||
// Get our context
|
||||
tfCtx, _, opState, contextDiags := b.context(op)
|
||||
|
|
|
@ -77,6 +77,7 @@ func (b *Local) context(op *backend.Operation) (*terraform.Context, *configload.
|
|||
opts.Destroy = op.Destroy
|
||||
opts.Targets = op.Targets
|
||||
opts.UIInput = op.UIIn
|
||||
opts.Hooks = op.Hooks
|
||||
|
||||
opts.SkipRefresh = op.Type != backend.OperationTypeRefresh && !op.PlanRefresh
|
||||
if opts.SkipRefresh {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/plans/planfile"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
||||
|
@ -110,7 +111,6 @@ func (c *ApplyCommand) Run(args []string) int {
|
|||
|
||||
// Set up our count hook that keeps track of resource changes
|
||||
countHook := new(CountHook)
|
||||
c.ExtraHooks = append(c.ExtraHooks, countHook)
|
||||
|
||||
// Load the backend
|
||||
var be backend.Enhanced
|
||||
|
@ -171,6 +171,7 @@ func (c *ApplyCommand) Run(args []string) int {
|
|||
opReq.AutoApprove = autoApprove
|
||||
opReq.ConfigDir = configPath
|
||||
opReq.Destroy = c.Destroy
|
||||
opReq.Hooks = []terraform.Hook{countHook, c.uiHook()}
|
||||
opReq.PlanFile = planFile
|
||||
opReq.PlanRefresh = refresh
|
||||
opReq.ShowDiagnostics = c.showDiagnostics
|
||||
|
|
|
@ -941,10 +941,12 @@ func TestApply_planNoModuleFiles(t *testing.T) {
|
|||
p := applyFixtureProvider()
|
||||
planPath := applyFixturePlanFile(t)
|
||||
|
||||
view, _ := testView(t)
|
||||
apply := &ApplyCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: new(cli.MockUi),
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
args := []string{
|
||||
|
|
|
@ -189,6 +189,7 @@ func (c *ImportCommand) Run(args []string) int {
|
|||
c.showDiagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
opReq.Hooks = []terraform.Hook{c.uiHook()}
|
||||
{
|
||||
var moreDiags tfdiags.Diagnostics
|
||||
opReq.Variables, moreDiags = c.collectVariableValues()
|
||||
|
|
|
@ -24,10 +24,12 @@ func TestImport(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ImportCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -77,10 +79,12 @@ func TestImport_providerConfig(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ImportCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -170,9 +174,11 @@ func TestImport_remoteState(t *testing.T) {
|
|||
|
||||
// init our backend
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
@ -192,6 +198,7 @@ func TestImport_remoteState(t *testing.T) {
|
|||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -280,9 +287,11 @@ func TestImport_initializationErrorShouldUnlock(t *testing.T) {
|
|||
|
||||
// init our backend
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
@ -305,6 +314,7 @@ func TestImport_initializationErrorShouldUnlock(t *testing.T) {
|
|||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -339,10 +349,12 @@ func TestImport_providerConfigWithVar(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ImportCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -417,10 +429,12 @@ func TestImport_providerConfigWithDataSource(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ImportCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -480,10 +494,12 @@ func TestImport_providerConfigWithVarDefault(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ImportCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -557,10 +573,12 @@ func TestImport_providerConfigWithVarFile(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ImportCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -635,10 +653,12 @@ func TestImport_allowMissingResourceConfig(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ImportCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -690,10 +710,12 @@ func TestImport_emptyConfig(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ImportCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -720,10 +742,12 @@ func TestImport_missingResourceConfig(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ImportCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -750,10 +774,12 @@ func TestImport_missingModuleConfig(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ImportCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -801,9 +827,11 @@ func TestImportModuleVarFile(t *testing.T) {
|
|||
|
||||
// init to install the module
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
@ -820,6 +848,7 @@ func TestImportModuleVarFile(t *testing.T) {
|
|||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
args := []string{
|
||||
|
@ -873,9 +902,11 @@ func TestImportModuleInputVariableEvaluation(t *testing.T) {
|
|||
|
||||
// init to install the module
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
@ -892,6 +923,7 @@ func TestImportModuleInputVariableEvaluation(t *testing.T) {
|
|||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
args := []string{
|
||||
|
@ -912,10 +944,12 @@ func TestImport_dataResource(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ImportCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -942,10 +976,12 @@ func TestImport_invalidResourceAddr(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ImportCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -972,10 +1008,12 @@ func TestImport_targetIsModule(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ImportCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/backend/local"
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/format"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/command/webbrowser"
|
||||
|
@ -69,9 +70,6 @@ type Meta struct {
|
|||
GlobalPluginDirs []string // Additional paths to search for plugins
|
||||
Ui cli.Ui // Ui for output
|
||||
|
||||
// ExtraHooks are extra hooks to add to the context.
|
||||
ExtraHooks []terraform.Hook
|
||||
|
||||
// Services provides access to remote endpoint information for
|
||||
// "terraform-native' services running at a specific user-facing hostname.
|
||||
Services *disco.Disco
|
||||
|
@ -434,8 +432,6 @@ func (m *Meta) contextOpts() (*terraform.ContextOpts, error) {
|
|||
}
|
||||
|
||||
var opts terraform.ContextOpts
|
||||
opts.Hooks = []terraform.Hook{m.uiHook()}
|
||||
opts.Hooks = append(opts.Hooks, m.ExtraHooks...)
|
||||
|
||||
opts.Targets = m.targets
|
||||
opts.UIInput = m.UIInput()
|
||||
|
@ -621,15 +617,21 @@ func (m *Meta) process(args []string) []string {
|
|||
},
|
||||
}
|
||||
|
||||
// Reconfigure the view. This is necessary for commands which use both
|
||||
// views.View and cli.Ui during the migration phase.
|
||||
if m.View != nil {
|
||||
m.View.Configure(&arguments.View{
|
||||
CompactWarnings: m.compactWarnings,
|
||||
NoColor: !m.Color,
|
||||
})
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
// uiHook returns the UiHook to use with the context.
|
||||
func (m *Meta) uiHook() *UiHook {
|
||||
return &UiHook{
|
||||
Colorize: m.Colorize(),
|
||||
Ui: m.Ui,
|
||||
}
|
||||
func (m *Meta) uiHook() *views.UiHook {
|
||||
return views.NewUiHook(m.View)
|
||||
}
|
||||
|
||||
// confirm asks a yes/no confirmation.
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/configs"
|
||||
"github.com/hashicorp/terraform/plans"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
||||
|
@ -82,6 +83,7 @@ func (c *PlanCommand) Run(args []string) int {
|
|||
opReq := c.Operation(b)
|
||||
opReq.ConfigDir = configPath
|
||||
opReq.Destroy = destroy
|
||||
opReq.Hooks = []terraform.Hook{c.uiHook()}
|
||||
opReq.PlanOutPath = outPath
|
||||
opReq.PlanRefresh = refresh
|
||||
opReq.ShowDiagnostics = c.showDiagnostics
|
||||
|
|
|
@ -32,10 +32,12 @@ func TestPlan(t *testing.T) {
|
|||
|
||||
p := planFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -59,10 +61,12 @@ func TestPlan_lockedState(t *testing.T) {
|
|||
|
||||
p := planFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -85,10 +89,12 @@ func TestPlan_plan(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -126,10 +132,12 @@ func TestPlan_destroy(t *testing.T) {
|
|||
|
||||
p := planFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -158,10 +166,12 @@ func TestPlan_noState(t *testing.T) {
|
|||
|
||||
p := planFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -193,10 +203,12 @@ func TestPlan_outPath(t *testing.T) {
|
|||
|
||||
p := planFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -246,10 +258,12 @@ func TestPlan_outPathNoChange(t *testing.T) {
|
|||
|
||||
p := planFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -324,10 +338,12 @@ func TestPlan_outBackend(t *testing.T) {
|
|||
}
|
||||
}
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -376,10 +392,12 @@ func TestPlan_refreshFalse(t *testing.T) {
|
|||
|
||||
p := planFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -407,10 +425,12 @@ func TestPlan_state(t *testing.T) {
|
|||
|
||||
p := planFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -450,10 +470,12 @@ func TestPlan_stateDefault(t *testing.T) {
|
|||
|
||||
p := planFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -505,10 +527,12 @@ func TestPlan_validate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -532,10 +556,12 @@ func TestPlan_vars(t *testing.T) {
|
|||
|
||||
p := planVarsFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -577,10 +603,12 @@ func TestPlan_varsUnset(t *testing.T) {
|
|||
|
||||
p := planVarsFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -640,10 +668,12 @@ func TestPlan_providerArgumentUnset(t *testing.T) {
|
|||
},
|
||||
}
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -667,10 +697,12 @@ func TestPlan_varFile(t *testing.T) {
|
|||
|
||||
p := planVarsFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -707,10 +739,12 @@ func TestPlan_varFileDefault(t *testing.T) {
|
|||
|
||||
p := planVarsFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -745,10 +779,12 @@ func TestPlan_varFileWithDecls(t *testing.T) {
|
|||
|
||||
p := planVarsFixtureProvider()
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -773,10 +809,12 @@ func TestPlan_detailedExitcode(t *testing.T) {
|
|||
|
||||
p := planFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -794,10 +832,12 @@ func TestPlan_detailedExitcode_emptyDiff(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -819,10 +859,12 @@ func TestPlan_shutdown(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ShutdownCh: shutdownCh,
|
||||
},
|
||||
}
|
||||
|
@ -884,10 +926,12 @@ func TestPlan_init_required(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
// Running plan without setting testingOverrides is similar to plan without init
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -927,10 +971,12 @@ func TestPlan_targeted(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -961,9 +1007,11 @@ func TestPlan_targetFlagsDiags(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &PlanCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
||||
|
@ -75,6 +76,7 @@ func (c *RefreshCommand) Run(args []string) int {
|
|||
// Build the operation
|
||||
opReq := c.Operation(b)
|
||||
opReq.ConfigDir = configPath
|
||||
opReq.Hooks = []terraform.Hook{c.uiHook()}
|
||||
opReq.ShowDiagnostics = c.showDiagnostics
|
||||
opReq.Type = backend.OperationTypeRefresh
|
||||
|
||||
|
|
|
@ -791,7 +791,7 @@ func TestRefresh_targeted(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
view, done := testView(t)
|
||||
c := &RefreshCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
|
@ -808,7 +808,7 @@ func TestRefresh_targeted(t *testing.T) {
|
|||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
got := ui.OutputWriter.String()
|
||||
got := done(t).Stdout()
|
||||
if want := "test_instance.foo: Refreshing"; !strings.Contains(got, want) {
|
||||
t.Fatalf("expected output to contain %q, got:\n%s", want, got)
|
||||
}
|
||||
|
|
|
@ -255,9 +255,11 @@ func TestShow_json_output(t *testing.T) {
|
|||
|
||||
p := showFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package command
|
||||
package views
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
@ -9,8 +9,6 @@ import (
|
|||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/mitchellh/colorstring"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
|
@ -24,17 +22,24 @@ import (
|
|||
const defaultPeriodicUiTimer = 10 * time.Second
|
||||
const maxIdLen = 80
|
||||
|
||||
func NewUiHook(view *View) *UiHook {
|
||||
return &UiHook{
|
||||
view: view,
|
||||
periodicUiTimer: defaultPeriodicUiTimer,
|
||||
resources: make(map[string]uiResourceState),
|
||||
}
|
||||
}
|
||||
|
||||
type UiHook struct {
|
||||
terraform.NilHook
|
||||
|
||||
Colorize *colorstring.Colorize
|
||||
Ui cli.Ui
|
||||
PeriodicUiTimer time.Duration
|
||||
view *View
|
||||
viewLock sync.Mutex
|
||||
|
||||
l sync.Mutex
|
||||
once sync.Once
|
||||
resources map[string]uiResourceState
|
||||
ui cli.Ui
|
||||
periodicUiTimer time.Duration
|
||||
|
||||
resources map[string]uiResourceState
|
||||
resourcesLock sync.Mutex
|
||||
}
|
||||
|
||||
var _ terraform.Hook = (*UiHook)(nil)
|
||||
|
@ -63,8 +68,6 @@ const (
|
|||
)
|
||||
|
||||
func (h *UiHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation, action plans.Action, priorState, plannedNewState cty.Value) (terraform.HookAction, error) {
|
||||
h.once.Do(h.init)
|
||||
|
||||
dispAddr := addr.String()
|
||||
if gen != states.CurrentGen {
|
||||
dispAddr = fmt.Sprintf("%s (%s)", dispAddr, gen)
|
||||
|
@ -89,7 +92,7 @@ func (h *UiHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation,
|
|||
default:
|
||||
// We don't expect any other actions in here, so anything else is a
|
||||
// bug in the caller but we'll ignore it in order to be robust.
|
||||
h.ui.Output(fmt.Sprintf("(Unknown action %s for %s)", action, dispAddr))
|
||||
h.println(fmt.Sprintf("(Unknown action %s for %s)", action, dispAddr))
|
||||
return terraform.HookActionContinue, nil
|
||||
}
|
||||
|
||||
|
@ -103,7 +106,7 @@ func (h *UiHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation,
|
|||
idValue = ""
|
||||
}
|
||||
|
||||
h.ui.Output(h.Colorize.Color(fmt.Sprintf(
|
||||
h.println(h.view.colorize.Color(fmt.Sprintf(
|
||||
"[reset][bold]%s: %s%s[reset]",
|
||||
dispAddr,
|
||||
operation,
|
||||
|
@ -121,9 +124,9 @@ func (h *UiHook) PreApply(addr addrs.AbsResourceInstance, gen states.Generation,
|
|||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
h.l.Lock()
|
||||
h.resourcesLock.Lock()
|
||||
h.resources[key] = uiState
|
||||
h.l.Unlock()
|
||||
h.resourcesLock.Unlock()
|
||||
|
||||
// Start goroutine that shows progress
|
||||
go h.stillApplying(uiState)
|
||||
|
@ -138,7 +141,7 @@ func (h *UiHook) stillApplying(state uiResourceState) {
|
|||
case <-state.DoneCh:
|
||||
return
|
||||
|
||||
case <-time.After(h.PeriodicUiTimer):
|
||||
case <-time.After(h.periodicUiTimer):
|
||||
// Timer up, show status
|
||||
}
|
||||
|
||||
|
@ -161,7 +164,7 @@ func (h *UiHook) stillApplying(state uiResourceState) {
|
|||
idSuffix = fmt.Sprintf("%s=%s, ", state.IDKey, truncateId(state.IDValue, maxIdLen))
|
||||
}
|
||||
|
||||
h.ui.Output(h.Colorize.Color(fmt.Sprintf(
|
||||
h.println(h.view.colorize.Color(fmt.Sprintf(
|
||||
"[reset][bold]%s: %s [%s%s elapsed][reset]",
|
||||
state.DispAddr,
|
||||
msg,
|
||||
|
@ -172,17 +175,16 @@ func (h *UiHook) stillApplying(state uiResourceState) {
|
|||
}
|
||||
|
||||
func (h *UiHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation, newState cty.Value, applyerr error) (terraform.HookAction, error) {
|
||||
|
||||
id := addr.String()
|
||||
|
||||
h.l.Lock()
|
||||
h.resourcesLock.Lock()
|
||||
state := h.resources[id]
|
||||
if state.DoneCh != nil {
|
||||
close(state.DoneCh)
|
||||
}
|
||||
|
||||
delete(h.resources, id)
|
||||
h.l.Unlock()
|
||||
h.resourcesLock.Unlock()
|
||||
|
||||
var stateIdSuffix string
|
||||
if k, v := format.ObjectValueID(newState); k != "" && v != "" {
|
||||
|
@ -208,21 +210,17 @@ func (h *UiHook) PostApply(addr addrs.AbsResourceInstance, gen states.Generation
|
|||
return terraform.HookActionContinue, nil
|
||||
}
|
||||
|
||||
colorized := h.Colorize.Color(fmt.Sprintf(
|
||||
colorized := h.view.colorize.Color(fmt.Sprintf(
|
||||
"[reset][bold]%s: %s after %s%s[reset]",
|
||||
addr, msg, time.Now().Round(time.Second).Sub(state.Start), stateIdSuffix))
|
||||
|
||||
h.ui.Output(colorized)
|
||||
h.println(colorized)
|
||||
|
||||
return terraform.HookActionContinue, nil
|
||||
}
|
||||
|
||||
func (h *UiHook) PreDiff(addr addrs.AbsResourceInstance, gen states.Generation, priorState, proposedNewState cty.Value) (terraform.HookAction, error) {
|
||||
return terraform.HookActionContinue, nil
|
||||
}
|
||||
|
||||
func (h *UiHook) PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeName string) (terraform.HookAction, error) {
|
||||
h.ui.Output(h.Colorize.Color(fmt.Sprintf(
|
||||
h.println(h.view.colorize.Color(fmt.Sprintf(
|
||||
"[reset][bold]%s: Provisioning with '%s'...[reset]",
|
||||
addr, typeName,
|
||||
)))
|
||||
|
@ -231,7 +229,7 @@ func (h *UiHook) PreProvisionInstanceStep(addr addrs.AbsResourceInstance, typeNa
|
|||
|
||||
func (h *UiHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string, msg string) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(h.Colorize.Color("[reset]"))
|
||||
buf.WriteString(h.view.colorize.Color("[reset]"))
|
||||
|
||||
prefix := fmt.Sprintf("%s (%s): ", addr, typeName)
|
||||
s := bufio.NewScanner(strings.NewReader(msg))
|
||||
|
@ -243,27 +241,23 @@ func (h *UiHook) ProvisionOutput(addr addrs.AbsResourceInstance, typeName string
|
|||
}
|
||||
}
|
||||
|
||||
h.ui.Output(strings.TrimSpace(buf.String()))
|
||||
h.println(strings.TrimSpace(buf.String()))
|
||||
}
|
||||
|
||||
func (h *UiHook) PreRefresh(addr addrs.AbsResourceInstance, gen states.Generation, priorState cty.Value) (terraform.HookAction, error) {
|
||||
h.once.Do(h.init)
|
||||
|
||||
var stateIdSuffix string
|
||||
if k, v := format.ObjectValueID(priorState); k != "" && v != "" {
|
||||
stateIdSuffix = fmt.Sprintf(" [%s=%s]", k, v)
|
||||
}
|
||||
|
||||
h.ui.Output(h.Colorize.Color(fmt.Sprintf(
|
||||
h.println(h.view.colorize.Color(fmt.Sprintf(
|
||||
"[reset][bold]%s: Refreshing state...%s",
|
||||
addr, stateIdSuffix)))
|
||||
return terraform.HookActionContinue, nil
|
||||
}
|
||||
|
||||
func (h *UiHook) PreImportState(addr addrs.AbsResourceInstance, importID string) (terraform.HookAction, error) {
|
||||
h.once.Do(h.init)
|
||||
|
||||
h.ui.Output(h.Colorize.Color(fmt.Sprintf(
|
||||
h.println(h.view.colorize.Color(fmt.Sprintf(
|
||||
"[reset][bold]%s: Importing from ID %q...",
|
||||
addr, importID,
|
||||
)))
|
||||
|
@ -271,12 +265,10 @@ func (h *UiHook) PreImportState(addr addrs.AbsResourceInstance, importID string)
|
|||
}
|
||||
|
||||
func (h *UiHook) PostImportState(addr addrs.AbsResourceInstance, imported []providers.ImportedResource) (terraform.HookAction, error) {
|
||||
h.once.Do(h.init)
|
||||
|
||||
h.ui.Output(h.Colorize.Color(fmt.Sprintf(
|
||||
h.println(h.view.colorize.Color(fmt.Sprintf(
|
||||
"[reset][bold][green]%s: Import prepared!", addr)))
|
||||
for _, s := range imported {
|
||||
h.ui.Output(h.Colorize.Color(fmt.Sprintf(
|
||||
h.println(h.view.colorize.Color(fmt.Sprintf(
|
||||
"[reset][green] Prepared %s for import",
|
||||
s.TypeName,
|
||||
)))
|
||||
|
@ -285,19 +277,11 @@ func (h *UiHook) PostImportState(addr addrs.AbsResourceInstance, imported []prov
|
|||
return terraform.HookActionContinue, nil
|
||||
}
|
||||
|
||||
func (h *UiHook) init() {
|
||||
if h.Colorize == nil {
|
||||
panic("colorize not given")
|
||||
}
|
||||
if h.PeriodicUiTimer == 0 {
|
||||
h.PeriodicUiTimer = defaultPeriodicUiTimer
|
||||
}
|
||||
|
||||
h.resources = make(map[string]uiResourceState)
|
||||
|
||||
// Wrap the ui so that it is safe for concurrency regardless of the
|
||||
// underlying reader/writer that is in place.
|
||||
h.ui = &cli.ConcurrentUi{Ui: h.Ui}
|
||||
// Wrap calls to the view so that concurrent calls do not interleave println.
|
||||
func (h *UiHook) println(s string) {
|
||||
h.viewLock.Lock()
|
||||
defer h.viewLock.Unlock()
|
||||
h.view.streams.Println(s)
|
||||
}
|
||||
|
||||
// scanLines is basically copied from the Go standard library except
|
|
@ -1,4 +1,4 @@
|
|||
package command
|
||||
package views
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -6,28 +6,20 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/mitchellh/colorstring"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/internal/terminal"
|
||||
"github.com/hashicorp/terraform/plans"
|
||||
"github.com/hashicorp/terraform/states"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestUiHookPreApply_periodicTimer(t *testing.T) {
|
||||
ui := cli.NewMockUi()
|
||||
h := &UiHook{
|
||||
Colorize: &colorstring.Colorize{
|
||||
Colors: colorstring.DefaultColors,
|
||||
Disable: true,
|
||||
Reset: true,
|
||||
},
|
||||
Ui: ui,
|
||||
PeriodicUiTimer: 1 * time.Second,
|
||||
}
|
||||
h.init()
|
||||
streams, done := terminal.StreamsForTesting(t)
|
||||
view := NewView(streams)
|
||||
h := NewUiHook(view)
|
||||
h.periodicUiTimer = 1 * time.Second
|
||||
h.resources = map[string]uiResourceState{
|
||||
"data.aws_availability_zones.available": uiResourceState{
|
||||
Op: uiResourceDestroy,
|
||||
|
@ -75,29 +67,23 @@ data.aws_availability_zones.available: Still destroying... [id=2017-03-05 10:56:
|
|||
data.aws_availability_zones.available: Still destroying... [id=2017-03-05 10:56:59.298784526 +0000 UTC, 2s elapsed]
|
||||
data.aws_availability_zones.available: Still destroying... [id=2017-03-05 10:56:59.298784526 +0000 UTC, 3s elapsed]
|
||||
`
|
||||
output := ui.OutputWriter.String()
|
||||
result := done(t)
|
||||
output := result.Stdout()
|
||||
if output != expectedOutput {
|
||||
t.Fatalf("Output didn't match.\nExpected: %q\nGiven: %q", expectedOutput, output)
|
||||
}
|
||||
|
||||
expectedErrOutput := ""
|
||||
errOutput := ui.ErrorWriter.String()
|
||||
errOutput := result.Stderr()
|
||||
if errOutput != expectedErrOutput {
|
||||
t.Fatalf("Error output didn't match.\nExpected: %q\nGiven: %q", expectedErrOutput, errOutput)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUiHookPreApply_destroy(t *testing.T) {
|
||||
ui := cli.NewMockUi()
|
||||
h := &UiHook{
|
||||
Colorize: &colorstring.Colorize{
|
||||
Colors: colorstring.DefaultColors,
|
||||
Disable: true,
|
||||
Reset: true,
|
||||
},
|
||||
Ui: ui,
|
||||
}
|
||||
h.init()
|
||||
streams, done := terminal.StreamsForTesting(t)
|
||||
view := NewView(streams)
|
||||
h := NewUiHook(view)
|
||||
h.resources = map[string]uiResourceState{
|
||||
"data.aws_availability_zones.available": uiResourceState{
|
||||
Op: uiResourceDestroy,
|
||||
|
@ -138,30 +124,24 @@ func TestUiHookPreApply_destroy(t *testing.T) {
|
|||
close(uiState.DoneCh)
|
||||
<-uiState.done
|
||||
|
||||
result := done(t)
|
||||
expectedOutput := "data.aws_availability_zones.available: Destroying... [id=2017-03-05 10:56:59.298784526 +0000 UTC]\n"
|
||||
output := ui.OutputWriter.String()
|
||||
output := result.Stdout()
|
||||
if output != expectedOutput {
|
||||
t.Fatalf("Output didn't match.\nExpected: %q\nGiven: %q", expectedOutput, output)
|
||||
}
|
||||
|
||||
expectedErrOutput := ""
|
||||
errOutput := ui.ErrorWriter.String()
|
||||
errOutput := result.Stderr()
|
||||
if errOutput != expectedErrOutput {
|
||||
t.Fatalf("Error output didn't match.\nExpected: %q\nGiven: %q", expectedErrOutput, errOutput)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUiHookPostApply_emptyState(t *testing.T) {
|
||||
ui := cli.NewMockUi()
|
||||
h := &UiHook{
|
||||
Colorize: &colorstring.Colorize{
|
||||
Colors: colorstring.DefaultColors,
|
||||
Disable: true,
|
||||
Reset: true,
|
||||
},
|
||||
Ui: ui,
|
||||
}
|
||||
h.init()
|
||||
streams, done := terminal.StreamsForTesting(t)
|
||||
view := NewView(streams)
|
||||
h := NewUiHook(view)
|
||||
h.resources = map[string]uiResourceState{
|
||||
"data.google_compute_zones.available": uiResourceState{
|
||||
Op: uiResourceDestroy,
|
||||
|
@ -187,15 +167,16 @@ func TestUiHookPostApply_emptyState(t *testing.T) {
|
|||
if action != terraform.HookActionContinue {
|
||||
t.Fatalf("Expected hook to continue, given: %#v", action)
|
||||
}
|
||||
result := done(t)
|
||||
|
||||
expectedRegexp := "^data.google_compute_zones.available: Destruction complete after -?[a-z0-9µ.]+\n$"
|
||||
output := ui.OutputWriter.String()
|
||||
output := result.Stdout()
|
||||
if matched, _ := regexp.MatchString(expectedRegexp, output); !matched {
|
||||
t.Fatalf("Output didn't match regexp.\nExpected: %q\nGiven: %q", expectedRegexp, output)
|
||||
}
|
||||
|
||||
expectedErrOutput := ""
|
||||
errOutput := ui.ErrorWriter.String()
|
||||
errOutput := result.Stderr()
|
||||
if errOutput != expectedErrOutput {
|
||||
t.Fatalf("Error output didn't match.\nExpected: %q\nGiven: %q", expectedErrOutput, errOutput)
|
||||
}
|
Loading…
Reference in New Issue