diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9538ae5..c3c4c6b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ jobs: timeout-minutes: 3 steps: - name: Checkout Repo - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # https://github.com/actions/checkout/releases/tag/v3.5.3 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # https://github.com/actions/checkout/releases/tag/v4.1.1 - name: Install copywrite uses: hashicorp/setup-copywrite@v1.1.2 - name: Validate Header Compliance @@ -41,9 +41,9 @@ jobs: - "1.20" steps: - name: Checkout - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # https://github.com/actions/checkout/releases/tag/v3.5.3 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # https://github.com/actions/checkout/releases/tag/v4.1.1 - name: Set up Go - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # https://github.com/actions/setup-go/releases/tag/v4.0.1 + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # https://github.com/actions/setup-go/releases/tag/v4.1.0 with: go-version: ${{ matrix.go }} - name: Go mod download diff --git a/README.md b/README.md index 4a9cd94..462c1a8 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,39 @@ This repository also serves as de facto documentation for the formats produced by these commands. For more details, see the [GoDoc](https://godoc.org/github.com/hashicorp/terraform-json). -## Why a Separate Repository? +## Should I use this library? + +This library was built for a few specific applications, and is not intended for +general purpose use. + +The Terraform core team **recommends against** using `terraform-json` if your +application has any of the following requirements: + +* **Forward-compatibility**: each version of this library represents a specific + snapshot of the [Terraform JSON output format](https://developer.hashicorp.com/terraform/internals/json-format), + and it often slightly lags behind Terraform itself. The library supports + [the 1.x compatibility promises](https://developer.hashicorp.com/terraform/language/v1-compatibility-promises) + but you will need to upgrade the version promptly to use new additions. If you + require full compatibility with future Terraform versions, we recommend + implementing your own custom decoders for the parts of the JSON format you need. +* **Writing JSON output**: the structures in this library are not guaranteed to emit + JSON data which is semantically equivalent to Terraform itself. If your application + must robustly write JSON data to be consumed by systems which expect Terraform's + format to be supported, you should implement your own custom encoders. +* **Filtering or round-tripping**: the Terraform JSON formats are designed to be + forwards compatible, and permit new attributes to be added which may safely be + ignored by earlier versions of consumers. This library **drops unknown attributes**, + which means it is unsuitable for any application which intends to filter data + or read-modify-write data which will be consumed downstream. Any application doing + this will silently drop new data from new versions. For this application, you should + implement a custom decoder and encoder which preserves any unknown attributes + through a round-trip. + +When is `terraform-json` suitable? We recommend using it for applications which +decode the core stable data types and use it directly, and don't attempt to emit +JSON to be consumed by applications which expect the Terraform format. + +## Why a separate repository? To reduce dependencies on any of Terraform core's internals, we've made a design decision to make any helpers or libraries that work with the external JSON data diff --git a/go.mod b/go.mod index 1afbb21..dba92f9 100644 --- a/go.mod +++ b/go.mod @@ -4,16 +4,16 @@ go 1.18 require ( github.com/davecgh/go-spew v1.1.1 - github.com/google/go-cmp v0.5.9 + github.com/google/go-cmp v0.6.0 github.com/hashicorp/go-version v1.6.0 github.com/mitchellh/copystructure v1.2.0 github.com/sebdah/goldie v1.0.0 - github.com/zclconf/go-cty v1.13.2 + github.com/zclconf/go-cty v1.14.1 github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b ) require ( - github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect + github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect - golang.org/x/text v0.3.8 // indirect + golang.org/x/text v0.11.0 // indirect ) diff --git a/go.sum b/go.sum index dd44634..2c27248 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,13 @@ github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= -github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= -github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= +github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= +github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -27,14 +27,14 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= -github.com/zclconf/go-cty v1.13.2 h1:4GvrUxe/QUDYuJKAav4EYqdM47/kZa672LwmXFmEKT0= -github.com/zclconf/go-cty v1.13.2/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0= +github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA= +github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/parse_test.go b/parse_test.go index 137d475..79c9a66 100644 --- a/parse_test.go +++ b/parse_test.go @@ -31,12 +31,6 @@ func testParse(t *testing.T, filename string, typ reflect.Type) { continue } - // Skip this directory as this is a unique test that only tests a subset - // of attributes for a plan. The fixture is not entirely valid, but that's okay. - if e.Name() == "has_checks" { - continue - } - t.Run(e.Name(), func(t *testing.T) { expected, err := ioutil.ReadFile(filepath.Join(testFixtureDir, e.Name(), filename)) if err != nil { diff --git a/plan.go b/plan.go index de529ac..b6583c0 100644 --- a/plan.go +++ b/plan.go @@ -144,6 +144,10 @@ type ResourceChange struct { // The absolute resource address. Address string `json:"address,omitempty"` + // The absolute address that this resource instance had + // at the conclusion of a previous plan. + PreviousAddress string `json:"previous_address,omitempty"` + // The module portion of the above address. Omitted if the instance // is in the root module. ModuleAddress string `json:"module_address,omitempty"` diff --git a/plan_test.go b/plan_test.go index 035cd4a..2f9b37c 100644 --- a/plan_test.go +++ b/plan_test.go @@ -99,3 +99,24 @@ func TestPlan_withChecks(t *testing.T) { } } } + +func TestPlan_movedBlock(t *testing.T) { + f, err := os.Open("testdata/moved_block/plan.json") + if err != nil { + t.Fatal(err) + } + defer f.Close() + + var plan *Plan + if err := json.NewDecoder(f).Decode(&plan); err != nil { + t.Fatal(err) + } + + if err := plan.Validate(); err != nil { + t.Fatal(err) + } + + if plan.ResourceChanges[0].PreviousAddress != "random_id.test" { + t.Fatalf("unexpected previous address %s, expected is random_id.test", plan.ResourceChanges[0].PreviousAddress) + } +} diff --git a/state.go b/state.go index 0f2a999..e533632 100644 --- a/state.go +++ b/state.go @@ -38,7 +38,7 @@ type State struct { // Checks contains the results of any conditional checks when Values was // last updated. - Checks *CheckResultStatic `json:"checks,omitempty"` + Checks []CheckResultStatic `json:"checks,omitempty"` } // UseJSONNumber controls whether the State will be decoded using the diff --git a/testdata/has_checks/child_moodule/main.tf b/testdata/has_checks/child_moodule/main.tf new file mode 100644 index 0000000..e961d4b --- /dev/null +++ b/testdata/has_checks/child_moodule/main.tf @@ -0,0 +1,20 @@ +variable "file_names" { + type = set(string) + default = [ + "file1.txt", + ] +} + +resource "local_file" "foo" { + for_each = var.file_names + content = "Hello, World!" + filename = each.value + + lifecycle { + postcondition { + condition = self.content == "Hello, World!" + error_message = "File content is not correct" + } + } +} + diff --git a/testdata/has_checks/main.tf b/testdata/has_checks/main.tf new file mode 100644 index 0000000..d121ed7 --- /dev/null +++ b/testdata/has_checks/main.tf @@ -0,0 +1,4 @@ +module "files" { + source = "./child_module" + file_names = ["file1.txt", "file2.txt"] +} \ No newline at end of file diff --git a/testdata/has_checks/plan.json b/testdata/has_checks/plan.json index 4c45605..896e59b 100644 --- a/testdata/has_checks/plan.json +++ b/testdata/has_checks/plan.json @@ -1 +1 @@ -{"format_version":"1.1","terraform_version":"1.5.0","planned_values":{"root_module":{"resources":[{"address":"null_resource.foo","mode":"managed","type":"null_resource","name":"foo","provider_name":"registry.terraform.io/hashicorp/null","schema_version":0,"values":{"triggers":null},"sensitive_values":{}}]}},"resource_changes":[{"address":"null_resource.foo","mode":"managed","type":"null_resource","name":"foo","provider_name":"registry.terraform.io/hashicorp/null","change":{"actions":["create"],"before":null,"after":{"triggers":null},"after_unknown":{"id":true},"before_sensitive":false,"after_sensitive":{}}}],"configuration":{"provider_config":{"null":{"name":"null","full_name":"registry.terraform.io/hashicorp/null"}},"root_module":{"resources":[{"address":"null_resource.foo","mode":"managed","type":"null_resource","name":"foo","provider_config_key":"null","schema_version":0}]}},"checks":[{"//":"EXPERIMENTAL: see docs for details","address":{"kind":"resource","mode":"managed","module":"module.foo.module.bar","name":"this","to_display":"module.foo.module.bar.foobar.this","type":"foobar"},"status":"pass","instances":[{"address":{"instance_key":0,"module":"module.foo.module.bar","to_display":"module.foo.module.bar.foobar.this[0]"},"status":"pass"}]},{"//":"EXPERIMENTAL: see docs for details","address":{"kind":"resource","mode":"managed","module":"module.foo.module.bar","name":"this","to_display":"module.foo.module.bar.foobar.this","type":"foobar"},"status":"pass"}]} +{"format_version":"1.2","terraform_version":"1.5.4","planned_values":{"root_module":{"child_modules":[{"resources":[{"address":"module.files.local_file.foo[\"file1.txt\"]","mode":"managed","type":"local_file","name":"foo","index":"file1.txt","provider_name":"registry.terraform.io/hashicorp/local","schema_version":0,"values":{"content":"Hello, World!","content_base64":null,"directory_permission":"0777","file_permission":"0777","filename":"file1.txt","sensitive_content":null,"source":null},"sensitive_values":{}},{"address":"module.files.local_file.foo[\"file2.txt\"]","mode":"managed","type":"local_file","name":"foo","index":"file2.txt","provider_name":"registry.terraform.io/hashicorp/local","schema_version":0,"values":{"content":"Hello, World!","content_base64":null,"directory_permission":"0777","file_permission":"0777","filename":"file2.txt","sensitive_content":null,"source":null},"sensitive_values":{}}],"address":"module.files"}]}},"resource_changes":[{"address":"module.files.local_file.foo[\"file1.txt\"]","module_address":"module.files","mode":"managed","type":"local_file","name":"foo","index":"file1.txt","provider_name":"registry.terraform.io/hashicorp/local","change":{"actions":["create"],"before":null,"after":{"content":"Hello, World!","content_base64":null,"directory_permission":"0777","file_permission":"0777","filename":"file1.txt","sensitive_content":null,"source":null},"after_unknown":{"content_base64sha256":true,"content_base64sha512":true,"content_md5":true,"content_sha1":true,"content_sha256":true,"content_sha512":true,"id":true},"before_sensitive":false,"after_sensitive":{"sensitive_content":true}}},{"address":"module.files.local_file.foo[\"file2.txt\"]","module_address":"module.files","mode":"managed","type":"local_file","name":"foo","index":"file2.txt","provider_name":"registry.terraform.io/hashicorp/local","change":{"actions":["create"],"before":null,"after":{"content":"Hello, World!","content_base64":null,"directory_permission":"0777","file_permission":"0777","filename":"file2.txt","sensitive_content":null,"source":null},"after_unknown":{"content_base64sha256":true,"content_base64sha512":true,"content_md5":true,"content_sha1":true,"content_sha256":true,"content_sha512":true,"id":true},"before_sensitive":false,"after_sensitive":{"sensitive_content":true}}}],"configuration":{"provider_config":{"module.files:local":{"name":"local","full_name":"registry.terraform.io/hashicorp/local","module_address":"module.files"}},"root_module":{"module_calls":{"files":{"source":"./child_module","expressions":{"file_names":{"constant_value":["file1.txt","file2.txt"]}},"module":{"resources":[{"address":"local_file.foo","mode":"managed","type":"local_file","name":"foo","provider_config_key":"module.files:local","expressions":{"content":{"constant_value":"Hello, World!"},"filename":{"references":["each.value"]}},"schema_version":0,"for_each_expression":{"references":["var.file_names"]}}],"variables":{"file_names":{"default":["file1.txt"]}}}}}}},"checks":[{"address":{"to_display":"module.files.local_file.foo","kind":"resource","module":"module.files","mode":"managed","type":"local_file","name":"foo"},"status":"pass","instances":[{"address":{"to_display":"module.files.local_file.foo[\"file1.txt\"]","module":"module.files","instance_key":"file1.txt"},"status":"pass"},{"address":{"to_display":"module.files.local_file.foo[\"file2.txt\"]","module":"module.files","instance_key":"file2.txt"},"status":"pass"}]}],"timestamp":"2023-08-30T10:38:39Z"} diff --git a/testdata/has_checks/schemas.json b/testdata/has_checks/schemas.json new file mode 100644 index 0000000..f6c7152 --- /dev/null +++ b/testdata/has_checks/schemas.json @@ -0,0 +1 @@ +{"format_version":"1.0","provider_schemas":{"registry.terraform.io/hashicorp/local":{"provider":{"version":0,"block":{"description_kind":"plain"}},"resource_schemas":{"local_file":{"version":0,"block":{"attributes":{"content":{"type":"string","description":"Content to store in the file, expected to be a UTF-8 encoded string.\n Conflicts with `sensitive_content`, `content_base64` and `source`.\n Exactly one of these four arguments must be specified.","description_kind":"plain","optional":true},"content_base64":{"type":"string","description":"Content to store in the file, expected to be binary encoded as base64 string.\n Conflicts with `content`, `sensitive_content` and `source`.\n Exactly one of these four arguments must be specified.","description_kind":"plain","optional":true},"content_base64sha256":{"type":"string","description":"Base64 encoded SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_base64sha512":{"type":"string","description":"Base64 encoded SHA512 checksum of file content.","description_kind":"plain","computed":true},"content_md5":{"type":"string","description":"MD5 checksum of file content.","description_kind":"plain","computed":true},"content_sha1":{"type":"string","description":"SHA1 checksum of file content.","description_kind":"plain","computed":true},"content_sha256":{"type":"string","description":"SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_sha512":{"type":"string","description":"SHA512 checksum of file content.","description_kind":"plain","computed":true},"directory_permission":{"type":"string","description":"Permissions to set for directories created (before umask), expressed as string in\n [numeric notation](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation).\n Default value is `\"0777\"`.","description_kind":"plain","optional":true,"computed":true},"file_permission":{"type":"string","description":"Permissions to set for the output file (before umask), expressed as string in\n [numeric notation](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation).\n Default value is `\"0777\"`.","description_kind":"plain","optional":true,"computed":true},"filename":{"type":"string","description":"The path to the file that will be created.\n Missing parent directories will be created.\n If the file already exists, it will be overridden with the given content.","description_kind":"plain","required":true},"id":{"type":"string","description":"The hexadecimal encoding of the SHA1 checksum of the file content.","description_kind":"plain","computed":true},"sensitive_content":{"type":"string","description":"Sensitive content to store in the file, expected to be an UTF-8 encoded string.\n Will not be displayed in diffs.\n Conflicts with `content`, `content_base64` and `source`.\n Exactly one of these four arguments must be specified.\n If in need to use _sensitive_ content, please use the [`local_sensitive_file`](./sensitive_file.html)\n resource instead.","description_kind":"plain","deprecated":true,"optional":true,"sensitive":true},"source":{"type":"string","description":"Path to file to use as source for the one we are creating.\n Conflicts with `content`, `sensitive_content` and `content_base64`.\n Exactly one of these four arguments must be specified.","description_kind":"plain","optional":true}},"description":"Generates a local file with the given content.","description_kind":"plain"}},"local_sensitive_file":{"version":0,"block":{"attributes":{"content":{"type":"string","description":"Sensitive Content to store in the file, expected to be a UTF-8 encoded string.\n Conflicts with `content_base64` and `source`.\n Exactly one of these three arguments must be specified.","description_kind":"plain","optional":true,"sensitive":true},"content_base64":{"type":"string","description":"Sensitive Content to store in the file, expected to be binary encoded as base64 string.\n Conflicts with `content` and `source`.\n Exactly one of these three arguments must be specified.","description_kind":"plain","optional":true,"sensitive":true},"content_base64sha256":{"type":"string","description":"Base64 encoded SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_base64sha512":{"type":"string","description":"Base64 encoded SHA512 checksum of file content.","description_kind":"plain","computed":true},"content_md5":{"type":"string","description":"MD5 checksum of file content.","description_kind":"plain","computed":true},"content_sha1":{"type":"string","description":"SHA1 checksum of file content.","description_kind":"plain","computed":true},"content_sha256":{"type":"string","description":"SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_sha512":{"type":"string","description":"SHA512 checksum of file content.","description_kind":"plain","computed":true},"directory_permission":{"type":"string","description":"Permissions to set for directories created (before umask), expressed as string in\n [numeric notation](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation).\n Default value is `\"0700\"`.","description_kind":"plain","optional":true,"computed":true},"file_permission":{"type":"string","description":"Permissions to set for the output file (before umask), expressed as string in\n [numeric notation](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation).\n Default value is `\"0700\"`.","description_kind":"plain","optional":true,"computed":true},"filename":{"type":"string","description":"The path to the file that will be created.\n Missing parent directories will be created.\n If the file already exists, it will be overridden with the given content.","description_kind":"plain","required":true},"id":{"type":"string","description":"The hexadecimal encoding of the SHA1 checksum of the file content.","description_kind":"plain","computed":true},"source":{"type":"string","description":"Path to file to use as source for the one we are creating.\n Conflicts with `content` and `content_base64`.\n Exactly one of these three arguments must be specified.","description_kind":"plain","optional":true}},"description":"Generates a local file with the given sensitive content.","description_kind":"plain"}}},"data_source_schemas":{"local_file":{"version":0,"block":{"attributes":{"content":{"type":"string","description":"Raw content of the file that was read, as UTF-8 encoded string. Files that do not contain UTF-8 text will have invalid UTF-8 sequences in `content`\n replaced with the Unicode replacement character. ","description_kind":"plain","computed":true},"content_base64":{"type":"string","description":"Base64 encoded version of the file content (use this when dealing with binary data).","description_kind":"plain","computed":true},"content_base64sha256":{"type":"string","description":"Base64 encoded SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_base64sha512":{"type":"string","description":"Base64 encoded SHA512 checksum of file content.","description_kind":"plain","computed":true},"content_md5":{"type":"string","description":"MD5 checksum of file content.","description_kind":"plain","computed":true},"content_sha1":{"type":"string","description":"SHA1 checksum of file content.","description_kind":"plain","computed":true},"content_sha256":{"type":"string","description":"SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_sha512":{"type":"string","description":"SHA512 checksum of file content.","description_kind":"plain","computed":true},"filename":{"type":"string","description":"Path to the file that will be read. The data source will return an error if the file does not exist.","description_kind":"plain","required":true},"id":{"type":"string","description":"The hexadecimal encoding of the SHA1 checksum of the file content.","description_kind":"plain","computed":true}},"description":"Reads a file from the local filesystem.","description_kind":"plain"}},"local_sensitive_file":{"version":0,"block":{"attributes":{"content":{"type":"string","description":"Raw content of the file that was read, as UTF-8 encoded string. Files that do not contain UTF-8 text will have invalid UTF-8 sequences in `content`\n replaced with the Unicode replacement character.","description_kind":"plain","computed":true,"sensitive":true},"content_base64":{"type":"string","description":"Base64 encoded version of the file content (use this when dealing with binary data).","description_kind":"plain","computed":true,"sensitive":true},"content_base64sha256":{"type":"string","description":"Base64 encoded SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_base64sha512":{"type":"string","description":"Base64 encoded SHA512 checksum of file content.","description_kind":"plain","computed":true},"content_md5":{"type":"string","description":"MD5 checksum of file content.","description_kind":"plain","computed":true},"content_sha1":{"type":"string","description":"SHA1 checksum of file content.","description_kind":"plain","computed":true},"content_sha256":{"type":"string","description":"SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_sha512":{"type":"string","description":"SHA512 checksum of file content.","description_kind":"plain","computed":true},"filename":{"type":"string","description":"Path to the file that will be read. The data source will return an error if the file does not exist.","description_kind":"plain","required":true},"id":{"type":"string","description":"The hexadecimal encoding of the SHA1 checksum of the file content.","description_kind":"plain","computed":true}},"description":"Reads a file that contains sensitive data, from the local filesystem.","description_kind":"plain"}}}}}} diff --git a/testdata/has_checks/state.json b/testdata/has_checks/state.json new file mode 100644 index 0000000..ac4378f --- /dev/null +++ b/testdata/has_checks/state.json @@ -0,0 +1 @@ +{"format_version":"1.0","terraform_version":"1.5.4","values":{"root_module":{"child_modules":[{"resources":[{"address":"module.files.local_file.foo[\"file1.txt\"]","mode":"managed","type":"local_file","name":"foo","index":"file1.txt","provider_name":"registry.terraform.io/hashicorp/local","schema_version":0,"values":{"content":"Hello, World!","content_base64":null,"content_base64sha256":"3/1gIbsr1bCvZ2KQgJ7DpTGR3YHH9wpLKGiKNiGCmG8=","content_base64sha512":"N015SpXNz9izWZMYX++bo2jxYNja9DLQi6nx7R5avmzGkpHg+i/gAGpSVw7xjBne9OYXwzzlLvCm5fvjGMsDhw==","content_md5":"65a8e27d8879283831b664bd8b7f0ad4","content_sha1":"0a0a9f2a6772942557ab5355d76af442f8f65e01","content_sha256":"dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f","content_sha512":"374d794a95cdcfd8b35993185fef9ba368f160d8daf432d08ba9f1ed1e5abe6cc69291e0fa2fe0006a52570ef18c19def4e617c33ce52ef0a6e5fbe318cb0387","directory_permission":"0777","file_permission":"0777","filename":"file1.txt","id":"0a0a9f2a6772942557ab5355d76af442f8f65e01","sensitive_content":null,"source":null},"sensitive_values":{"sensitive_content":true}},{"address":"module.files.local_file.foo[\"file2.txt\"]","mode":"managed","type":"local_file","name":"foo","index":"file2.txt","provider_name":"registry.terraform.io/hashicorp/local","schema_version":0,"values":{"content":"Hello, World!","content_base64":null,"content_base64sha256":"3/1gIbsr1bCvZ2KQgJ7DpTGR3YHH9wpLKGiKNiGCmG8=","content_base64sha512":"N015SpXNz9izWZMYX++bo2jxYNja9DLQi6nx7R5avmzGkpHg+i/gAGpSVw7xjBne9OYXwzzlLvCm5fvjGMsDhw==","content_md5":"65a8e27d8879283831b664bd8b7f0ad4","content_sha1":"0a0a9f2a6772942557ab5355d76af442f8f65e01","content_sha256":"dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f","content_sha512":"374d794a95cdcfd8b35993185fef9ba368f160d8daf432d08ba9f1ed1e5abe6cc69291e0fa2fe0006a52570ef18c19def4e617c33ce52ef0a6e5fbe318cb0387","directory_permission":"0777","file_permission":"0777","filename":"file2.txt","id":"0a0a9f2a6772942557ab5355d76af442f8f65e01","sensitive_content":null,"source":null},"sensitive_values":{"sensitive_content":true}}],"address":"module.files"}]}},"checks":[{"address":{"to_display":"module.files.local_file.foo","kind":"resource","module":"module.files","mode":"managed","type":"local_file","name":"foo"},"status":"pass","instances":[{"address":{"to_display":"module.files.local_file.foo[\"file1.txt\"]","module":"module.files","instance_key":"file1.txt"},"status":"pass"},{"address":{"to_display":"module.files.local_file.foo[\"file2.txt\"]","module":"module.files","instance_key":"file2.txt"},"status":"pass"}]}]} diff --git a/testdata/moved_block/main.tf b/testdata/moved_block/main.tf new file mode 100644 index 0000000..b58f06e --- /dev/null +++ b/testdata/moved_block/main.tf @@ -0,0 +1,8 @@ +moved { + from = random_id.test + to = random_id.test2 +} + +resource "random_id" "test2" { + byte_length = 10 +} diff --git a/testdata/moved_block/plan.json b/testdata/moved_block/plan.json new file mode 100644 index 0000000..d4b4e50 --- /dev/null +++ b/testdata/moved_block/plan.json @@ -0,0 +1 @@ +{"format_version":"1.2","terraform_version":"1.5.3","planned_values":{"root_module":{"resources":[{"address":"random_id.test2","mode":"managed","type":"random_id","name":"test2","provider_name":"registry.terraform.io/hashicorp/random","schema_version":0,"values":{"b64_std":"uBIJLwrgNTh6OQ==","b64_url":"uBIJLwrgNTh6OQ","byte_length":10,"dec":"869248136000969819847225","hex":"b812092f0ae035387a39","id":"uBIJLwrgNTh6OQ","keepers":null,"prefix":null},"sensitive_values":{}}]}},"resource_changes":[{"address":"random_id.test2","previous_address":"random_id.test","mode":"managed","type":"random_id","name":"test2","provider_name":"registry.terraform.io/hashicorp/random","change":{"actions":["no-op"],"before":{"b64_std":"uBIJLwrgNTh6OQ==","b64_url":"uBIJLwrgNTh6OQ","byte_length":10,"dec":"869248136000969819847225","hex":"b812092f0ae035387a39","id":"uBIJLwrgNTh6OQ","keepers":null,"prefix":null},"after":{"b64_std":"uBIJLwrgNTh6OQ==","b64_url":"uBIJLwrgNTh6OQ","byte_length":10,"dec":"869248136000969819847225","hex":"b812092f0ae035387a39","id":"uBIJLwrgNTh6OQ","keepers":null,"prefix":null},"after_unknown":{},"before_sensitive":{},"after_sensitive":{}}}],"prior_state":{"format_version":"1.0","terraform_version":"1.5.3","values":{"root_module":{"resources":[{"address":"random_id.test2","mode":"managed","type":"random_id","name":"test2","provider_name":"registry.terraform.io/hashicorp/random","schema_version":0,"values":{"b64_std":"uBIJLwrgNTh6OQ==","b64_url":"uBIJLwrgNTh6OQ","byte_length":10,"dec":"869248136000969819847225","hex":"b812092f0ae035387a39","id":"uBIJLwrgNTh6OQ","keepers":null,"prefix":null},"sensitive_values":{}}]}}},"configuration":{"provider_config":{"random":{"name":"random","full_name":"registry.terraform.io/hashicorp/random"}},"root_module":{"resources":[{"address":"random_id.test2","mode":"managed","type":"random_id","name":"test2","provider_config_key":"random","expressions":{"byte_length":{"constant_value":10}},"schema_version":0}]}},"timestamp":"2023-08-31T11:49:54Z"} diff --git a/testdata/moved_block/schemas.json b/testdata/moved_block/schemas.json new file mode 100644 index 0000000..0c5262a --- /dev/null +++ b/testdata/moved_block/schemas.json @@ -0,0 +1 @@ +{"format_version":"1.0","provider_schemas":{"registry.terraform.io/hashicorp/random":{"provider":{"version":0,"block":{"description_kind":"plain"}},"resource_schemas":{"random_id":{"version":0,"block":{"attributes":{"b64_std":{"type":"string","description":"The generated id presented in base64 without additional transformations.","description_kind":"plain","computed":true},"b64_url":{"type":"string","description":"The generated id presented in base64, using the URL-friendly character set: case-sensitive letters, digits and the characters `_` and `-`.","description_kind":"plain","computed":true},"byte_length":{"type":"number","description":"The number of random bytes to produce. The minimum value is 1, which produces eight bits of randomness.","description_kind":"plain","required":true},"dec":{"type":"string","description":"The generated id presented in non-padded decimal digits.","description_kind":"plain","computed":true},"hex":{"type":"string","description":"The generated id presented in padded hexadecimal digits. This result will always be twice as long as the requested byte length.","description_kind":"plain","computed":true},"id":{"type":"string","description":"The generated id presented in base64 without additional transformations or prefix.","description_kind":"plain","computed":true},"keepers":{"type":["map","string"],"description":"Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.","description_kind":"plain","optional":true},"prefix":{"type":"string","description":"Arbitrary string to prefix the output value with. This string is supplied as-is, meaning it is not guaranteed to be URL-safe or base64 encoded.","description_kind":"plain","optional":true}},"description":"\nThe resource `random_id` generates random numbers that are intended to be\nused as unique identifiers for other resources.\n\nThis resource *does* use a cryptographic random number generator in order\nto minimize the chance of collisions, making the results of this resource\nwhen a 16-byte identifier is requested of equivalent uniqueness to a\ntype-4 UUID.\n\nThis resource can be used in conjunction with resources that have\nthe `create_before_destroy` lifecycle flag set to avoid conflicts with\nunique names during the brief period where both the old and new resources\nexist concurrently.\n","description_kind":"plain"}},"random_integer":{"version":0,"block":{"attributes":{"id":{"type":"string","description":"The string representation of the integer result.","description_kind":"plain","computed":true},"keepers":{"type":["map","string"],"description":"Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.","description_kind":"plain","optional":true},"max":{"type":"number","description":"The maximum inclusive value of the range.","description_kind":"plain","required":true},"min":{"type":"number","description":"The minimum inclusive value of the range.","description_kind":"plain","required":true},"result":{"type":"number","description":"The random integer result.","description_kind":"plain","computed":true},"seed":{"type":"string","description":"A custom seed to always produce the same value.","description_kind":"plain","optional":true}},"description":"The resource `random_integer` generates random values from a given range, described by the `min` and `max` attributes of a given resource.\n\nThis resource can be used in conjunction with resources that have the `create_before_destroy` lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.","description_kind":"plain"}},"random_password":{"version":3,"block":{"attributes":{"bcrypt_hash":{"type":"string","description":"A bcrypt hash of the generated random string. **NOTE**: If the generated random string is greater than 72 bytes in length, `bcrypt_hash` will contain a hash of the first 72 bytes.","description_kind":"plain","computed":true,"sensitive":true},"id":{"type":"string","description":"A static value used internally by Terraform, this should not be referenced in configurations.","description_kind":"plain","computed":true},"keepers":{"type":["map","string"],"description":"Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.","description_kind":"plain","optional":true},"length":{"type":"number","description":"The length of the string desired. The minimum value for length is 1 and, length must also be \u003e= (`min_upper` + `min_lower` + `min_numeric` + `min_special`).","description_kind":"plain","required":true},"lower":{"type":"bool","description":"Include lowercase alphabet characters in the result. Default value is `true`.","description_kind":"plain","optional":true,"computed":true},"min_lower":{"type":"number","description":"Minimum number of lowercase alphabet characters in the result. Default value is `0`.","description_kind":"plain","optional":true,"computed":true},"min_numeric":{"type":"number","description":"Minimum number of numeric characters in the result. Default value is `0`.","description_kind":"plain","optional":true,"computed":true},"min_special":{"type":"number","description":"Minimum number of special characters in the result. Default value is `0`.","description_kind":"plain","optional":true,"computed":true},"min_upper":{"type":"number","description":"Minimum number of uppercase alphabet characters in the result. Default value is `0`.","description_kind":"plain","optional":true,"computed":true},"number":{"type":"bool","description":"Include numeric characters in the result. Default value is `true`. **NOTE**: This is deprecated, use `numeric` instead.","description_kind":"plain","deprecated":true,"optional":true,"computed":true},"numeric":{"type":"bool","description":"Include numeric characters in the result. Default value is `true`.","description_kind":"plain","optional":true,"computed":true},"override_special":{"type":"string","description":"Supply your own list of special characters to use for string generation. This overrides the default character list in the special argument. The `special` argument must still be set to true for any overwritten characters to be used in generation.","description_kind":"plain","optional":true},"result":{"type":"string","description":"The generated random string.","description_kind":"plain","computed":true,"sensitive":true},"special":{"type":"bool","description":"Include special characters in the result. These are `!@#$%\u0026*()-_=+[]{}\u003c\u003e:?`. Default value is `true`.","description_kind":"plain","optional":true,"computed":true},"upper":{"type":"bool","description":"Include uppercase alphabet characters in the result. Default value is `true`.","description_kind":"plain","optional":true,"computed":true}},"description":"Identical to [random_string](string.html) with the exception that the result is treated as sensitive and, thus, _not_ displayed in console output. Read more about sensitive data handling in the [Terraform documentation](https://www.terraform.io/docs/language/state/sensitive-data.html).\n\nThis resource *does* use a cryptographic random number generator.","description_kind":"plain"}},"random_pet":{"version":0,"block":{"attributes":{"id":{"type":"string","description":"The random pet name.","description_kind":"plain","computed":true},"keepers":{"type":["map","string"],"description":"Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.","description_kind":"plain","optional":true},"length":{"type":"number","description":"The length (in words) of the pet name. Defaults to 2","description_kind":"plain","optional":true,"computed":true},"prefix":{"type":"string","description":"A string to prefix the name with.","description_kind":"plain","optional":true},"separator":{"type":"string","description":"The character to separate words in the pet name. Defaults to \"-\"","description_kind":"plain","optional":true,"computed":true}},"description":"The resource `random_pet` generates random pet names that are intended to be used as unique identifiers for other resources.\n\nThis resource can be used in conjunction with resources that have the `create_before_destroy` lifecycle flag set, to avoid conflicts with unique names during the brief period where both the old and new resources exist concurrently.","description_kind":"plain"}},"random_shuffle":{"version":0,"block":{"attributes":{"id":{"type":"string","description":"A static value used internally by Terraform, this should not be referenced in configurations.","description_kind":"plain","computed":true},"input":{"type":["list","string"],"description":"The list of strings to shuffle.","description_kind":"plain","required":true},"keepers":{"type":["map","string"],"description":"Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.","description_kind":"plain","optional":true},"result":{"type":["list","string"],"description":"Random permutation of the list of strings given in `input`.","description_kind":"plain","computed":true},"result_count":{"type":"number","description":"The number of results to return. Defaults to the number of items in the `input` list. If fewer items are requested, some elements will be excluded from the result. If more items are requested, items will be repeated in the result but not more frequently than the number of items in the input list.","description_kind":"plain","optional":true},"seed":{"type":"string","description":"Arbitrary string with which to seed the random number generator, in order to produce less-volatile permutations of the list.\n\n**Important:** Even with an identical seed, it is not guaranteed that the same permutation will be produced across different versions of Terraform. This argument causes the result to be *less volatile*, but not fixed for all time.","description_kind":"plain","optional":true}},"description":"The resource `random_shuffle` generates a random permutation of a list of strings given as an argument.","description_kind":"plain"}},"random_string":{"version":2,"block":{"attributes":{"id":{"type":"string","description":"The generated random string.","description_kind":"plain","computed":true},"keepers":{"type":["map","string"],"description":"Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.","description_kind":"plain","optional":true},"length":{"type":"number","description":"The length of the string desired. The minimum value for length is 1 and, length must also be \u003e= (`min_upper` + `min_lower` + `min_numeric` + `min_special`).","description_kind":"plain","required":true},"lower":{"type":"bool","description":"Include lowercase alphabet characters in the result. Default value is `true`.","description_kind":"plain","optional":true,"computed":true},"min_lower":{"type":"number","description":"Minimum number of lowercase alphabet characters in the result. Default value is `0`.","description_kind":"plain","optional":true,"computed":true},"min_numeric":{"type":"number","description":"Minimum number of numeric characters in the result. Default value is `0`.","description_kind":"plain","optional":true,"computed":true},"min_special":{"type":"number","description":"Minimum number of special characters in the result. Default value is `0`.","description_kind":"plain","optional":true,"computed":true},"min_upper":{"type":"number","description":"Minimum number of uppercase alphabet characters in the result. Default value is `0`.","description_kind":"plain","optional":true,"computed":true},"number":{"type":"bool","description":"Include numeric characters in the result. Default value is `true`. **NOTE**: This is deprecated, use `numeric` instead.","description_kind":"plain","deprecated":true,"optional":true,"computed":true},"numeric":{"type":"bool","description":"Include numeric characters in the result. Default value is `true`.","description_kind":"plain","optional":true,"computed":true},"override_special":{"type":"string","description":"Supply your own list of special characters to use for string generation. This overrides the default character list in the special argument. The `special` argument must still be set to true for any overwritten characters to be used in generation.","description_kind":"plain","optional":true},"result":{"type":"string","description":"The generated random string.","description_kind":"plain","computed":true},"special":{"type":"bool","description":"Include special characters in the result. These are `!@#$%\u0026*()-_=+[]{}\u003c\u003e:?`. Default value is `true`.","description_kind":"plain","optional":true,"computed":true},"upper":{"type":"bool","description":"Include uppercase alphabet characters in the result. Default value is `true`.","description_kind":"plain","optional":true,"computed":true}},"description":"The resource `random_string` generates a random permutation of alphanumeric characters and optionally special characters.\n\nThis resource *does* use a cryptographic random number generator.\n\nHistorically this resource's intended usage has been ambiguous as the original example used it in a password. For backwards compatibility it will continue to exist. For unique ids please use [random_id](id.html), for sensitive random values please use [random_password](password.html).","description_kind":"plain"}},"random_uuid":{"version":0,"block":{"attributes":{"id":{"type":"string","description":"The generated uuid presented in string format.","description_kind":"plain","computed":true},"keepers":{"type":["map","string"],"description":"Arbitrary map of values that, when changed, will trigger recreation of resource. See [the main provider documentation](../index.html) for more information.","description_kind":"plain","optional":true},"result":{"type":"string","description":"The generated uuid presented in string format.","description_kind":"plain","computed":true}},"description":"The resource `random_uuid` generates random uuid string that is intended to be used as unique identifiers for other resources.\n\nThis resource uses [hashicorp/go-uuid](https://github.com/hashicorp/go-uuid) to generate a UUID-formatted string for use with services needed a unique string identifier.","description_kind":"plain"}}}}}} diff --git a/testdata/moved_block/show.json b/testdata/moved_block/show.json new file mode 100644 index 0000000..bf08945 --- /dev/null +++ b/testdata/moved_block/show.json @@ -0,0 +1 @@ +{"format_version":"1.0","terraform_version":"1.5.3","values":{"root_module":{"resources":[{"address":"random_id.test","mode":"managed","type":"random_id","name":"test","provider_name":"registry.terraform.io/hashicorp/random","schema_version":0,"values":{"b64_std":"uBIJLwrgNTh6OQ==","b64_url":"uBIJLwrgNTh6OQ","byte_length":10,"dec":"869248136000969819847225","hex":"b812092f0ae035387a39","id":"uBIJLwrgNTh6OQ","keepers":null,"prefix":null},"sensitive_values":{}}]}}}