Skip to content

Commit

Permalink
Sort generated properties by their keys to get deterministic output. (#…
Browse files Browse the repository at this point in the history
…110)

* Sort generated properties by the position of their keys to get deterministic output.

* review feedback

---------

Co-authored-by: Fraser Waters <fraser@pulumi.com>
  • Loading branch information
Zaid-Ajaj and Frassle authored Feb 22, 2024
1 parent 41b7d19 commit 1489e19
Show file tree
Hide file tree
Showing 10 changed files with 63 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG_PENDING.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
### Improvements

- Sort generated properties by the position of their keys to get deterministic output.

### Bug Fixes
11 changes: 11 additions & 0 deletions pkg/convert/testdata/programs/expressions/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ output "str_object_out" {
}
}

output "sorted_object_out" {
value = {
nested: {
b: 4
a: 3
}
b: 2
a: 1
}
}

locals {
a_key = "hello"
a_value = -1
Expand Down
11 changes: 11 additions & 0 deletions pkg/convert/testdata/programs/expressions/pcl/main.pp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@
goodbye = "ha det"
}
}

output "sortedObjectOut" {
value = {
nested = {
b = 4
a = 3
}
b = 2
a = 1
}
}
aKey = "hello"
aValue = -1
aList = [1, 2, 3]
Expand Down
6 changes: 3 additions & 3 deletions pkg/convert/testdata/programs/name_conflict/pcl/main.pp
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
config "aThing" {
}
myaThing = true
myAThing = true

resource "aThingResource" "simple:index:resource" {
__logicalName = "a_thing"
inputOne = "Hello ${aThing}"
inputTwo = myaThing
inputTwo = myAThing
}

aThingDataSource = invoke("simple:index:dataSource", {
inputOne = "Hello ${aThingResource.result}"
inputTwo = myaThing
inputTwo = myAThing
})

resource "aThingAnotherResource" "simple:index:anotherResource" {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[
"warning:main.pp:1,14-42:undefined variable exampledataunknownDataSource:",
"warning:main.pp:2,14-40:undefined variable exampleunknownResourceType:"
"warning:main.pp:1,14-38:undefined variable exampleUnknownDataSource:",
"warning:main.pp:2,14-40:undefined variable exampleUnknownResourceType:"
]
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
resource "example" "simple:index:resource" {
inputOne = exampledataunknownDataSource.attr
inputTwo = exampleunknownResourceType.list[0]
inputOne = exampleUnknownDataSource.attr
inputTwo = exampleUnknownResourceType.list[0]
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
outputFilePaths = notImplemented("setunion(keys(local.template_file_paths),local.static_file_paths)")
fileSuffixMatches = { for p in outputFilePaths : p => notImplemented("regexall(\"\\\\.[^\\\\.]+\\\\z\",p)") }
fileSuffixes = { for p, ms in fileSuffixMatches : p => length(ms) > 0 ? ms[0] : "" }
myfileTypes = { for p in outputFilePaths : p => notImplemented("lookup(var.file_types,local.file_suffixes[p],var.default_file_type)") }
myFileTypes = { for p in outputFilePaths : p => notImplemented("lookup(var.file_types,local.file_suffixes[p],var.default_file_type)") }
files = notImplemented("merge(\n{\nforpinkeys(local.template_file_paths):p=>{\ncontent_type=local.file_types[p]\nsource_path=tostring(null)\ncontent=local.template_file_contents[p]\ndigests=tomap({\nmd5=md5(local.template_file_contents[p])\nsha1=sha1(local.template_file_contents[p])\nsha256=sha256(local.template_file_contents[p])\nsha512=sha512(local.template_file_contents[p])\nbase64sha256=base64sha256(local.template_file_contents[p])\nbase64sha512=base64sha512(local.template_file_contents[p])\n})\n}\n},\n{\nforpinlocal.static_file_paths:p=>{\ncontent_type=local.file_types[p]\nsource_path=local.static_file_local_paths[p]\ncontent=tostring(null)\ndigests=tomap({\nmd5=filemd5(local.static_file_local_paths[p])\nsha1=filesha1(local.static_file_local_paths[p])\nsha256=filesha256(local.static_file_local_paths[p])\nsha512=filesha512(local.static_file_local_paths[p])\nbase64sha256=filebase64sha256(local.static_file_local_paths[p])\nbase64sha512=filebase64sha512(local.static_file_local_paths[p])\n})\n}\n},\n)")
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
outputFilePaths = notImplemented("setunion(keys(local.template_file_paths),local.static_file_paths)")
fileSuffixMatches = { for p in outputFilePaths : p => notImplemented("regexall(\"\\\\.[^\\\\.]+\\\\z\",p)") }
fileSuffixes = { for p, ms in fileSuffixMatches : p => length(ms) > 0 ? ms[0] : "" }
myfileTypes = { for p in outputFilePaths : p => notImplemented("lookup(var.file_types,local.file_suffixes[p],var.default_file_type)") }
myFileTypes = { for p in outputFilePaths : p => notImplemented("lookup(var.file_types,local.file_suffixes[p],var.default_file_type)") }
files = notImplemented("merge(\n{\nforpinkeys(local.template_file_paths):p=>{\ncontent_type=local.file_types[p]\nsource_path=tostring(null)\ncontent=local.template_file_contents[p]\ndigests=tomap({\nmd5=md5(local.template_file_contents[p])\nsha1=sha1(local.template_file_contents[p])\nsha256=sha256(local.template_file_contents[p])\nsha512=sha512(local.template_file_contents[p])\nbase64sha256=base64sha256(local.template_file_contents[p])\nbase64sha512=base64sha512(local.template_file_contents[p])\n})\n}\n},\n{\nforpinlocal.static_file_paths:p=>{\ncontent_type=local.file_types[p]\nsource_path=local.static_file_local_paths[p]\ncontent=tostring(null)\ndigests=tomap({\nmd5=filemd5(local.static_file_local_paths[p])\nsha1=filesha1(local.static_file_local_paths[p])\nsha256=filesha256(local.static_file_local_paths[p])\nsha512=filesha512(local.static_file_local_paths[p])\nbase64sha256=filebase64sha256(local.static_file_local_paths[p])\nbase64sha512=filebase64sha512(local.static_file_local_paths[p])\n})\n}\n},\n)")
29 changes: 21 additions & 8 deletions pkg/convert/tf.go
Original file line number Diff line number Diff line change
Expand Up @@ -1193,11 +1193,21 @@ func rewriteTraversal(
} else if root.Name == "data" && maybeFirstAttr != nil && maybeSecondAttr != nil {
// This is a lookup of a data resources etc, we need to rewrite this traversal such that the root is now the
// pulumi invoked value instead.
suffix := camelCaseName(maybeFirstAttr.Name)
path := "data." + maybeFirstAttr.Name + "." + maybeSecondAttr.Name
newName := scopes.getOrAddPulumiName(path, "", "data"+suffix)
newTraversal = append(newTraversal, hcl.TraverseRoot{Name: newName})
newTraversal = append(newTraversal, rewriteRelativeTraversal(scopes, path, traversal[3:])...)
rootName := scopes.lookup(path)
if rootName != "" {
newName := scopes.getOrAddPulumiName(path, "", "data"+camelCaseName(rootName))
newTraversal = append(newTraversal, hcl.TraverseRoot{Name: newName})
newTraversal = append(newTraversal, rewriteRelativeTraversal(scopes, path, traversal[3:])...)
} else {
// unbound data source / invoke usage.
// turn data.{data_source_token}.{local_name}.{rest}
// into {localName}{DataSourceToken}.{rest}
suffix := camelCaseName(maybeFirstAttr.Name)
newRootName := scopes.getOrAddPulumiName(path, "", suffix)
newTraversal = append(newTraversal, hcl.TraverseRoot{Name: newRootName})
newTraversal = append(newTraversal, rewriteRelativeTraversal(scopes, "", traversal[3:])...)
}
} else if root.Name == "count" && maybeFirstAttr != nil {
if maybeFirstAttr.Name == "index" && scopes.countIndex != nil {
newTraversal = append(newTraversal, scopes.countIndex...)
Expand Down Expand Up @@ -1299,10 +1309,13 @@ func rewriteTraversal(
newTraversal = append(newTraversal, hcl.TraverseRoot{Name: newName})
newTraversal = append(newTraversal, rewriteRelativeTraversal(scopes, "", traversal[1:])...)
} else {
// We don't know what this is, so lets assume it's an unknown resource (we shouldn't ever have unknown locals)
newName = scopes.getOrAddPulumiName(path, "", camelCaseName(root.Name))
newTraversal = append(newTraversal, hcl.TraverseRoot{Name: newName})
newTraversal = append(newTraversal, rewriteRelativeTraversal(scopes, path, traversal[2:])...)
// We don't know what this is, so let's assume it's an unknown resource (we shouldn't ever have unknown locals)
// turn {resource_type}.{resource_name}.{rest}
// into {resourceName}{ResourceType}.{rest}
suffix := camelCaseName(root.Name)
newRootName := scopes.getOrAddPulumiName(path, "", suffix)
newTraversal = append(newTraversal, hcl.TraverseRoot{Name: newRootName})
newTraversal = append(newTraversal, rewriteRelativeTraversal(scopes, "", traversal[2:])...)
}
}
} else {
Expand Down
10 changes: 9 additions & 1 deletion pkg/convert/tf_scopes.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/schema"
"github.com/pulumi/pulumi/pkg/v3/codegen/cgstrings"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
"github.com/pulumi/terraform/pkg/addrs"
"github.com/pulumi/terraform/pkg/lang"
Expand Down Expand Up @@ -127,7 +128,14 @@ func (s *scopes) generateUniqueName(name, prefix, suffix string) string {
return name
}
// It's used, so add the prefix and suffix
name = prefix + name + suffix
if prefix != "" {
name = prefix + cgstrings.UppercaseFirst(name)
}

if suffix != "" {
name = name + cgstrings.UppercaseFirst(suffix)
}

if !s.isUsed(name) {
return name
}
Expand Down

0 comments on commit 1489e19

Please sign in to comment.