stacks: mark input and output changes as no-ops when no changes (#35725)

pull/35726/head
Liam Cervante 2 years ago committed by GitHub
parent d142486a40
commit 3b30caa42b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -159,6 +159,54 @@ func TestApply(t *testing.T) {
},
},
},
"updating inputs and outputs (noop)": {
path: "component-input-output",
cycles: []TestCycle{
{
planInputs: map[string]cty.Value{
"value": cty.StringVal("foo"),
},
},
{
planInputs: map[string]cty.Value{
"value": cty.StringVal("foo"),
},
wantPlannedChanges: []stackplan.PlannedChange{
&stackplan.PlannedChangeApplyable{
Applyable: true,
},
&stackplan.PlannedChangeHeader{
TerraformVersion: version.SemVer,
},
&stackplan.PlannedChangeOutputValue{
Addr: mustStackOutputValue("value"),
Action: plans.NoOp,
Before: cty.StringVal("foo"),
After: cty.StringVal("foo"),
},
&stackplan.PlannedChangePlannedTimestamp{
PlannedTimestamp: fakePlanTimestamp,
},
&stackplan.PlannedChangeRootInputValue{
Addr: mustStackInputVariable("value"),
Action: plans.NoOp,
Before: cty.StringVal("foo"),
After: cty.StringVal("foo"),
},
},
wantAppliedChanges: []stackstate.AppliedChange{
&stackstate.AppliedChangeOutputValue{
Addr: mustStackOutputValue("value"),
Value: cty.StringVal("foo"),
},
&stackstate.AppliedChangeInputVariable{
Addr: mustStackInputVariable("value"),
Value: cty.StringVal("foo"),
},
},
},
},
},
"deleting inputs and outputs": {
path: "component-input-output",
state: stackstate.NewStateBuilder().

@ -245,13 +245,6 @@ func (v *InputVariable) PlanChanges(ctx context.Context) ([]stackplan.PlannedCha
before, beforeEphemeral := v.main.PlanPrevState().RootInputVariable(v.Addr().Item)
action := plans.Create
if beforeEphemeral || before != cty.NilVal {
action = plans.Update
} else {
before = cty.NullVal(cty.DynamicPseudoType)
}
decl := v.Declaration(ctx)
after := v.Value(ctx, PlanPhase)
requiredOnApply := false
@ -261,6 +254,35 @@ func (v *InputVariable) PlanChanges(ctx context.Context) ([]stackplan.PlannedCha
requiredOnApply = !after.IsNull()
after = cty.NilVal
}
var action plans.Action
if beforeEphemeral {
// We can't tell the difference between an Update and NoOp change for
// an ephemeral input so we just always mark it as updated.
action = plans.Update
} else if before != cty.NilVal {
if decl.Ephemeral {
// if the new value is ephemeral, and the old value wasn't, then
// we'll set the operation to an update even if the actual hasn't
// changed
action = plans.Update
} else if result := before.Equals(after); result.IsKnown() && result.True() {
// The values are definitely equal, so NoOp change.
action = plans.NoOp
} else {
// If we don't know for sure that the values are equal, then we'll
// call this an update.
action = plans.Update
}
} else {
action = plans.Create
// We think this is a brand new input variable so we'll also mark the
// before as being a null value (as opposed to NilVal which means it
// existed before but was ephemeral).
before = cty.NullVal(cty.DynamicPseudoType)
}
return []stackplan.PlannedChange{
&stackplan.PlannedChangeRootInputValue{
Addr: v.Addr().Item,

@ -773,8 +773,13 @@ func (s *Stack) PlanChanges(ctx context.Context) ([]stackplan.PlannedChange, tfd
action := plans.Create
if actualBefore, exists := beforeVal[addr]; exists {
action = plans.Update
before = actualBefore
if result := before.Equals(after); result.IsKnown() && result.True() {
action = plans.NoOp
} else {
action = plans.Update
}
}
changes = append(changes, &stackplan.PlannedChangeOutputValue{

Loading…
Cancel
Save