2018-12-10 18:42:45 +01:00
|
|
|
package format
|
|
|
|
|
|
|
|
import (
|
2020-09-04 22:03:48 +02:00
|
|
|
"fmt"
|
2018-12-10 18:42:45 +01:00
|
|
|
"testing"
|
|
|
|
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
"github.com/google/go-cmp/cmp"
|
2018-12-10 18:42:45 +01:00
|
|
|
"github.com/hashicorp/terraform/addrs"
|
|
|
|
"github.com/hashicorp/terraform/configs/configschema"
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
"github.com/hashicorp/terraform/helper/experiment"
|
2018-12-10 18:42:45 +01:00
|
|
|
"github.com/hashicorp/terraform/plans"
|
|
|
|
"github.com/mitchellh/colorstring"
|
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
)
|
|
|
|
|
2018-12-11 12:49:17 +01:00
|
|
|
func TestResourceChange_primitiveTypes(t *testing.T) {
|
|
|
|
testCases := map[string]testCase{
|
2018-12-10 18:42:45 +01:00
|
|
|
"creation": {
|
|
|
|
Action: plans.Create,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.NullVal(cty.EmptyObject),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Computed: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-10 18:42:45 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be created
|
|
|
|
+ resource "test_instance" "example" {
|
|
|
|
+ id = (known after apply)
|
|
|
|
}
|
2019-03-14 22:20:42 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"creation (null string)": {
|
|
|
|
Action: plans.Create,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.NullVal(cty.EmptyObject),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"string": cty.StringVal("null"),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"string": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
|
|
|
Tainted: false,
|
|
|
|
ExpectedOutput: ` # test_instance.example will be created
|
|
|
|
+ resource "test_instance" "example" {
|
|
|
|
+ string = "null"
|
|
|
|
}
|
2019-11-15 16:25:49 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"creation (null string with extra whitespace)": {
|
|
|
|
Action: plans.Create,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.NullVal(cty.EmptyObject),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"string": cty.StringVal("null "),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"string": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
|
|
|
Tainted: false,
|
|
|
|
ExpectedOutput: ` # test_instance.example will be created
|
|
|
|
+ resource "test_instance" "example" {
|
|
|
|
+ string = "null "
|
|
|
|
}
|
2018-12-10 18:42:45 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"deletion": {
|
|
|
|
Action: plans.Delete,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
}),
|
|
|
|
After: cty.NullVal(cty.EmptyObject),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Computed: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-10 18:42:45 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be destroyed
|
2019-01-13 23:51:05 +01:00
|
|
|
- resource "test_instance" "example" {
|
|
|
|
- id = "i-02ae66f368e8518a9" -> null
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"deletion (empty string)": {
|
|
|
|
Action: plans.Delete,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"intentionally_long": cty.StringVal(""),
|
|
|
|
}),
|
|
|
|
After: cty.NullVal(cty.EmptyObject),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Computed: true},
|
|
|
|
"intentionally_long": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-13 23:51:05 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be destroyed
|
2018-12-10 18:42:45 +01:00
|
|
|
- resource "test_instance" "example" {
|
|
|
|
- id = "i-02ae66f368e8518a9" -> null
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
2018-12-11 12:49:17 +01:00
|
|
|
"string in-place update": {
|
2018-12-10 18:42:45 +01:00
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-10 18:42:45 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
2018-12-11 12:49:17 +01:00
|
|
|
"string force-new update": {
|
2018-12-10 18:42:45 +01:00
|
|
|
Action: plans.DeleteThenCreate,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
2018-12-11 12:49:17 +01:00
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
2018-12-10 18:42:45 +01:00
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(cty.Path{
|
|
|
|
cty.GetAttrStep{Name: "ami"},
|
|
|
|
}),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-10 18:42:45 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example must be replaced
|
|
|
|
-/+ resource "test_instance" "example" {
|
2018-12-11 12:55:59 +01:00
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER" # forces replacement
|
2018-12-11 12:49:17 +01:00
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"string in-place update (null values)": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"unchanged": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"unchanged": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"unchanged": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:49:17 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update of multi-line string field": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"more_lines": cty.StringVal(`original
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
long
|
|
|
|
multi-line
|
|
|
|
string
|
|
|
|
field
|
2018-12-11 12:49:17 +01:00
|
|
|
`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"more_lines": cty.StringVal(`original
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
extremely long
|
|
|
|
multi-line
|
|
|
|
string
|
|
|
|
field
|
2018-12-11 12:49:17 +01:00
|
|
|
`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"more_lines": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:49:17 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ more_lines = <<~EOT
|
|
|
|
original
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
- long
|
|
|
|
+ extremely long
|
|
|
|
multi-line
|
|
|
|
string
|
|
|
|
field
|
2018-12-11 12:49:17 +01:00
|
|
|
EOT
|
|
|
|
}
|
2019-11-07 00:59:54 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"addition of multi-line string field": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"more_lines": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"more_lines": cty.StringVal(`original
|
|
|
|
new line
|
|
|
|
`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"more_lines": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
|
|
|
Tainted: false,
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
+ more_lines = <<~EOT
|
|
|
|
original
|
|
|
|
new line
|
|
|
|
EOT
|
|
|
|
}
|
2018-12-11 12:49:17 +01:00
|
|
|
`,
|
|
|
|
},
|
2018-12-11 12:55:59 +01:00
|
|
|
"force-new update of multi-line string field": {
|
|
|
|
Action: plans.DeleteThenCreate,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"more_lines": cty.StringVal(`original
|
|
|
|
`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"more_lines": cty.StringVal(`original
|
|
|
|
new line
|
|
|
|
`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"more_lines": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(cty.Path{
|
|
|
|
cty.GetAttrStep{Name: "more_lines"},
|
|
|
|
}),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:55:59 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example must be replaced
|
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ more_lines = <<~EOT # forces replacement
|
|
|
|
original
|
|
|
|
+ new line
|
|
|
|
EOT
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
2018-12-11 12:49:17 +01:00
|
|
|
|
|
|
|
// Sensitive
|
|
|
|
|
|
|
|
"creation with sensitive field": {
|
|
|
|
Action: plans.Create,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.NullVal(cty.EmptyObject),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"password": cty.StringVal("top-secret"),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Computed: true},
|
|
|
|
"password": {Type: cty.String, Optional: true, Sensitive: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:49:17 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be created
|
|
|
|
+ resource "test_instance" "example" {
|
|
|
|
+ id = (known after apply)
|
|
|
|
+ password = (sensitive value)
|
2018-12-10 18:42:45 +01:00
|
|
|
}
|
2019-01-23 16:32:13 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"update with equal sensitive field": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("blah"),
|
|
|
|
"str": cty.StringVal("before"),
|
|
|
|
"password": cty.StringVal("top-secret"),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"str": cty.StringVal("after"),
|
|
|
|
"password": cty.StringVal("top-secret"),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Computed: true},
|
|
|
|
"str": {Type: cty.String, Optional: true},
|
|
|
|
"password": {Type: cty.String, Optional: true, Sensitive: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-23 16:32:13 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "blah" -> (known after apply)
|
|
|
|
~ str = "before" -> "after"
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2019-01-23 16:32:13 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "blah" -> (known after apply)
|
|
|
|
password = (sensitive value)
|
|
|
|
~ str = "before" -> "after"
|
|
|
|
}
|
2019-03-06 01:18:55 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
|
|
|
|
// tainted resources
|
|
|
|
"replace tainted resource": {
|
|
|
|
Action: plans.DeleteThenCreate,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(cty.Path{
|
|
|
|
cty.GetAttrStep{Name: "ami"},
|
|
|
|
}),
|
|
|
|
Tainted: true,
|
|
|
|
ExpectedOutput: ` # test_instance.example is tainted, so must be replaced
|
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER" # forces replacement
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
}
|
2019-03-29 22:52:13 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"force replacement with empty before value": {
|
|
|
|
Action: plans.DeleteThenCreate,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"name": cty.StringVal("name"),
|
|
|
|
"forced": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"name": cty.StringVal("name"),
|
|
|
|
"forced": cty.StringVal("example"),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"name": {Type: cty.String, Optional: true},
|
|
|
|
"forced": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(cty.Path{
|
|
|
|
cty.GetAttrStep{Name: "forced"},
|
|
|
|
}),
|
|
|
|
Tainted: false,
|
|
|
|
ExpectedOutput: ` # test_instance.example must be replaced
|
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
+ forced = "example" # forces replacement
|
|
|
|
name = "name"
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"force replacement with empty before value legacy": {
|
|
|
|
Action: plans.DeleteThenCreate,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"name": cty.StringVal("name"),
|
|
|
|
"forced": cty.StringVal(""),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"name": cty.StringVal("name"),
|
|
|
|
"forced": cty.StringVal("example"),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"name": {Type: cty.String, Optional: true},
|
|
|
|
"forced": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(cty.Path{
|
|
|
|
cty.GetAttrStep{Name: "forced"},
|
|
|
|
}),
|
|
|
|
Tainted: false,
|
|
|
|
ExpectedOutput: ` # test_instance.example must be replaced
|
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
+ forced = "example" # forces replacement
|
|
|
|
name = "name"
|
|
|
|
}
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"show all identifying attributes even if unchanged": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"bar": cty.StringVal("bar"),
|
|
|
|
"foo": cty.StringVal("foo"),
|
|
|
|
"name": cty.StringVal("alice"),
|
|
|
|
"tags": cty.MapVal(map[string]cty.Value{
|
|
|
|
"name": cty.StringVal("bob"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"bar": cty.StringVal("bar"),
|
|
|
|
"foo": cty.StringVal("foo"),
|
|
|
|
"name": cty.StringVal("alice"),
|
|
|
|
"tags": cty.MapVal(map[string]cty.Value{
|
|
|
|
"name": cty.StringVal("bob"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"bar": {Type: cty.String, Optional: true},
|
|
|
|
"foo": {Type: cty.String, Optional: true},
|
|
|
|
"name": {Type: cty.String, Optional: true},
|
|
|
|
"tags": {Type: cty.Map(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
|
|
|
Tainted: false,
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
name = "alice"
|
|
|
|
tags = {
|
|
|
|
"name" = "bob"
|
|
|
|
}
|
|
|
|
# (2 unchanged attributes hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
bar = "bar"
|
|
|
|
foo = "foo"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
name = "alice"
|
|
|
|
tags = {
|
|
|
|
"name" = "bob"
|
|
|
|
}
|
|
|
|
}
|
2018-12-10 18:42:45 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2018-12-11 12:49:17 +01:00
|
|
|
runTestCases(t, testCases)
|
|
|
|
}
|
|
|
|
|
2018-12-11 12:50:08 +01:00
|
|
|
func TestResourceChange_JSON(t *testing.T) {
|
|
|
|
testCases := map[string]testCase{
|
|
|
|
"creation": {
|
|
|
|
Action: plans.Create,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.NullVal(cty.EmptyObject),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`{
|
|
|
|
"str": "value",
|
|
|
|
"list":["a","b", 234, true],
|
|
|
|
"obj": {"key": "val"}
|
|
|
|
}`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be created
|
|
|
|
+ resource "test_instance" "example" {
|
|
|
|
+ id = (known after apply)
|
|
|
|
+ json_field = jsonencode(
|
|
|
|
{
|
|
|
|
+ list = [
|
|
|
|
+ "a",
|
|
|
|
+ "b",
|
|
|
|
+ 234,
|
|
|
|
+ true,
|
|
|
|
]
|
|
|
|
+ obj = {
|
|
|
|
+ key = "val"
|
|
|
|
}
|
|
|
|
+ str = "value"
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
2019-01-23 14:13:48 +01:00
|
|
|
"in-place update of object": {
|
2018-12-11 12:50:08 +01:00
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
"json_field": cty.StringVal(`{"aaa": "value","ccc": 5}`),
|
2018-12-11 12:50:08 +01:00
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`{"aaa": "value", "bbb": "new_value"}`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ {
|
|
|
|
+ bbb = "new_value"
|
|
|
|
- ccc = 5 -> null
|
|
|
|
# (1 unchanged element hidden)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2018-12-11 12:50:08 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ {
|
2019-01-15 16:37:03 +01:00
|
|
|
aaa = "value"
|
2018-12-11 12:50:08 +01:00
|
|
|
+ bbb = "new_value"
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
- ccc = 5 -> null
|
2018-12-11 12:50:08 +01:00
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
2019-01-15 16:37:03 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update (from empty tuple)": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"json_field": cty.StringVal(`{"aaa": []}`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`{"aaa": ["value"]}`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-15 16:37:03 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ {
|
|
|
|
~ aaa = [
|
|
|
|
+ "value",
|
|
|
|
]
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update (to empty tuple)": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"json_field": cty.StringVal(`{"aaa": ["value"]}`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`{"aaa": []}`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-15 16:37:03 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ {
|
|
|
|
~ aaa = [
|
|
|
|
- "value",
|
|
|
|
]
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
2019-01-22 17:49:49 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update (tuple of different types)": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"json_field": cty.StringVal(`{"aaa": [42, {"foo":"bar"}, "value"]}`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`{"aaa": [42, {"foo":"baz"}, "value"]}`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-22 17:49:49 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ {
|
|
|
|
~ aaa = [
|
|
|
|
42,
|
|
|
|
~ {
|
|
|
|
~ foo = "bar" -> "baz"
|
|
|
|
},
|
|
|
|
"value",
|
|
|
|
]
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
2018-12-11 12:55:59 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"force-new update": {
|
|
|
|
Action: plans.DeleteThenCreate,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"json_field": cty.StringVal(`{"aaa": "value"}`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`{"aaa": "value", "bbb": "new_value"}`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(cty.Path{
|
|
|
|
cty.GetAttrStep{Name: "json_field"},
|
|
|
|
}),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:55:59 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example must be replaced
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ {
|
|
|
|
+ bbb = "new_value"
|
|
|
|
# (1 unchanged element hidden)
|
|
|
|
} # forces replacement
|
|
|
|
)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example must be replaced
|
2018-12-11 12:55:59 +01:00
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ {
|
2019-01-15 16:37:03 +01:00
|
|
|
aaa = "value"
|
2018-12-11 12:55:59 +01:00
|
|
|
+ bbb = "new_value"
|
|
|
|
} # forces replacement
|
|
|
|
)
|
|
|
|
}
|
2018-12-11 12:50:08 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update (whitespace change)": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"json_field": cty.StringVal(`{"aaa": "value", "bbb": "another"}`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`{"aaa":"value",
|
|
|
|
"bbb":"another"}`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode( # whitespace changes
|
|
|
|
{
|
|
|
|
aaa = "value"
|
|
|
|
bbb = "another"
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
2018-12-11 12:55:59 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"force-new update (whitespace change)": {
|
|
|
|
Action: plans.DeleteThenCreate,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"json_field": cty.StringVal(`{"aaa": "value", "bbb": "another"}`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`{"aaa":"value",
|
|
|
|
"bbb":"another"}`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(cty.Path{
|
|
|
|
cty.GetAttrStep{Name: "json_field"},
|
|
|
|
}),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:55:59 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example must be replaced
|
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode( # whitespace changes force replacement
|
|
|
|
{
|
|
|
|
aaa = "value"
|
|
|
|
bbb = "another"
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
2019-01-14 16:29:36 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"creation (empty)": {
|
|
|
|
Action: plans.Create,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.NullVal(cty.EmptyObject),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`{}`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-14 16:29:36 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be created
|
|
|
|
+ resource "test_instance" "example" {
|
|
|
|
+ id = (known after apply)
|
|
|
|
+ json_field = jsonencode({})
|
|
|
|
}
|
2018-12-11 12:50:08 +01:00
|
|
|
`,
|
|
|
|
},
|
2019-01-15 16:37:03 +01:00
|
|
|
"JSON list item removal": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"json_field": cty.StringVal(`["first","second","third"]`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`["first","second"]`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-15 16:37:03 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ [
|
|
|
|
# (1 unchanged element hidden)
|
|
|
|
"second",
|
|
|
|
- "third",
|
|
|
|
]
|
|
|
|
)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2019-01-15 16:37:03 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ [
|
|
|
|
"first",
|
|
|
|
"second",
|
|
|
|
- "third",
|
|
|
|
]
|
|
|
|
)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"JSON list item addition": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"json_field": cty.StringVal(`["first","second"]`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`["first","second","third"]`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-15 16:37:03 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ [
|
|
|
|
# (1 unchanged element hidden)
|
|
|
|
"second",
|
|
|
|
+ "third",
|
|
|
|
]
|
|
|
|
)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2019-01-15 16:37:03 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ [
|
|
|
|
"first",
|
|
|
|
"second",
|
|
|
|
+ "third",
|
|
|
|
]
|
|
|
|
)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"JSON list object addition": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"json_field": cty.StringVal(`{"first":"111"}`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`{"first":"111","second":"222"}`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-15 16:37:03 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ {
|
|
|
|
+ second = "222"
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
# (1 unchanged element hidden)
|
2019-01-15 16:37:03 +01:00
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"JSON object with nested list": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"json_field": cty.StringVal(`{
|
|
|
|
"Statement": ["first"]
|
|
|
|
}`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`{
|
|
|
|
"Statement": ["first", "second"]
|
|
|
|
}`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-15 16:37:03 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ {
|
|
|
|
~ Statement = [
|
|
|
|
"first",
|
|
|
|
+ "second",
|
|
|
|
]
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
2019-03-19 23:21:32 +01:00
|
|
|
"JSON list of objects - adding item": {
|
2019-01-15 16:37:03 +01:00
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"json_field": cty.StringVal(`[{"one": "111"}]`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`[{"one": "111"}, {"two": "222"}]`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-15 16:37:03 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ [
|
|
|
|
{
|
|
|
|
one = "111"
|
|
|
|
},
|
|
|
|
+ {
|
|
|
|
+ two = "222"
|
|
|
|
},
|
|
|
|
]
|
|
|
|
)
|
|
|
|
}
|
2019-03-19 23:21:32 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"JSON list of objects - removing item": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
2019-11-09 01:05:23 +01:00
|
|
|
"json_field": cty.StringVal(`[{"one": "111"}, {"two": "222"}, {"three": "333"}]`),
|
2019-03-19 23:21:32 +01:00
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
2019-11-09 01:05:23 +01:00
|
|
|
"json_field": cty.StringVal(`[{"one": "111"}, {"three": "333"}]`),
|
2019-03-19 23:21:32 +01:00
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
|
|
|
Tainted: false,
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ [
|
|
|
|
{
|
|
|
|
one = "111"
|
|
|
|
},
|
|
|
|
- {
|
|
|
|
- two = "222"
|
|
|
|
},
|
2019-11-09 01:05:23 +01:00
|
|
|
{
|
|
|
|
three = "333"
|
|
|
|
},
|
2019-03-19 23:21:32 +01:00
|
|
|
]
|
|
|
|
)
|
|
|
|
}
|
2019-01-15 16:37:03 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"JSON object with list of objects": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"json_field": cty.StringVal(`{"parent":[{"one": "111"}]}`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`{"parent":[{"one": "111"}, {"two": "222"}]}`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-15 16:37:03 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ {
|
|
|
|
~ parent = [
|
|
|
|
{
|
|
|
|
one = "111"
|
|
|
|
},
|
|
|
|
+ {
|
|
|
|
+ two = "222"
|
|
|
|
},
|
|
|
|
]
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"JSON object double nested lists": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"json_field": cty.StringVal(`{"parent":[{"another_list": ["111"]}]}`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`{"parent":[{"another_list": ["111", "222"]}]}`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-15 16:37:03 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ {
|
|
|
|
~ parent = [
|
|
|
|
~ {
|
|
|
|
~ another_list = [
|
|
|
|
"111",
|
|
|
|
+ "222",
|
|
|
|
]
|
|
|
|
},
|
|
|
|
]
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
2019-01-23 14:13:48 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update from object to tuple": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"json_field": cty.StringVal(`{"aaa": [42, {"foo":"bar"}, "value"]}`),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"json_field": cty.StringVal(`["aaa", 42, "something"]`),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"json_field": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-23 14:13:48 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ json_field = jsonencode(
|
|
|
|
~ {
|
|
|
|
- aaa = [
|
|
|
|
- 42,
|
|
|
|
- {
|
|
|
|
- foo = "bar"
|
|
|
|
},
|
|
|
|
- "value",
|
|
|
|
]
|
|
|
|
} -> [
|
|
|
|
+ "aaa",
|
|
|
|
+ 42,
|
|
|
|
+ "something",
|
|
|
|
]
|
|
|
|
)
|
|
|
|
}
|
2019-01-15 16:37:03 +01:00
|
|
|
`,
|
|
|
|
},
|
2018-12-11 12:50:08 +01:00
|
|
|
}
|
|
|
|
runTestCases(t, testCases)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestResourceChange_primitiveList(t *testing.T) {
|
|
|
|
testCases := map[string]testCase{
|
|
|
|
"in-place update - creation": {
|
2019-01-14 16:34:41 +01:00
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.NullVal(cty.List(cty.String)),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("new-element"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"list_field": {Type: cty.List(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-14 16:34:41 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
+ list_field = [
|
|
|
|
+ "new-element",
|
|
|
|
]
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2019-01-14 16:34:41 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
+ list_field = [
|
|
|
|
+ "new-element",
|
|
|
|
]
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - first addition": {
|
2018-12-11 12:50:08 +01:00
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListValEmpty(cty.String),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("new-element"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"list_field": {Type: cty.List(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ list_field = [
|
|
|
|
+ "new-element",
|
|
|
|
]
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2018-12-11 12:50:08 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ list_field = [
|
|
|
|
+ "new-element",
|
|
|
|
]
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - insertion": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
cty.StringVal("dddd"),
|
|
|
|
cty.StringVal("eeee"),
|
|
|
|
cty.StringVal("ffff"),
|
2018-12-11 12:50:08 +01:00
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
cty.StringVal("cccc"),
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
cty.StringVal("dddd"),
|
|
|
|
cty.StringVal("eeee"),
|
|
|
|
cty.StringVal("ffff"),
|
2018-12-11 12:50:08 +01:00
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"list_field": {Type: cty.List(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ list_field = [
|
|
|
|
# (1 unchanged element hidden)
|
|
|
|
"bbbb",
|
|
|
|
+ "cccc",
|
|
|
|
"dddd",
|
|
|
|
# (2 unchanged elements hidden)
|
|
|
|
]
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2018-12-11 12:50:08 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ list_field = [
|
|
|
|
"aaaa",
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
"bbbb",
|
|
|
|
+ "cccc",
|
|
|
|
"dddd",
|
|
|
|
"eeee",
|
|
|
|
"ffff",
|
2018-12-11 12:50:08 +01:00
|
|
|
]
|
|
|
|
}
|
2018-12-11 12:55:59 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"force-new update - insertion": {
|
|
|
|
Action: plans.DeleteThenCreate,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"list_field": {Type: cty.List(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(cty.Path{
|
|
|
|
cty.GetAttrStep{Name: "list_field"},
|
|
|
|
}),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:55:59 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example must be replaced
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ list_field = [ # forces replacement
|
|
|
|
"aaaa",
|
|
|
|
+ "bbbb",
|
|
|
|
"cccc",
|
|
|
|
]
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example must be replaced
|
2018-12-11 12:55:59 +01:00
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ list_field = [ # forces replacement
|
|
|
|
"aaaa",
|
|
|
|
+ "bbbb",
|
|
|
|
"cccc",
|
|
|
|
]
|
|
|
|
}
|
2018-12-11 12:50:08 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - deletion": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
cty.StringVal("cccc"),
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
cty.StringVal("dddd"),
|
|
|
|
cty.StringVal("eeee"),
|
2018-12-11 12:50:08 +01:00
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("bbbb"),
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
cty.StringVal("dddd"),
|
|
|
|
cty.StringVal("eeee"),
|
2018-12-11 12:50:08 +01:00
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"list_field": {Type: cty.List(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ list_field = [
|
|
|
|
- "aaaa",
|
|
|
|
"bbbb",
|
|
|
|
- "cccc",
|
|
|
|
"dddd",
|
|
|
|
# (1 unchanged element hidden)
|
|
|
|
]
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2018-12-11 12:50:08 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ list_field = [
|
|
|
|
- "aaaa",
|
|
|
|
"bbbb",
|
|
|
|
- "cccc",
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
"dddd",
|
|
|
|
"eeee",
|
2018-12-11 12:50:08 +01:00
|
|
|
]
|
|
|
|
}
|
2019-01-14 16:34:41 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"creation - empty list": {
|
|
|
|
Action: plans.Create,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.NullVal(cty.EmptyObject),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListValEmpty(cty.String),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"list_field": {Type: cty.List(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-14 16:34:41 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be created
|
|
|
|
+ resource "test_instance" "example" {
|
|
|
|
+ ami = "ami-STATIC"
|
|
|
|
+ id = (known after apply)
|
|
|
|
+ list_field = []
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - full to empty": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListValEmpty(cty.String),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"list_field": {Type: cty.List(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-14 16:34:41 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ list_field = [
|
|
|
|
- "aaaa",
|
|
|
|
- "bbbb",
|
|
|
|
- "cccc",
|
|
|
|
]
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2019-01-14 16:34:41 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ list_field = [
|
|
|
|
- "aaaa",
|
|
|
|
- "bbbb",
|
|
|
|
- "cccc",
|
|
|
|
]
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - null to empty": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.NullVal(cty.List(cty.String)),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListValEmpty(cty.String),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"list_field": {Type: cty.List(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-14 16:34:41 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
+ list_field = []
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2019-01-14 16:34:41 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
+ list_field = []
|
|
|
|
}
|
2019-01-21 16:02:15 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"update to unknown element": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.UnknownVal(cty.String),
|
|
|
|
cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"list_field": {Type: cty.List(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-21 16:02:15 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ list_field = [
|
|
|
|
"aaaa",
|
|
|
|
- "bbbb",
|
|
|
|
+ (known after apply),
|
|
|
|
"cccc",
|
|
|
|
]
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2019-01-21 16:02:15 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ list_field = [
|
|
|
|
"aaaa",
|
|
|
|
- "bbbb",
|
|
|
|
+ (known after apply),
|
|
|
|
"cccc",
|
|
|
|
]
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"update - two new unknown elements": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
cty.StringVal("cccc"),
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
cty.StringVal("dddd"),
|
|
|
|
cty.StringVal("eeee"),
|
2019-01-21 16:02:15 +01:00
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"list_field": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.UnknownVal(cty.String),
|
|
|
|
cty.UnknownVal(cty.String),
|
|
|
|
cty.StringVal("cccc"),
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
cty.StringVal("dddd"),
|
|
|
|
cty.StringVal("eeee"),
|
2019-01-21 16:02:15 +01:00
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"list_field": {Type: cty.List(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-21 16:02:15 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ list_field = [
|
|
|
|
"aaaa",
|
|
|
|
- "bbbb",
|
|
|
|
+ (known after apply),
|
|
|
|
+ (known after apply),
|
|
|
|
"cccc",
|
|
|
|
# (2 unchanged elements hidden)
|
|
|
|
]
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2019-01-21 16:02:15 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ list_field = [
|
|
|
|
"aaaa",
|
|
|
|
- "bbbb",
|
|
|
|
+ (known after apply),
|
|
|
|
+ (known after apply),
|
|
|
|
"cccc",
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
"dddd",
|
|
|
|
"eeee",
|
|
|
|
]
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
runTestCases(t, testCases)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestResourceChange_primitiveTuple(t *testing.T) {
|
|
|
|
testCases := map[string]testCase{
|
|
|
|
"in-place update": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"tuple_field": cty.TupleVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
cty.StringVal("dddd"),
|
|
|
|
cty.StringVal("eeee"),
|
|
|
|
cty.StringVal("ffff"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"tuple_field": cty.TupleVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
cty.StringVal("cccc"),
|
|
|
|
cty.StringVal("eeee"),
|
|
|
|
cty.StringVal("ffff"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Required: true},
|
|
|
|
"tuple_field": {Type: cty.Tuple([]cty.Type{cty.String, cty.String, cty.String, cty.String, cty.String}), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
|
|
|
Tainted: false,
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
~ tuple_field = [
|
|
|
|
# (1 unchanged element hidden)
|
|
|
|
"bbbb",
|
|
|
|
- "dddd",
|
|
|
|
+ "cccc",
|
|
|
|
"eeee",
|
|
|
|
# (1 unchanged element hidden)
|
|
|
|
]
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
~ tuple_field = [
|
|
|
|
"aaaa",
|
|
|
|
"bbbb",
|
|
|
|
- "dddd",
|
|
|
|
+ "cccc",
|
|
|
|
"eeee",
|
|
|
|
"ffff",
|
2019-01-21 16:02:15 +01:00
|
|
|
]
|
|
|
|
}
|
2018-12-11 12:50:08 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
runTestCases(t, testCases)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestResourceChange_primitiveSet(t *testing.T) {
|
|
|
|
testCases := map[string]testCase{
|
|
|
|
"in-place update - creation": {
|
2019-01-14 16:34:41 +01:00
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.NullVal(cty.Set(cty.String)),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetVal([]cty.Value{
|
|
|
|
cty.StringVal("new-element"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"set_field": {Type: cty.Set(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-14 16:34:41 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
+ set_field = [
|
|
|
|
+ "new-element",
|
|
|
|
]
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2019-01-14 16:34:41 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
+ set_field = [
|
|
|
|
+ "new-element",
|
|
|
|
]
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - first insertion": {
|
2018-12-11 12:50:08 +01:00
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetValEmpty(cty.String),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetVal([]cty.Value{
|
|
|
|
cty.StringVal("new-element"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"set_field": {Type: cty.Set(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ set_field = [
|
|
|
|
+ "new-element",
|
|
|
|
]
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2018-12-11 12:50:08 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ set_field = [
|
|
|
|
+ "new-element",
|
|
|
|
]
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - insertion": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"set_field": {Type: cty.Set(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ set_field = [
|
|
|
|
+ "bbbb",
|
|
|
|
# (2 unchanged elements hidden)
|
|
|
|
]
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2018-12-11 12:50:08 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ set_field = [
|
|
|
|
"aaaa",
|
|
|
|
+ "bbbb",
|
|
|
|
"cccc",
|
|
|
|
]
|
|
|
|
}
|
2018-12-11 12:55:59 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"force-new update - insertion": {
|
|
|
|
Action: plans.DeleteThenCreate,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"set_field": {Type: cty.Set(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(cty.Path{
|
|
|
|
cty.GetAttrStep{Name: "set_field"},
|
|
|
|
}),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:55:59 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example must be replaced
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ set_field = [ # forces replacement
|
|
|
|
+ "bbbb",
|
|
|
|
# (2 unchanged elements hidden)
|
|
|
|
]
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example must be replaced
|
2018-12-11 12:55:59 +01:00
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ set_field = [ # forces replacement
|
|
|
|
"aaaa",
|
|
|
|
+ "bbbb",
|
|
|
|
"cccc",
|
|
|
|
]
|
|
|
|
}
|
2018-12-11 12:50:08 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - deletion": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetVal([]cty.Value{
|
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"set_field": {Type: cty.Set(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ set_field = [
|
|
|
|
- "aaaa",
|
|
|
|
- "cccc",
|
|
|
|
# (1 unchanged element hidden)
|
|
|
|
]
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2018-12-11 12:50:08 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ set_field = [
|
|
|
|
- "aaaa",
|
|
|
|
"bbbb",
|
|
|
|
- "cccc",
|
|
|
|
]
|
|
|
|
}
|
2019-01-14 16:34:41 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"creation - empty set": {
|
|
|
|
Action: plans.Create,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.NullVal(cty.EmptyObject),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetValEmpty(cty.String),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"set_field": {Type: cty.Set(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-14 16:34:41 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be created
|
|
|
|
+ resource "test_instance" "example" {
|
|
|
|
+ ami = "ami-STATIC"
|
|
|
|
+ id = (known after apply)
|
|
|
|
+ set_field = []
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - full to empty set": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetValEmpty(cty.String),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"set_field": {Type: cty.Set(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ set_field = [
|
|
|
|
- "aaaa",
|
|
|
|
- "bbbb",
|
|
|
|
]
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2019-01-14 16:34:41 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ set_field = [
|
|
|
|
- "aaaa",
|
|
|
|
- "bbbb",
|
|
|
|
]
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - null to empty set": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.NullVal(cty.Set(cty.String)),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetValEmpty(cty.String),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"set_field": {Type: cty.Set(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-14 16:34:41 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
+ set_field = []
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2019-01-14 16:34:41 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
+ set_field = []
|
|
|
|
}
|
2019-01-18 14:04:53 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update to unknown": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.UnknownVal(cty.Set(cty.String)),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"set_field": {Type: cty.Set(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-18 14:04:53 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ set_field = [
|
|
|
|
- "aaaa",
|
|
|
|
- "bbbb",
|
|
|
|
] -> (known after apply)
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2019-01-18 14:04:53 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ set_field = [
|
|
|
|
- "aaaa",
|
|
|
|
- "bbbb",
|
|
|
|
] -> (known after apply)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update to unknown element": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.StringVal("bbbb"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"set_field": cty.SetVal([]cty.Value{
|
|
|
|
cty.StringVal("aaaa"),
|
|
|
|
cty.UnknownVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"set_field": {Type: cty.Set(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-18 14:04:53 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ set_field = [
|
|
|
|
- "bbbb",
|
|
|
|
~ (known after apply),
|
|
|
|
# (1 unchanged element hidden)
|
|
|
|
]
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2019-01-18 14:04:53 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ set_field = [
|
|
|
|
"aaaa",
|
|
|
|
- "bbbb",
|
|
|
|
~ (known after apply),
|
|
|
|
]
|
|
|
|
}
|
2018-12-11 12:50:08 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
runTestCases(t, testCases)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestResourceChange_map(t *testing.T) {
|
|
|
|
testCases := map[string]testCase{
|
|
|
|
"in-place update - creation": {
|
2019-01-14 16:15:01 +01:00
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"map_field": cty.NullVal(cty.Map(cty.String)),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"map_field": cty.MapVal(map[string]cty.Value{
|
|
|
|
"new-key": cty.StringVal("new-element"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"map_field": {Type: cty.Map(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-14 16:15:01 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
+ map_field = {
|
|
|
|
+ "new-key" = "new-element"
|
|
|
|
}
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2019-01-14 16:15:01 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
+ map_field = {
|
|
|
|
+ "new-key" = "new-element"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - first insertion": {
|
2018-12-11 12:50:08 +01:00
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"map_field": cty.MapValEmpty(cty.String),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"map_field": cty.MapVal(map[string]cty.Value{
|
|
|
|
"new-key": cty.StringVal("new-element"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"map_field": {Type: cty.Map(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ map_field = {
|
|
|
|
+ "new-key" = "new-element"
|
|
|
|
}
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2018-12-11 12:50:08 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ map_field = {
|
|
|
|
+ "new-key" = "new-element"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - insertion": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"map_field": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.StringVal("aaaa"),
|
|
|
|
"c": cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"map_field": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.StringVal("aaaa"),
|
|
|
|
"b": cty.StringVal("bbbb"),
|
|
|
|
"c": cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"map_field": {Type: cty.Map(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ map_field = {
|
|
|
|
+ "b" = "bbbb"
|
|
|
|
# (2 unchanged elements hidden)
|
|
|
|
}
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2018-12-11 12:50:08 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ map_field = {
|
|
|
|
"a" = "aaaa"
|
|
|
|
+ "b" = "bbbb"
|
|
|
|
"c" = "cccc"
|
|
|
|
}
|
|
|
|
}
|
2018-12-11 12:55:59 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"force-new update - insertion": {
|
|
|
|
Action: plans.DeleteThenCreate,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"map_field": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.StringVal("aaaa"),
|
|
|
|
"c": cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"map_field": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.StringVal("aaaa"),
|
|
|
|
"b": cty.StringVal("bbbb"),
|
|
|
|
"c": cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"map_field": {Type: cty.Map(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(cty.Path{
|
|
|
|
cty.GetAttrStep{Name: "map_field"},
|
|
|
|
}),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:55:59 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example must be replaced
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ map_field = { # forces replacement
|
|
|
|
+ "b" = "bbbb"
|
|
|
|
# (2 unchanged elements hidden)
|
|
|
|
}
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example must be replaced
|
2018-12-11 12:55:59 +01:00
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ map_field = { # forces replacement
|
|
|
|
"a" = "aaaa"
|
|
|
|
+ "b" = "bbbb"
|
|
|
|
"c" = "cccc"
|
|
|
|
}
|
|
|
|
}
|
2018-12-11 12:50:08 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - deletion": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"map_field": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.StringVal("aaaa"),
|
|
|
|
"b": cty.StringVal("bbbb"),
|
|
|
|
"c": cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"map_field": cty.MapVal(map[string]cty.Value{
|
|
|
|
"b": cty.StringVal("bbbb"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"map_field": {Type: cty.Map(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ map_field = {
|
|
|
|
- "a" = "aaaa" -> null
|
|
|
|
- "c" = "cccc" -> null
|
|
|
|
# (1 unchanged element hidden)
|
|
|
|
}
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2018-12-11 12:50:08 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ map_field = {
|
|
|
|
- "a" = "aaaa" -> null
|
|
|
|
"b" = "bbbb"
|
|
|
|
- "c" = "cccc" -> null
|
|
|
|
}
|
|
|
|
}
|
2019-01-14 16:15:01 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"creation - empty": {
|
|
|
|
Action: plans.Create,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.NullVal(cty.EmptyObject),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"map_field": cty.MapValEmpty(cty.String),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"map_field": {Type: cty.Map(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-14 16:15:01 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be created
|
|
|
|
+ resource "test_instance" "example" {
|
|
|
|
+ ami = "ami-STATIC"
|
|
|
|
+ id = (known after apply)
|
|
|
|
+ map_field = {}
|
|
|
|
}
|
2019-01-21 16:02:51 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"update to unknown element": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"map_field": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.StringVal("aaaa"),
|
|
|
|
"b": cty.StringVal("bbbb"),
|
|
|
|
"c": cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"ami": cty.StringVal("ami-STATIC"),
|
|
|
|
"map_field": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.StringVal("aaaa"),
|
|
|
|
"b": cty.UnknownVal(cty.String),
|
|
|
|
"c": cty.StringVal("cccc"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
"map_field": {Type: cty.Map(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-21 16:02:51 +01:00
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ map_field = {
|
|
|
|
~ "b" = "bbbb" -> (known after apply)
|
|
|
|
# (2 unchanged elements hidden)
|
|
|
|
}
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
2019-01-21 16:02:51 +01:00
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
ami = "ami-STATIC"
|
|
|
|
~ id = "i-02ae66f368e8518a9" -> (known after apply)
|
|
|
|
~ map_field = {
|
|
|
|
"a" = "aaaa"
|
|
|
|
~ "b" = "bbbb" -> (known after apply)
|
|
|
|
"c" = "cccc"
|
|
|
|
}
|
|
|
|
}
|
2018-12-11 12:50:08 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
runTestCases(t, testCases)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestResourceChange_nestedList(t *testing.T) {
|
|
|
|
testCases := map[string]testCase{
|
2018-12-11 13:56:11 +01:00
|
|
|
"in-place update - equal": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.ListVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.ListVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 13:56:11 +01:00
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2018-12-12 15:28:12 +01:00
|
|
|
Nesting: configschema.NestingList,
|
2018-12-11 13:56:11 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
# (1 unchanged block hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
2018-12-11 13:56:11 +01:00
|
|
|
root_block_device {
|
|
|
|
volume_type = "gp2"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
2018-12-11 12:50:08 +01:00
|
|
|
"in-place update - creation": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
2019-03-09 21:14:08 +01:00
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.ListValEmpty(cty.Object(map[string]cty.Type{
|
|
|
|
"volume_type": cty.String,
|
|
|
|
})),
|
2018-12-11 12:50:08 +01:00
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.ListVal([]cty.Value{
|
2019-01-14 17:07:04 +01:00
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2019-01-14 17:07:04 +01:00
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Nesting: configschema.NestingList,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
|
|
|
+ root_block_device {}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - first insertion": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
2019-03-09 21:14:08 +01:00
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.ListValEmpty(cty.Object(map[string]cty.Type{
|
|
|
|
"volume_type": cty.String,
|
|
|
|
})),
|
2019-01-14 17:07:04 +01:00
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.ListVal([]cty.Value{
|
2018-12-11 12:50:08 +01:00
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2018-12-12 15:28:12 +01:00
|
|
|
Nesting: configschema.NestingList,
|
2018-12-11 12:50:08 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
|
|
|
+ root_block_device {
|
|
|
|
+ volume_type = "gp2"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - insertion": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.ListVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
"new_field": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.ListVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
"new_field": cty.StringVal("new_value"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"new_field": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2018-12-12 15:28:12 +01:00
|
|
|
Nesting: configschema.NestingList,
|
2018-12-11 12:50:08 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ root_block_device {
|
|
|
|
+ new_field = "new_value"
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
2018-12-11 12:50:08 +01:00
|
|
|
~ root_block_device {
|
|
|
|
+ new_field = "new_value"
|
|
|
|
volume_type = "gp2"
|
|
|
|
}
|
|
|
|
}
|
2018-12-11 12:55:59 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"force-new update (inside block)": {
|
|
|
|
Action: plans.DeleteThenCreate,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.ListVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.ListVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("different"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(cty.Path{
|
|
|
|
cty.GetAttrStep{Name: "root_block_device"},
|
|
|
|
cty.IndexStep{Key: cty.NumberIntVal(0)},
|
|
|
|
cty.GetAttrStep{Name: "volume_type"},
|
|
|
|
}),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:55:59 +01:00
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2018-12-12 15:28:12 +01:00
|
|
|
Nesting: configschema.NestingList,
|
2018-12-11 12:55:59 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example must be replaced
|
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
|
|
|
~ root_block_device {
|
|
|
|
~ volume_type = "gp2" -> "different" # forces replacement
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"force-new update (whole block)": {
|
|
|
|
Action: plans.DeleteThenCreate,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.ListVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.ListVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("different"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(cty.Path{
|
|
|
|
cty.GetAttrStep{Name: "root_block_device"},
|
|
|
|
}),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:55:59 +01:00
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2018-12-12 15:28:12 +01:00
|
|
|
Nesting: configschema.NestingList,
|
2018-12-11 12:55:59 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example must be replaced
|
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
|
|
|
~ root_block_device { # forces replacement
|
|
|
|
~ volume_type = "gp2" -> "different"
|
|
|
|
}
|
|
|
|
}
|
2018-12-11 12:50:08 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - deletion": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.ListVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
"new_field": cty.StringVal("new_value"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
2019-03-09 21:14:08 +01:00
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.ListValEmpty(cty.Object(map[string]cty.Type{
|
|
|
|
"volume_type": cty.String,
|
|
|
|
"new_field": cty.String,
|
|
|
|
})),
|
2018-12-11 12:50:08 +01:00
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"new_field": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2018-12-12 15:28:12 +01:00
|
|
|
Nesting: configschema.NestingList,
|
2018-12-11 12:50:08 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
|
|
|
- root_block_device {
|
|
|
|
- new_field = "new_value" -> null
|
|
|
|
- volume_type = "gp2" -> null
|
|
|
|
}
|
|
|
|
}
|
2019-03-09 21:14:08 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"with dynamically-typed attribute": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"block": cty.EmptyTupleVal,
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"block": cty.TupleVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"attr": cty.StringVal("foo"),
|
|
|
|
}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"attr": cty.True,
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
|
|
|
Tainted: false,
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"block": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"attr": {Type: cty.DynamicPseudoType, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Nesting: configschema.NestingList,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
+ block {
|
|
|
|
+ attr = "foo"
|
|
|
|
}
|
|
|
|
+ block {
|
|
|
|
+ attr = true
|
|
|
|
}
|
|
|
|
}
|
2018-12-11 12:50:08 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
runTestCases(t, testCases)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestResourceChange_nestedSet(t *testing.T) {
|
|
|
|
testCases := map[string]testCase{
|
|
|
|
"in-place update - creation": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
2019-03-09 21:14:08 +01:00
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.SetValEmpty(cty.Object(map[string]cty.Type{
|
|
|
|
"volume_type": cty.String,
|
|
|
|
})),
|
2018-12-11 12:50:08 +01:00
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.SetVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2018-12-12 15:28:12 +01:00
|
|
|
Nesting: configschema.NestingSet,
|
2018-12-11 12:50:08 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
|
|
|
+ root_block_device {
|
|
|
|
+ volume_type = "gp2"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - insertion": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.SetVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
"new_field": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.SetVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
"new_field": cty.StringVal("new_value"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"new_field": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2018-12-12 15:28:12 +01:00
|
|
|
Nesting: configschema.NestingSet,
|
2018-12-11 12:50:08 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
2018-12-12 15:28:12 +01:00
|
|
|
+ root_block_device {
|
|
|
|
+ new_field = "new_value"
|
|
|
|
+ volume_type = "gp2"
|
2018-12-11 12:55:59 +01:00
|
|
|
}
|
2019-05-01 00:29:47 +02:00
|
|
|
- root_block_device {
|
|
|
|
- volume_type = "gp2" -> null
|
|
|
|
}
|
2018-12-11 12:55:59 +01:00
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"force-new update (whole block)": {
|
|
|
|
Action: plans.DeleteThenCreate,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.SetVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.SetVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("different"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(cty.Path{
|
|
|
|
cty.GetAttrStep{Name: "root_block_device"},
|
|
|
|
}),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:55:59 +01:00
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2018-12-12 15:28:12 +01:00
|
|
|
Nesting: configschema.NestingSet,
|
2018-12-11 12:55:59 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example must be replaced
|
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
2018-12-12 15:28:12 +01:00
|
|
|
+ root_block_device { # forces replacement
|
|
|
|
+ volume_type = "different"
|
2018-12-11 12:55:59 +01:00
|
|
|
}
|
2019-05-01 00:29:47 +02:00
|
|
|
- root_block_device { # forces replacement
|
|
|
|
- volume_type = "gp2" -> null
|
|
|
|
}
|
2018-12-11 12:55:59 +01:00
|
|
|
}
|
2018-12-11 12:50:08 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - deletion": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.SetVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
"new_field": cty.StringVal("new_value"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
2019-03-09 21:14:08 +01:00
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.SetValEmpty(cty.Object(map[string]cty.Type{
|
|
|
|
"volume_type": cty.String,
|
|
|
|
"new_field": cty.String,
|
|
|
|
})),
|
2018-12-11 12:50:08 +01:00
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted: false,
|
2018-12-11 12:50:08 +01:00
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"new_field": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2018-12-12 15:28:12 +01:00
|
|
|
Nesting: configschema.NestingSet,
|
2018-12-11 12:50:08 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
|
|
|
- root_block_device {
|
|
|
|
- new_field = "new_value" -> null
|
|
|
|
- volume_type = "gp2" -> null
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
runTestCases(t, testCases)
|
|
|
|
}
|
|
|
|
|
2019-03-09 21:30:23 +01:00
|
|
|
func TestResourceChange_nestedMap(t *testing.T) {
|
|
|
|
testCases := map[string]testCase{
|
|
|
|
"in-place update - creation": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.MapValEmpty(cty.Object(map[string]cty.Type{
|
|
|
|
"volume_type": cty.String,
|
|
|
|
})),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
|
|
|
Tainted: false,
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Nesting: configschema.NestingMap,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
|
|
|
+ root_block_device "a" {
|
|
|
|
+ volume_type = "gp2"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - change attr": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
"new_field": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
"new_field": cty.StringVal("new_value"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
|
|
|
Tainted: false,
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"new_field": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Nesting: configschema.NestingMap,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ root_block_device "a" {
|
|
|
|
+ new_field = "new_value"
|
|
|
|
# (1 unchanged attribute hidden)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
2019-03-09 21:30:23 +01:00
|
|
|
~ root_block_device "a" {
|
|
|
|
+ new_field = "new_value"
|
|
|
|
volume_type = "gp2"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - insertion": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
"new_field": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
"new_field": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
"b": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
"new_field": cty.StringVal("new_value"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
|
|
|
Tainted: false,
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"new_field": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Nesting: configschema.NestingMap,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
+ root_block_device "b" {
|
|
|
|
+ new_field = "new_value"
|
|
|
|
+ volume_type = "gp2"
|
|
|
|
}
|
|
|
|
# (1 unchanged block hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
2019-03-09 21:30:23 +01:00
|
|
|
root_block_device "a" {
|
|
|
|
volume_type = "gp2"
|
|
|
|
}
|
|
|
|
+ root_block_device "b" {
|
|
|
|
+ new_field = "new_value"
|
|
|
|
+ volume_type = "gp2"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"force-new update (whole block)": {
|
|
|
|
Action: plans.DeleteThenCreate,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
}),
|
|
|
|
"b": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("standard"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("different"),
|
|
|
|
}),
|
|
|
|
"b": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("standard"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(cty.Path{
|
|
|
|
cty.GetAttrStep{Name: "root_block_device"},
|
|
|
|
cty.IndexStep{Key: cty.StringVal("a")},
|
|
|
|
}),
|
|
|
|
Tainted: false,
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Nesting: configschema.NestingMap,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example must be replaced
|
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
~ root_block_device "a" { # forces replacement
|
|
|
|
~ volume_type = "gp2" -> "different"
|
|
|
|
}
|
|
|
|
# (1 unchanged block hidden)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
VerboseOutput: ` # test_instance.example must be replaced
|
|
|
|
-/+ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
2019-03-09 21:30:23 +01:00
|
|
|
~ root_block_device "a" { # forces replacement
|
|
|
|
~ volume_type = "gp2" -> "different"
|
|
|
|
}
|
|
|
|
root_block_device "b" {
|
|
|
|
volume_type = "standard"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place update - deletion": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
"new_field": cty.StringVal("new_value"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.MapValEmpty(cty.Object(map[string]cty.Type{
|
|
|
|
"volume_type": cty.String,
|
|
|
|
"new_field": cty.String,
|
|
|
|
})),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
|
|
|
Tainted: false,
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"new_field": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Nesting: configschema.NestingMap,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = "ami-BEFORE" -> "ami-AFTER"
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
|
|
|
- root_block_device "a" {
|
|
|
|
- new_field = "new_value" -> null
|
|
|
|
- volume_type = "gp2" -> null
|
|
|
|
}
|
|
|
|
}
|
2019-04-27 17:23:37 +02:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
"in-place sequence update - deletion": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"list": cty.ListVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{"attr": cty.StringVal("x")}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{"attr": cty.StringVal("y")}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"list": cty.ListVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{"attr": cty.StringVal("y")}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{"attr": cty.StringVal("z")}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
|
|
|
Tainted: false,
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"list": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"attr": {
|
|
|
|
Type: cty.String,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Nesting: configschema.NestingList,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ list {
|
|
|
|
~ attr = "x" -> "y"
|
|
|
|
}
|
|
|
|
~ list {
|
|
|
|
~ attr = "y" -> "z"
|
|
|
|
}
|
|
|
|
}
|
2019-03-09 21:30:23 +01:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
runTestCases(t, testCases)
|
|
|
|
}
|
|
|
|
|
2020-09-10 22:45:31 +02:00
|
|
|
func TestResourceChange_sensitiveVariable(t *testing.T) {
|
|
|
|
testCases := map[string]testCase{
|
|
|
|
"in-place update - creation": {
|
|
|
|
Action: plans.Update,
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-BEFORE"),
|
|
|
|
"root_block_device": cty.MapValEmpty(cty.Object(map[string]cty.Type{
|
|
|
|
"volume_type": cty.String,
|
|
|
|
})),
|
|
|
|
}),
|
|
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("i-02ae66f368e8518a9"),
|
|
|
|
"ami": cty.StringVal("ami-AFTER"),
|
|
|
|
"root_block_device": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"volume_type": cty.StringVal("gp2"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
AfterValMarks: []cty.PathValueMarks{
|
|
|
|
{
|
|
|
|
Path: cty.Path{cty.GetAttrStep{Name: "ami"}},
|
|
|
|
Marks: cty.NewValueMarks("sensitive"),
|
|
|
|
}},
|
|
|
|
RequiredReplace: cty.NewPathSet(),
|
|
|
|
Tainted: false,
|
|
|
|
Schema: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Optional: true, Computed: true},
|
|
|
|
"ami": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"root_block_device": {
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"volume_type": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Nesting: configschema.NestingMap,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ExpectedOutput: ` # test_instance.example will be updated in-place
|
|
|
|
~ resource "test_instance" "example" {
|
|
|
|
~ ami = (sensitive)
|
|
|
|
id = "i-02ae66f368e8518a9"
|
|
|
|
|
|
|
|
+ root_block_device "a" {
|
|
|
|
+ volume_type = "gp2"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
runTestCases(t, testCases)
|
|
|
|
}
|
|
|
|
|
2018-12-11 12:49:17 +01:00
|
|
|
type testCase struct {
|
|
|
|
Action plans.Action
|
|
|
|
Mode addrs.ResourceMode
|
|
|
|
Before cty.Value
|
2020-09-10 22:45:31 +02:00
|
|
|
BeforeValMarks []cty.PathValueMarks
|
|
|
|
AfterValMarks []cty.PathValueMarks
|
2018-12-11 12:49:17 +01:00
|
|
|
After cty.Value
|
|
|
|
Schema *configschema.Block
|
|
|
|
RequiredReplace cty.PathSet
|
2019-03-06 01:18:55 +01:00
|
|
|
Tainted bool
|
2018-12-11 12:49:17 +01:00
|
|
|
ExpectedOutput string
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
|
|
|
|
// This field and all associated values can be removed if the concise diff
|
|
|
|
// experiment succeeds.
|
|
|
|
VerboseOutput string
|
2018-12-11 12:49:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func runTestCases(t *testing.T, testCases map[string]testCase) {
|
2018-12-10 18:42:45 +01:00
|
|
|
color := &colorstring.Colorize{Colors: colorstring.DefaultColors, Disable: true}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
2019-03-09 21:14:08 +01:00
|
|
|
ty := tc.Schema.ImpliedType()
|
|
|
|
|
2018-12-10 18:42:45 +01:00
|
|
|
beforeVal := tc.Before
|
2019-03-09 21:14:08 +01:00
|
|
|
switch { // Some fixups to make the test cases a little easier to write
|
|
|
|
case beforeVal.IsNull():
|
|
|
|
beforeVal = cty.NullVal(ty) // allow mistyped nulls
|
|
|
|
case !beforeVal.IsKnown():
|
|
|
|
beforeVal = cty.UnknownVal(ty) // allow mistyped unknowns
|
|
|
|
}
|
|
|
|
before, err := plans.NewDynamicValue(beforeVal, ty)
|
2018-12-10 18:42:45 +01:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
afterVal := tc.After
|
2019-03-09 21:14:08 +01:00
|
|
|
switch { // Some fixups to make the test cases a little easier to write
|
|
|
|
case afterVal.IsNull():
|
|
|
|
afterVal = cty.NullVal(ty) // allow mistyped nulls
|
|
|
|
case !afterVal.IsKnown():
|
|
|
|
afterVal = cty.UnknownVal(ty) // allow mistyped unknowns
|
|
|
|
}
|
|
|
|
after, err := plans.NewDynamicValue(afterVal, ty)
|
2018-12-10 18:42:45 +01:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
change := &plans.ResourceInstanceChangeSrc{
|
|
|
|
Addr: addrs.Resource{
|
|
|
|
Mode: tc.Mode,
|
|
|
|
Type: "test_instance",
|
|
|
|
Name: "example",
|
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
2020-02-13 21:32:58 +01:00
|
|
|
ProviderAddr: addrs.AbsProviderConfig{
|
|
|
|
Provider: addrs.NewLegacyProvider("test"),
|
2020-03-11 19:19:52 +01:00
|
|
|
Module: addrs.RootModule,
|
2020-02-13 21:32:58 +01:00
|
|
|
},
|
2018-12-10 18:42:45 +01:00
|
|
|
ChangeSrc: plans.ChangeSrc{
|
2020-09-10 22:45:31 +02:00
|
|
|
Action: tc.Action,
|
|
|
|
Before: before,
|
|
|
|
After: after,
|
|
|
|
BeforeValMarks: tc.BeforeValMarks,
|
|
|
|
AfterValMarks: tc.AfterValMarks,
|
2018-12-10 18:42:45 +01:00
|
|
|
},
|
|
|
|
RequiredReplace: tc.RequiredReplace,
|
|
|
|
}
|
|
|
|
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
experiment.SetEnabled(experiment.X_concise_diff, true)
|
2019-03-06 01:18:55 +01:00
|
|
|
output := ResourceChange(change, tc.Tainted, tc.Schema, color)
|
2018-12-10 18:42:45 +01:00
|
|
|
if output != tc.ExpectedOutput {
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
t.Errorf("Unexpected diff.\ngot:\n%s\nwant:\n%s\n", output, tc.ExpectedOutput)
|
|
|
|
t.Errorf("%s", cmp.Diff(output, tc.ExpectedOutput))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Temporary coverage for verbose diff behaviour. All lines below
|
|
|
|
// in this function can be removed if the concise diff experiment
|
|
|
|
// succeeds.
|
|
|
|
if tc.VerboseOutput == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
experiment.SetEnabled(experiment.X_concise_diff, false)
|
|
|
|
output = ResourceChange(change, tc.Tainted, tc.Schema, color)
|
|
|
|
if output != tc.VerboseOutput {
|
|
|
|
t.Errorf("Unexpected diff.\ngot:\n%s\nwant:\n%s\n", output, tc.VerboseOutput)
|
|
|
|
t.Errorf("%s", cmp.Diff(output, tc.VerboseOutput))
|
2018-12-10 18:42:45 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2020-09-04 22:03:48 +02:00
|
|
|
|
|
|
|
func TestOutputChanges(t *testing.T) {
|
|
|
|
color := &colorstring.Colorize{Colors: colorstring.DefaultColors, Disable: true}
|
|
|
|
|
|
|
|
testCases := map[string]struct {
|
|
|
|
changes []*plans.OutputChangeSrc
|
|
|
|
output string
|
|
|
|
}{
|
|
|
|
"new output value": {
|
|
|
|
[]*plans.OutputChangeSrc{
|
|
|
|
outputChange(
|
|
|
|
"foo",
|
|
|
|
cty.NullVal(cty.DynamicPseudoType),
|
|
|
|
cty.StringVal("bar"),
|
|
|
|
false,
|
|
|
|
),
|
|
|
|
},
|
|
|
|
`
|
|
|
|
+ foo = "bar"`,
|
|
|
|
},
|
|
|
|
"removed output": {
|
|
|
|
[]*plans.OutputChangeSrc{
|
|
|
|
outputChange(
|
|
|
|
"foo",
|
|
|
|
cty.StringVal("bar"),
|
|
|
|
cty.NullVal(cty.DynamicPseudoType),
|
|
|
|
false,
|
|
|
|
),
|
|
|
|
},
|
|
|
|
`
|
|
|
|
- foo = "bar" -> null`,
|
|
|
|
},
|
|
|
|
"single string change": {
|
|
|
|
[]*plans.OutputChangeSrc{
|
|
|
|
outputChange(
|
|
|
|
"foo",
|
|
|
|
cty.StringVal("bar"),
|
|
|
|
cty.StringVal("baz"),
|
|
|
|
false,
|
|
|
|
),
|
|
|
|
},
|
|
|
|
`
|
|
|
|
~ foo = "bar" -> "baz"`,
|
|
|
|
},
|
|
|
|
"element added to list": {
|
|
|
|
[]*plans.OutputChangeSrc{
|
|
|
|
outputChange(
|
|
|
|
"foo",
|
|
|
|
cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("alpha"),
|
|
|
|
cty.StringVal("beta"),
|
|
|
|
cty.StringVal("delta"),
|
|
|
|
cty.StringVal("epsilon"),
|
|
|
|
}),
|
|
|
|
cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("alpha"),
|
|
|
|
cty.StringVal("beta"),
|
|
|
|
cty.StringVal("gamma"),
|
|
|
|
cty.StringVal("delta"),
|
|
|
|
cty.StringVal("epsilon"),
|
|
|
|
}),
|
|
|
|
false,
|
|
|
|
),
|
|
|
|
},
|
|
|
|
`
|
|
|
|
~ foo = [
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
# (1 unchanged element hidden)
|
2020-09-04 22:03:48 +02:00
|
|
|
"beta",
|
|
|
|
+ "gamma",
|
|
|
|
"delta",
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
# (1 unchanged element hidden)
|
2020-09-04 22:03:48 +02:00
|
|
|
]`,
|
|
|
|
},
|
|
|
|
"multiple outputs changed, one sensitive": {
|
|
|
|
[]*plans.OutputChangeSrc{
|
|
|
|
outputChange(
|
|
|
|
"a",
|
|
|
|
cty.NumberIntVal(1),
|
|
|
|
cty.NumberIntVal(2),
|
|
|
|
false,
|
|
|
|
),
|
|
|
|
outputChange(
|
|
|
|
"b",
|
|
|
|
cty.StringVal("hunter2"),
|
|
|
|
cty.StringVal("correct-horse-battery-staple"),
|
|
|
|
true,
|
|
|
|
),
|
|
|
|
outputChange(
|
|
|
|
"c",
|
|
|
|
cty.BoolVal(false),
|
|
|
|
cty.BoolVal(true),
|
|
|
|
false,
|
|
|
|
),
|
|
|
|
},
|
|
|
|
`
|
|
|
|
~ a = 1 -> 2
|
|
|
|
~ b = (sensitive value)
|
|
|
|
~ c = false -> true`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
command: Add experimental concise diff renderer
When rendering a diff between current state and projected state, we only
show resources and outputs which have changes. However, we show a full
structural diff for these values, which includes all attributes and
blocks for a changed resource or output. The result can be a very long
diff, which makes it difficult to verify what the changed fields are.
This commit adds an experimental concise diff renderer, which suppresses
most unchanged fields, only displaying the most relevant changes and
some identifying context. This means:
- Always show all identifying attributes, initially defined as `id`,
`name`, and `tags`, even if unchanged;
- Only show changed, added, or removed primitive values: `string`,
`number`, or `bool`;
- Only show added or removed elements in unordered collections and
structural types: `map`, `set`, and `object`;
- Show added or removed elements with any surrounding unchanged elements
for sequence types: `list` and `tuple`;
- Only show added or removed nested blocks, or blocks with changed
attributes.
If any attributes, collection elements, or blocks are hidden, a count
is kept and displayed at the end of the parent scope. This ensures that
it is clear that the diff is only displaying a subset of the resource.
The experiment is currently enabled by default, but can be disabled by
setting the TF_X_CONCISE_DIFF environment variable to 0.
2020-08-19 22:47:56 +02:00
|
|
|
experiment.SetEnabled(experiment.X_concise_diff, true)
|
2020-09-04 22:03:48 +02:00
|
|
|
output := OutputChanges(tc.changes, color)
|
|
|
|
if output != tc.output {
|
|
|
|
t.Errorf("Unexpected diff.\ngot:\n%s\nwant:\n%s\n", output, tc.output)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func outputChange(name string, before, after cty.Value, sensitive bool) *plans.OutputChangeSrc {
|
|
|
|
addr := addrs.AbsOutputValue{
|
|
|
|
OutputValue: addrs.OutputValue{Name: name},
|
|
|
|
}
|
|
|
|
|
|
|
|
change := &plans.OutputChange{
|
|
|
|
Addr: addr, Change: plans.Change{
|
|
|
|
Before: before,
|
|
|
|
After: after,
|
|
|
|
},
|
|
|
|
Sensitive: sensitive,
|
|
|
|
}
|
|
|
|
|
|
|
|
changeSrc, err := change.Encode()
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Sprintf("failed to encode change for %s: %s", addr, err))
|
|
|
|
}
|
|
|
|
|
|
|
|
return changeSrc
|
|
|
|
}
|