Skip to content

Commit 294bbd8

Browse files
authored
Merge pull request #27681 from hashicorp/alisdair/remove-deprecated-destroy-force
cli: Remove deprecated destroy -force flag
2 parents 030632e + b2ba650 commit 294bbd8

File tree

6 files changed

+211
-16
lines changed

6 files changed

+211
-16
lines changed

backend/backend.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,11 @@ type Operation struct {
188188

189189
// The options below are more self-explanatory and affect the runtime
190190
// behavior of the operation.
191-
AutoApprove bool
192-
Destroy bool
193-
DestroyForce bool
194-
Parallelism int
195-
Targets []addrs.Targetable
196-
Variables map[string]UnparsedVariableValue
191+
AutoApprove bool
192+
Destroy bool
193+
Parallelism int
194+
Targets []addrs.Targetable
195+
Variables map[string]UnparsedVariableValue
197196

198197
// Some operations use root module variables only opportunistically or
199198
// don't need them at all. If this flag is set, the backend must treat

backend/local/backend_apply.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (b *Local) opApply(
7979

8080
trivialPlan := plan.Changes.Empty()
8181
hasUI := op.UIOut != nil && op.UIIn != nil
82-
mustConfirm := hasUI && ((op.Destroy && (!op.DestroyForce && !op.AutoApprove)) || (!op.Destroy && !op.AutoApprove && !trivialPlan))
82+
mustConfirm := hasUI && !op.AutoApprove && !trivialPlan
8383
if mustConfirm {
8484
var desc, query string
8585
if op.Destroy {

backend/remote/backend_apply.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,7 @@ func (b *Remote) opApply(stopCtx, cancelCtx context.Context, op *backend.Operati
170170
return r, diags.Err()
171171
}
172172

173-
mustConfirm := (op.UIIn != nil && op.UIOut != nil) &&
174-
((op.Destroy && (!op.DestroyForce && !op.AutoApprove)) || (!op.Destroy && !op.AutoApprove))
173+
mustConfirm := (op.UIIn != nil && op.UIOut != nil) && !op.AutoApprove
175174

176175
if !w.AutoApply {
177176
if mustConfirm {

command/apply.go

+1-7
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type ApplyCommand struct {
2424
}
2525

2626
func (c *ApplyCommand) Run(args []string) int {
27-
var destroyForce, refresh, autoApprove bool
27+
var refresh, autoApprove bool
2828
args = c.Meta.process(args)
2929
cmdName := "apply"
3030
if c.Destroy {
@@ -33,9 +33,6 @@ func (c *ApplyCommand) Run(args []string) int {
3333

3434
cmdFlags := c.Meta.extendedFlagSet(cmdName)
3535
cmdFlags.BoolVar(&autoApprove, "auto-approve", false, "skip interactive approval of plan before applying")
36-
if c.Destroy {
37-
cmdFlags.BoolVar(&destroyForce, "force", false, "deprecated: same as auto-approve")
38-
}
3936
cmdFlags.BoolVar(&refresh, "refresh", true, "refresh")
4037
cmdFlags.IntVar(&c.Meta.parallelism, "parallelism", DefaultParallelism, "parallelism")
4138
cmdFlags.StringVar(&c.Meta.statePath, "state", "", "path")
@@ -160,7 +157,6 @@ func (c *ApplyCommand) Run(args []string) int {
160157
opReq.AutoApprove = autoApprove
161158
opReq.ConfigDir = configPath
162159
opReq.Destroy = c.Destroy
163-
opReq.DestroyForce = destroyForce
164160
opReq.PlanFile = planFile
165161
opReq.PlanRefresh = refresh
166162
opReq.Type = backend.OperationTypeApply
@@ -319,8 +315,6 @@ Options:
319315
320316
-auto-approve Skip interactive approval before destroying.
321317
322-
-force Deprecated: same as auto-approve.
323-
324318
-lock=true Lock the state file when locking is supported.
325319
326320
-lock-timeout=0s Duration to retry a state lock.

command/apply_destroy_test.go

+118
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package command
22

33
import (
4+
"bytes"
45
"os"
56
"strings"
67
"testing"
@@ -114,6 +115,123 @@ func TestApply_destroy(t *testing.T) {
114115
}
115116
}
116117

118+
func TestApply_destroyApproveNo(t *testing.T) {
119+
// Create a temporary working directory that is empty
120+
td := tempDir(t)
121+
testCopyDir(t, testFixturePath("apply"), td)
122+
defer os.RemoveAll(td)
123+
defer testChdir(t, td)()
124+
125+
// Create some existing state
126+
originalState := states.BuildState(func(s *states.SyncState) {
127+
s.SetResourceInstanceCurrent(
128+
addrs.Resource{
129+
Mode: addrs.ManagedResourceMode,
130+
Type: "test_instance",
131+
Name: "foo",
132+
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
133+
&states.ResourceInstanceObjectSrc{
134+
AttrsJSON: []byte(`{"id":"bar"}`),
135+
Status: states.ObjectReady,
136+
},
137+
addrs.AbsProviderConfig{
138+
Provider: addrs.NewDefaultProvider("test"),
139+
Module: addrs.RootModule,
140+
},
141+
)
142+
})
143+
statePath := testStateFile(t, originalState)
144+
145+
// Disable test mode so input would be asked
146+
test = false
147+
defer func() { test = true }()
148+
149+
// Answer approval request with "no"
150+
defaultInputReader = bytes.NewBufferString("no\n")
151+
defaultInputWriter = new(bytes.Buffer)
152+
153+
p := applyFixtureProvider()
154+
ui := new(cli.MockUi)
155+
c := &ApplyCommand{
156+
Destroy: true,
157+
Meta: Meta{
158+
testingOverrides: metaOverridesForProvider(p),
159+
Ui: ui,
160+
},
161+
}
162+
163+
args := []string{
164+
"-state", statePath,
165+
}
166+
if code := c.Run(args); code != 1 {
167+
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
168+
}
169+
if got, want := ui.OutputWriter.String(), "Destroy cancelled"; !strings.Contains(got, want) {
170+
t.Fatalf("expected output to include %q, but was:\n%s", want, got)
171+
}
172+
173+
state := testStateRead(t, statePath)
174+
if state == nil {
175+
t.Fatal("state should not be nil")
176+
}
177+
actualStr := strings.TrimSpace(state.String())
178+
expectedStr := strings.TrimSpace(originalState.String())
179+
if actualStr != expectedStr {
180+
t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr)
181+
}
182+
}
183+
184+
func TestApply_destroyApproveYes(t *testing.T) {
185+
// Create a temporary working directory that is empty
186+
td := tempDir(t)
187+
testCopyDir(t, testFixturePath("apply"), td)
188+
defer os.RemoveAll(td)
189+
defer testChdir(t, td)()
190+
191+
statePath := testTempFile(t)
192+
193+
p := applyFixtureProvider()
194+
195+
// Disable test mode so input would be asked
196+
test = false
197+
defer func() { test = true }()
198+
199+
// Answer approval request with "yes"
200+
defaultInputReader = bytes.NewBufferString("yes\n")
201+
defaultInputWriter = new(bytes.Buffer)
202+
203+
ui := new(cli.MockUi)
204+
c := &ApplyCommand{
205+
Destroy: true,
206+
Meta: Meta{
207+
testingOverrides: metaOverridesForProvider(p),
208+
Ui: ui,
209+
},
210+
}
211+
212+
args := []string{
213+
"-state", statePath,
214+
}
215+
if code := c.Run(args); code != 0 {
216+
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
217+
}
218+
219+
if _, err := os.Stat(statePath); err != nil {
220+
t.Fatalf("err: %s", err)
221+
}
222+
223+
state := testStateRead(t, statePath)
224+
if state == nil {
225+
t.Fatal("state should not be nil")
226+
}
227+
228+
actualStr := strings.TrimSpace(state.String())
229+
expectedStr := strings.TrimSpace(testApplyDestroyStr)
230+
if actualStr != expectedStr {
231+
t.Fatalf("bad:\n\n%s\n\n%s", actualStr, expectedStr)
232+
}
233+
}
234+
117235
func TestApply_destroyLockedState(t *testing.T) {
118236
originalState := states.BuildState(func(s *states.SyncState) {
119237
s.SetResourceInstanceCurrent(

command/apply_test.go

+85
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,91 @@ func TestApply(t *testing.T) {
6363
}
6464
}
6565

66+
func TestApply_approveNo(t *testing.T) {
67+
// Create a temporary working directory that is empty
68+
td := tempDir(t)
69+
testCopyDir(t, testFixturePath("apply"), td)
70+
defer os.RemoveAll(td)
71+
defer testChdir(t, td)()
72+
73+
statePath := testTempFile(t)
74+
75+
// Disable test mode so input would be asked
76+
test = false
77+
defer func() { test = true }()
78+
79+
// Answer approval request with "no"
80+
defaultInputReader = bytes.NewBufferString("no\n")
81+
defaultInputWriter = new(bytes.Buffer)
82+
83+
p := applyFixtureProvider()
84+
ui := new(cli.MockUi)
85+
c := &ApplyCommand{
86+
Meta: Meta{
87+
testingOverrides: metaOverridesForProvider(p),
88+
Ui: ui,
89+
},
90+
}
91+
92+
args := []string{
93+
"-state", statePath,
94+
}
95+
if code := c.Run(args); code != 1 {
96+
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
97+
}
98+
if got, want := ui.OutputWriter.String(), "Apply cancelled"; !strings.Contains(got, want) {
99+
t.Fatalf("expected output to include %q, but was:\n%s", want, got)
100+
}
101+
102+
if _, err := os.Stat(statePath); err == nil || !os.IsNotExist(err) {
103+
t.Fatalf("state file should not exist")
104+
}
105+
}
106+
107+
func TestApply_approveYes(t *testing.T) {
108+
// Create a temporary working directory that is empty
109+
td := tempDir(t)
110+
testCopyDir(t, testFixturePath("apply"), td)
111+
defer os.RemoveAll(td)
112+
defer testChdir(t, td)()
113+
114+
statePath := testTempFile(t)
115+
116+
p := applyFixtureProvider()
117+
118+
// Disable test mode so input would be asked
119+
test = false
120+
defer func() { test = true }()
121+
122+
// Answer approval request with "yes"
123+
defaultInputReader = bytes.NewBufferString("yes\n")
124+
defaultInputWriter = new(bytes.Buffer)
125+
126+
ui := new(cli.MockUi)
127+
c := &ApplyCommand{
128+
Meta: Meta{
129+
testingOverrides: metaOverridesForProvider(p),
130+
Ui: ui,
131+
},
132+
}
133+
134+
args := []string{
135+
"-state", statePath,
136+
}
137+
if code := c.Run(args); code != 0 {
138+
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
139+
}
140+
141+
if _, err := os.Stat(statePath); err != nil {
142+
t.Fatalf("err: %s", err)
143+
}
144+
145+
state := testStateRead(t, statePath)
146+
if state == nil {
147+
t.Fatal("state should not be nil")
148+
}
149+
}
150+
66151
// test apply with locked state
67152
func TestApply_lockedState(t *testing.T) {
68153
// Create a temporary working directory that is empty

0 commit comments

Comments
 (0)