pulumi/pkg/codegen/pcl/rewrite_apply_test.go

187 lines
5.3 KiB
Go
Raw Normal View History

package pcl
import (
"fmt"
"testing"
"github.com/hashicorp/hcl/v2"
"github.com/pulumi/pulumi/pkg/v3/codegen/hcl2/model"
"github.com/pulumi/pulumi/pkg/v3/codegen/hcl2/syntax"
"github.com/stretchr/testify/assert"
)
type nameInfo int
func (nameInfo) Format(name string) string {
return name
}
sdk/go: Remove 'nolint' directives from package docs Go treats comments that match the following regex as directives. //[a-z0-9]+:[a-z0-9] Comments that are directives don't show in an entity's documentation. https://github.com/golang/go/commit/5a550b695117f07a4f2454039a4871250cd3ed09#diff-f56160fd9fcea272966a8a1d692ad9f49206fdd8dbcbfe384865a98cd9bc2749R165 Our code has `//nolint` directives that now show in the API Reference. This is because these directives are in one of the following forms, which don't get this special treatment. // nolint:foo //nolint: foo This change fixes all such directives found by the regex: `// nolint|//nolint: `. See bottom of commit for command used for the fix. Verification: Here's the output of `go doc` on some entities before and after this change. Before ``` % go doc github.com/pulumi/pulumi/sdk/v3/go/pulumi | head -n8 package pulumi // import "github.com/pulumi/pulumi/sdk/v3/go/pulumi" nolint: lll, interfacer nolint: lll, interfacer const EnvOrganization = "PULUMI_ORGANIZATION" ... var ErrPlugins = errors.New("pulumi: plugins requested") ``` After ``` % go doc github.com/pulumi/pulumi/sdk/v3/go/pulumi | head -n8 package pulumi // import "github.com/pulumi/pulumi/sdk/v3/go/pulumi" const EnvOrganization = "PULUMI_ORGANIZATION" ... var ErrPlugins = errors.New("pulumi: plugins requested") func BoolRef(v bool) *bool func Float64Ref(v float64) *float64 func IntRef(v int) *int func IsSecret(o Output) bool ``` Before ``` % go doc github.com/pulumi/pulumi/sdk/v3/go/pulumi URN_ package pulumi // import "github.com/pulumi/pulumi/sdk/v3/go/pulumi" func URN_(o string) ResourceOption URN_ is an optional URN of a previously-registered resource of this type to read from the engine. nolint: revive ``` After: ``` % go doc github.com/pulumi/pulumi/sdk/v3/go/pulumi URN_ package pulumi // import "github.com/pulumi/pulumi/sdk/v3/go/pulumi" func URN_(o string) ResourceOption URN_ is an optional URN of a previously-registered resource of this type to read from the engine. ``` Note that golangci-lint offers a 'nolintlint' linter that finds such miuses of nolint, but it also finds other issues so I've deferred that to a follow up PR. Resolves #11785 Related: https://github.com/golangci/golangci-lint/issues/892 [git-generate] FILES=$(mktemp) rg -l '// nolint|//nolint: ' | tee "$FILES" | xargs perl -p -i -e ' s|// nolint|//nolint|g; s|//nolint: |//nolint:|g; ' rg '.go$' < "$FILES" | xargs gofmt -w -s
2023-01-06 00:07:45 +00:00
//nolint:lll
func TestApplyRewriter(t *testing.T) {
t.Parallel()
cases := []struct {
input, output string
skipPromises bool
}{
{
input: `"v: ${resource.foo.bar}"`,
output: `__apply(resource.foo,eval(foo, "v: ${foo.bar}"))`,
},
{
input: `"v: ${resource.baz[0]}"`,
output: `__apply(resource.baz,eval(baz, "v: ${baz[0]}"))`,
},
{
input: `"v: ${resources[0].foo.bar}"`,
output: `__apply(resources[0].foo,eval(foo, "v: ${foo.bar}"))`,
},
{
input: `"v: ${resources.*.id[0]}"`,
output: `__apply(resources.*.id[0],eval(id, "v: ${id}"))`,
},
{
input: `"v: ${element(resources.*.id, 0)}"`,
output: `__apply(element(resources.*.id, 0),eval(ids, "v: ${ids}"))`,
},
{
input: `"v: ${[for r in resources: r.id][0]}"`,
output: `__apply([for r in resources: r.id][0],eval(id, "v: ${id}"))`,
},
{
input: `"v: ${element([for r in resources: r.id], 0)}"`,
output: `__apply(element([for r in resources: r.id], 0),eval(ids, "v: ${ids}"))`,
},
{
input: `"v: ${resource[key]}"`,
output: `__apply(resource[key],eval(key, "v: ${key}"))`,
},
{
input: `"v: ${resource[resource.id]}"`,
output: `__apply(__apply(resource.id,eval(id, resource[id])),eval(id, "v: ${id}"))`,
},
{
input: `resourcesPromise.*.id`,
output: `__apply(resourcesPromise, eval(resourcesPromise, resourcesPromise.*.id))`,
},
{
input: `[for r in resourcesPromise: r.id]`,
output: `__apply(resourcesPromise,eval(resourcesPromise, [for r in resourcesPromise: r.id]))`,
},
{
input: `resourcesOutput.*.id`,
output: `__apply(resourcesOutput, eval(resourcesOutput, resourcesOutput.*.id))`,
},
{
input: `[for r in resourcesOutput: r.id]`,
output: `__apply(resourcesOutput,eval(resourcesOutput, [for r in resourcesOutput: r.id]))`,
},
{
input: `"v: ${[for r in resourcesPromise: r.id]}"`,
output: `__apply(__apply(resourcesPromise,eval(resourcesPromise, [for r in resourcesPromise: r.id])),eval(ids, "v: ${ids}"))`,
},
{
input: `toJSON({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = "*"
Action = [ "s3:GetObject" ]
Resource = [ "arn:aws:s3:::${resource.id}/*" ]
}]
})`,
output: `__apply(resource.id,eval(id, toJSON({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = "*"
Action = [ "s3:GetObject" ]
Resource = [ "arn:aws:s3:::${id}/*" ]
}]
})))`,
},
{
input: `getPromise().property`,
output: `__apply(getPromise(), eval(getPromise, getPromise.property))`,
},
{
input: `getPromise().object.foo`,
output: `__apply(getPromise(), eval(getPromise, getPromise.object.foo))`,
},
{
input: `getPromise().property`,
output: `getPromise().property`,
skipPromises: true,
},
{
input: `getPromise().object.foo`,
output: `getPromise().object.foo`,
skipPromises: true,
},
{
input: `getPromise(resource.id).property`,
output: `__apply(__apply(resource.id,eval(id, getPromise(id))), eval(getPromise, getPromise.property))`,
},
}
resourceType := model.NewObjectType(map[string]model.Type{
"id": model.NewOutputType(model.StringType),
"foo": model.NewOutputType(model.NewObjectType(map[string]model.Type{
"bar": model.StringType,
})),
"baz": model.NewOutputType(model.NewListType(model.StringType)),
})
scope := model.NewRootScope(syntax.None)
scope.Define("key", &model.Variable{
Name: "key",
VariableType: model.StringType,
})
scope.Define("resource", &model.Variable{
Name: "resource",
VariableType: resourceType,
})
scope.Define("resources", &model.Variable{
Name: "resources",
VariableType: model.NewListType(resourceType),
})
scope.Define("resourcesPromise", &model.Variable{
Name: "resourcesPromise",
VariableType: model.NewPromiseType(model.NewListType(resourceType)),
})
scope.Define("resourcesOutput", &model.Variable{
Name: "resourcesOutput",
VariableType: model.NewOutputType(model.NewListType(resourceType)),
})
functions := pulumiBuiltins(bindOptions{})
scope.DefineFunction("element", functions["element"])
scope.DefineFunction("toJSON", functions["toJSON"])
scope.DefineFunction("getPromise", model.NewFunction(model.StaticFunctionSignature{
Parameters: []model.Parameter{{
Name: "p",
Type: model.NewOptionalType(model.StringType),
}},
ReturnType: model.NewPromiseType(model.NewObjectType(map[string]model.Type{
"property": model.StringType,
"object": model.NewObjectType(map[string]model.Type{
"foo": model.StringType,
}),
})),
}))
for _, c := range cases {
c := c
t.Run(c.input, func(t *testing.T) {
t.Parallel()
expr, diags := model.BindExpressionText(c.input, scope, hcl.Pos{})
assert.Len(t, diags, 0)
expr, diags = RewriteApplies(expr, nameInfo(0), !c.skipPromises)
assert.Len(t, diags, 0)
assert.Equal(t, c.output, fmt.Sprintf("%v", expr))
})
}
}