diff --git a/internal/testprovider/schema_mini_cloudflare.go b/internal/testprovider/schema_mini_cloudflare.go index 2466c6409..2dcdce1a8 100644 --- a/internal/testprovider/schema_mini_cloudflare.go +++ b/internal/testprovider/schema_mini_cloudflare.go @@ -18,7 +18,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -// Subset of pulumi-random provider. +// Subset of pulumi-cloudflare provider, specifically to test nested descriptions cleanup func ProviderMiniCloudflare() *schema.Provider { resourceRuleset := func() *schema.Resource { return &schema.Resource{ diff --git a/internal/testprovider/schema_nested_descriptions.go b/internal/testprovider/schema_nested_descriptions.go new file mode 100644 index 000000000..da6e1e39c --- /dev/null +++ b/internal/testprovider/schema_nested_descriptions.go @@ -0,0 +1,92 @@ +// Copyright 2016-2022, Pulumi Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package testprovider + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// Subset of pulumi-cloudflare provider. +func ProviderNestedDescriptions() *schema.Provider { + resourceRuleset := func() *schema.Resource { + return &schema.Resource{ + Description: "Deploy a ruleset for cloudflare", + Schema: resourceNestedDescriptionsSchema(), + } + } + + return &schema.Provider{ + Schema: map[string]*schema.Schema{}, + ResourcesMap: map[string]*schema.Resource{ + "cloudflare_ruleset": resourceRuleset(), + }, + } +} + +// An aggressively cut down version of cloudflare_ruleset. +func resourceNestedDescriptionsSchema() map[string]*schema.Schema { + return map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Name of the ruleset.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Brief summary of the ruleset and its intended use.", + }, + "rules": { + Type: schema.TypeList, + Optional: true, + Description: "List of rules to apply to the ruleset.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Unique rule identifier.", + }, + "version": { + Type: schema.TypeString, + Computed: true, + Description: "Version of the ruleset to deploy.", + }, + "action_parameters": { + Type: schema.TypeList, + Optional: true, + Description: "List of parameters that configure the behavior of the ruleset rule action.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + Description: "Identifier of the action parameter to modify. " + + "When Terraform is mentioned here, the description should be dropped.", + }, + "translateField": { + Type: schema.TypeString, + Optional: true, + Description: "When cloudflare_ruleset is mentioned, it should be translated.", + }, + }, + }, + }, + }, + }, + }, + } +} diff --git a/pf/internal/schemashim/object_type_test.go b/pf/internal/schemashim/object_type_test.go index 9a6917984..30f8c5e50 100644 --- a/pf/internal/schemashim/object_type_test.go +++ b/pf/internal/schemashim/object_type_test.go @@ -42,13 +42,21 @@ func TestObjectAttribute(t *testing.T) { assert.Equal(t, shim.TypeString, s.Type()) } +func TestTypeSchemaDescriptionIsEmpty(t *testing.T) { + shimmedType := &typeSchema{ + t: types.StringType, + nested: nil, + } + assert.Equal(t, shimmedType.Description(), "") +} + func TestSingleNestedBlock(t *testing.T) { b := schema.SingleNestedBlock{ Attributes: simpleObjectAttributes(), } shimmed := &blockSchema{"key", pfutils.FromResourceBlock(b)} assertIsObjectType(t, shimmed) - assert.Equal(t, "obj[c=str,co=str,o=str,r=str]", schemaLogicalType(shimmed).String()) + assert.Equal(t, "obj[c=str,co=str,desc=str,o=str,r=str]", schemaLogicalType(shimmed).String()) r, ok := shimmed.Elem().(shim.Resource) require.True(t, ok, "Single-nested TF blocks should be represented as Elem() shim.Resource") assertHasSimpleObjectAttributes(t, r) @@ -61,7 +69,7 @@ func TestListNestedBlock(t *testing.T) { }, } shimmed := &blockSchema{"key", pfutils.FromResourceBlock(b)} - assert.Equal(t, "list[obj[c=str,co=str,o=str,r=str]]", schemaLogicalType(shimmed).String()) + assert.Equal(t, "list[obj[c=str,co=str,desc=str,o=str,r=str]]", schemaLogicalType(shimmed).String()) r, ok := shimmed.Elem().(shim.Resource) require.True(t, ok, "List-nested TF blocks should be represented as Elem() shim.Resource") assertHasSimpleObjectAttributes(t, r) @@ -74,7 +82,7 @@ func TestSetNestedBlock(t *testing.T) { }, } shimmed := &blockSchema{"key", pfutils.FromResourceBlock(b)} - assert.Equal(t, "set[obj[c=str,co=str,o=str,r=str]]", schemaLogicalType(shimmed).String()) + assert.Equal(t, "set[obj[c=str,co=str,desc=str,o=str,r=str]]", schemaLogicalType(shimmed).String()) r, ok := shimmed.Elem().(shim.Resource) require.True(t, ok, "Set-nested TF blocks should be represented as Elem() shim.Resource") assertHasSimpleObjectAttributes(t, r) @@ -135,6 +143,9 @@ func simpleObjectAttributes() map[string]schema.Attribute { Computed: true, Optional: true, }, + "desc": schema.StringAttribute{ + Description: "I am a description", + }, } } @@ -143,6 +154,7 @@ func assertHasSimpleObjectAttributes(t *testing.T, r shim.Resource) { assert.True(t, r.Schema().Get("c").Computed(), "c is computed") assert.True(t, r.Schema().Get("r").Required(), "r is required") assert.True(t, r.Schema().Get("co").Computed() && r.Schema().Get("co").Optional(), "co is computed and optional") + assert.Equal(t, r.Schema().Get("desc").Description(), "I am a description") } func assertIsObjectType(t *testing.T, shimmed shim.Schema) { diff --git a/pf/internal/schemashim/type_schema.go b/pf/internal/schemashim/type_schema.go index 9d5b21617..0972b4c1d 100644 --- a/pf/internal/schemashim/type_schema.go +++ b/pf/internal/schemashim/type_schema.go @@ -99,7 +99,7 @@ func (*typeSchema) DefaultValue() (interface{}, error) { } func (*typeSchema) Description() string { - panic("Description() should not be called during schema generation") + return "" } func (*typeSchema) StateFunc() shim.SchemaStateFunc { diff --git a/pf/tests/internal/testprovider/cmd/pulumi-resource-testbridge/schema.json b/pf/tests/internal/testprovider/cmd/pulumi-resource-testbridge/schema.json index d67fae8af..bc6e5ee63 100644 --- a/pf/tests/internal/testprovider/cmd/pulumi-resource-testbridge/schema.json +++ b/pf/tests/internal/testprovider/cmd/pulumi-resource-testbridge/schema.json @@ -45,10 +45,12 @@ "testbridge:index/TestnestRule:TestnestRule": { "properties": { "actionParameters": { - "$ref": "#/types/testbridge:index/TestnestRuleActionParameters:TestnestRuleActionParameters" + "$ref": "#/types/testbridge:index/TestnestRuleActionParameters:TestnestRuleActionParameters", + "description": "List of parameters that configure the behavior of the ruleset rule action.\n" }, "protocol": { - "type": "string" + "type": "string", + "description": "network protocol\n" } }, "type": "object" @@ -56,10 +58,12 @@ "testbridge:index/TestnestRuleActionParameters:TestnestRuleActionParameters": { "properties": { "automaticHttpsRewrites": { - "type": "boolean" + "type": "boolean", + "description": "Turn on or off Cloudflare Automatic HTTPS rewrites.\n" }, "bic": { - "type": "boolean" + "type": "boolean", + "description": "Inspect the visitor's browser for headers commonly associated with spammers and certain bots.\n" }, "phases": { "$ref": "#/types/testbridge:index/TestnestRuleActionParametersPhases:TestnestRuleActionParametersPhases" @@ -70,10 +74,12 @@ "testbridge:index/TestnestRuleActionParametersPhases:TestnestRuleActionParametersPhases": { "properties": { "p1": { - "type": "boolean" + "type": "boolean", + "description": "The first phase.\n" }, "p2": { - "type": "boolean" + "type": "boolean", + "description": "The second phase.\n" } }, "type": "object" @@ -81,16 +87,19 @@ "testbridge:index/TestnestService:TestnestService": { "properties": { "intport": { - "type": "integer" + "type": "integer", + "description": "Port application listens on internally\n" }, "ports": { "type": "array", "items": { "$ref": "#/types/testbridge:index/TestnestServicePort:TestnestServicePort" - } + }, + "description": "External ports and handlers\n" }, "protocol": { - "type": "string" + "type": "string", + "description": "network protocol\n" } }, "type": "object", @@ -106,10 +115,12 @@ "type": "array", "items": { "type": "string" - } + }, + "description": "How the edge should process requests\n" }, "port": { - "type": "integer" + "type": "integer", + "description": "External port\n" } }, "type": "object", @@ -120,16 +131,19 @@ "testbridge:index/TestnestattrService:TestnestattrService": { "properties": { "intport": { - "type": "integer" + "type": "integer", + "description": "Port application listens on internally\n" }, "ports": { "type": "array", "items": { "$ref": "#/types/testbridge:index/TestnestattrServicePort:TestnestattrServicePort" - } + }, + "description": "External ports and handlers\n" }, "protocol": { - "type": "string" + "type": "string", + "description": "network protocol\n" } }, "type": "object", @@ -145,10 +159,12 @@ "type": "array", "items": { "type": "string" - } + }, + "description": "How the edge should process requests\n" }, "port": { - "type": "integer" + "type": "integer", + "description": "External port\n" } }, "type": "object", @@ -159,16 +175,19 @@ "testbridge:index/TestresService:TestresService": { "properties": { "intport": { - "type": "integer" + "type": "integer", + "description": "Port application listens on internally\n" }, "ports": { "type": "array", "items": { "$ref": "#/types/testbridge:index/TestresServicePort:TestresServicePort" - } + }, + "description": "External ports and handlers\n" }, "protocol": { - "type": "string" + "type": "string", + "description": "network protocol\n" } }, "type": "object", @@ -184,10 +203,12 @@ "type": "array", "items": { "type": "string" - } + }, + "description": "How the edge should process requests\n" }, "port": { - "type": "integer" + "type": "integer", + "description": "External port\n" } }, "type": "object", diff --git a/pf/tests/internal/testprovider/cmd/pulumi-resource-tls/schema.json b/pf/tests/internal/testprovider/cmd/pulumi-resource-tls/schema.json index 322d81f5a..b504e6341 100644 --- a/pf/tests/internal/testprovider/cmd/pulumi-resource-tls/schema.json +++ b/pf/tests/internal/testprovider/cmd/pulumi-resource-tls/schema.json @@ -60,17 +60,21 @@ "tls:config/proxy:proxy": { "properties": { "fromEnv": { - "type": "boolean" + "type": "boolean", + "description": "When `true` the provider will discover the proxy configuration from environment variables. This is based upon [`http.ProxyFromEnvironment`](https://pkg.go.dev/net/http#ProxyFromEnvironment) and it supports the same environment variables (default: `true`).\n" }, "password": { "type": "string", + "description": "Password used for Basic authentication against the Proxy.\n", "secret": true }, "url": { - "type": "string" + "type": "string", + "description": "URL used to connect to the Proxy. Accepted schemes are: `http`, `https`, `socks5`.\n" }, "username": { - "type": "string" + "type": "string", + "description": "Username (or Token) used for Basic authentication against the Proxy.\n" } }, "type": "object" @@ -78,34 +82,43 @@ "tls:index/CertRequestSubject:CertRequestSubject": { "properties": { "commonName": { - "type": "string" + "type": "string", + "description": "Distinguished name: `CN`\n" }, "country": { - "type": "string" + "type": "string", + "description": "Distinguished name: `C`\n" }, "locality": { - "type": "string" + "type": "string", + "description": "Distinguished name: `L`\n" }, "organization": { - "type": "string" + "type": "string", + "description": "Distinguished name: `O`\n" }, "organizationalUnit": { - "type": "string" + "type": "string", + "description": "Distinguished name: `OU`\n" }, "postalCode": { - "type": "string" + "type": "string", + "description": "Distinguished name: `PC`\n" }, "province": { - "type": "string" + "type": "string", + "description": "Distinguished name: `ST`\n" }, "serialNumber": { - "type": "string" + "type": "string", + "description": "Distinguished name: `SERIALNUMBER`\n" }, "streetAddresses": { "type": "array", "items": { "type": "string" - } + }, + "description": "Distinguished name: `STREET`\n" } }, "type": "object" @@ -113,17 +126,21 @@ "tls:index/ProviderProxy:ProviderProxy": { "properties": { "fromEnv": { - "type": "boolean" + "type": "boolean", + "description": "When `true` the provider will discover the proxy configuration from environment variables. This is based upon [`http.ProxyFromEnvironment`](https://pkg.go.dev/net/http#ProxyFromEnvironment) and it supports the same environment variables (default: `true`).\n" }, "password": { "type": "string", + "description": "Password used for Basic authentication against the Proxy.\n", "secret": true }, "url": { - "type": "string" + "type": "string", + "description": "URL used to connect to the Proxy. Accepted schemes are: `http`, `https`, `socks5`.\n" }, "username": { - "type": "string" + "type": "string", + "description": "Username (or Token) used for Basic authentication against the Proxy.\n" } }, "type": "object" @@ -131,34 +148,43 @@ "tls:index/SelfSignedCertSubject:SelfSignedCertSubject": { "properties": { "commonName": { - "type": "string" + "type": "string", + "description": "Distinguished name: `CN`\n" }, "country": { - "type": "string" + "type": "string", + "description": "Distinguished name: `C`\n" }, "locality": { - "type": "string" + "type": "string", + "description": "Distinguished name: `L`\n" }, "organization": { - "type": "string" + "type": "string", + "description": "Distinguished name: `O`\n" }, "organizationalUnit": { - "type": "string" + "type": "string", + "description": "Distinguished name: `OU`\n" }, "postalCode": { - "type": "string" + "type": "string", + "description": "Distinguished name: `PC`\n" }, "province": { - "type": "string" + "type": "string", + "description": "Distinguished name: `ST`\n" }, "serialNumber": { - "type": "string" + "type": "string", + "description": "Distinguished name: `SERIALNUMBER`\n" }, "streetAddresses": { "type": "array", "items": { "type": "string" - } + }, + "description": "Distinguished name: `STREET`\n" } }, "type": "object" diff --git a/pkg/tfgen/generate.go b/pkg/tfgen/generate.go index cc0b9c3f8..d8535c54e 100644 --- a/pkg/tfgen/generate.go +++ b/pkg/tfgen/generate.go @@ -428,10 +428,14 @@ func (g *Generator) makePropertyType(typePath paths.TypePath, return t } +func getDocsFromSchemaMap(key string, schemaMap shim.SchemaMap) string { + subSchema := schemaMap.Get(key) + return subSchema.Description() +} + func (g *Generator) makeObjectPropertyType(typePath paths.TypePath, objPath docsPath, res shim.Resource, info *tfbridge.SchemaInfo, out bool, entityDocs entityDocs) *propertyType { - t := &propertyType{ kind: kindObject, } @@ -456,6 +460,19 @@ func (g *Generator) makeObjectPropertyType(typePath paths.TypePath, // This seems wrong, so we ignore the second return value here for now. doc, _ := getNestedDescriptionFromParsedDocs(entityDocs, objPath.join(key)) + // If we have no result from entityDocs, we look up the TF schema Description. + if doc == "" { + doc = getDocsFromSchemaMap(key, propertySchema) + // Since these docs have not been parsed via entityDocs, they still need to be reformatted. + docsInfoCtx := infoContext{ + language: g.language, + pkg: g.pkg, + info: g.info, + } + // Description fields have no footers, so we pass in an empty map + fakeFooterLinks := map[string]string{} + doc, _ = reformatText(docsInfoCtx, doc, fakeFooterLinks) + } if v := g.propertyVariable(typePath, key, propertySchema, propertyInfos, doc, "", out, entityDocs); v != nil { t.properties = append(t.properties, v) @@ -1075,8 +1092,16 @@ func (g *Generator) gatherConfig() *module { for _, key := range cfgkeys { // Generate a name and type to use for this key. sch := cfg.Get(key) + // Reformat the upstream Description if necessary + docsInfoCtx := infoContext{ + language: g.language, + pkg: g.pkg, + info: g.info, + } + fakeFooterLinks := map[string]string{} + rawdoc, _ := reformatText(docsInfoCtx, sch.Description(), fakeFooterLinks) prop := g.propertyVariable(cfgPath, - key, cfg, custom, "", sch.Description(), true /*out*/, entityDocs{}) + key, cfg, custom, "", rawdoc, true /*out*/, entityDocs{}) if prop != nil { prop.config = true config.addMember(prop) diff --git a/pkg/tfgen/generate_schema_test.go b/pkg/tfgen/generate_schema_test.go index d2709cf7d..8037303a8 100644 --- a/pkg/tfgen/generate_schema_test.go +++ b/pkg/tfgen/generate_schema_test.go @@ -152,6 +152,15 @@ func TestNestedMaxItemsOne(t *testing.T) { assert.Equal(t, schema, schema2) } +func TestNestedDescriptions(t *testing.T) { + provider := testprovider.ProviderNestedDescriptions() + schema, err := GenerateSchema(provider, diag.DefaultSink(io.Discard, io.Discard, diag.FormatOptions{ + Color: colors.Never, + })) + assert.NoError(t, err) + bridgetesting.AssertEqualsJSONFile(t, "test_data/nested-descriptions-schema.json", schema) +} + func TestRenameGeneration(t *testing.T) { info := testprovider.ProviderRegress611() diff --git a/pkg/tfgen/internal/testprovider/defaultinfo.go b/pkg/tfgen/internal/testprovider/defaultinfo.go index 86c90aeae..c7dd16c9a 100644 --- a/pkg/tfgen/internal/testprovider/defaultinfo.go +++ b/pkg/tfgen/internal/testprovider/defaultinfo.go @@ -15,30 +15,13 @@ package testprovider import ( - "unicode" - + testproviderdata "github.com/pulumi/pulumi-terraform-bridge/v3/internal/testprovider" "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge" shimv2 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2" - "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" - - testproviderdata "github.com/pulumi/pulumi-terraform-bridge/v3/internal/testprovider" ) func ProviderDefaultInfo() tfbridge.ProviderInfo { - member := func(mod string, mem string) tokens.ModuleMember { - return tokens.ModuleMember("cloudflare" + ":" + mod + ":" + mem) - } - - typ := func(mod string, typ string) tokens.Type { - return tokens.Type(member(mod, typ)) - } - - resource := func(mod string, res string) tokens.Type { - fn := string(unicode.ToLower(rune(res[0]))) + res[1:] - return typ(mod+"/"+fn, res) - } - return tfbridge.ProviderInfo{ P: shimv2.NewProvider(testproviderdata.ProviderDefaultInfo()), Name: "default-info", @@ -56,7 +39,7 @@ func ProviderDefaultInfo() tfbridge.ProviderInfo { }, Resources: map[string]*tfbridge.ResourceInfo{ "default_ruleset": { - Tok: resource("index", "Ruleset"), + Tok: tfbridge.MakeResource("cloudflare", "index", "Ruleset"), Fields: map[string]*tfbridge.SchemaInfo{ "rules": { Elem: &tfbridge.SchemaInfo{ diff --git a/pkg/tfgen/internal/testprovider/minicloudflare.go b/pkg/tfgen/internal/testprovider/minicloudflare.go index d42c3bc1e..1f71750ff 100644 --- a/pkg/tfgen/internal/testprovider/minicloudflare.go +++ b/pkg/tfgen/internal/testprovider/minicloudflare.go @@ -15,30 +15,13 @@ package testprovider import ( - "unicode" - + testproviderdata "github.com/pulumi/pulumi-terraform-bridge/v3/internal/testprovider" "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge" shimv2 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2" - "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" - - testproviderdata "github.com/pulumi/pulumi-terraform-bridge/v3/internal/testprovider" ) func ProviderMiniCloudflare() tfbridge.ProviderInfo { - member := func(mod string, mem string) tokens.ModuleMember { - return tokens.ModuleMember("cloudflare" + ":" + mod + ":" + mem) - } - - typ := func(mod string, typ string) tokens.Type { - return tokens.Type(member(mod, typ)) - } - - resource := func(mod string, res string) tokens.Type { - fn := string(unicode.ToLower(rune(res[0]))) + res[1:] - return typ(mod+"/"+fn, res) - } - return tfbridge.ProviderInfo{ P: shimv2.NewProvider(testproviderdata.ProviderMiniCloudflare()), Name: "cloudflare", @@ -49,7 +32,7 @@ func ProviderMiniCloudflare() tfbridge.ProviderInfo { Repository: "https://github.com/pulumi/pulumi-cloudflare", Resources: map[string]*tfbridge.ResourceInfo{ "cloudflare_ruleset": { - Tok: resource("index", "Ruleset"), + Tok: tfbridge.MakeResource("cloudflare", "index", "Ruleset"), Fields: map[string]*tfbridge.SchemaInfo{ "rules": { Elem: &tfbridge.SchemaInfo{ diff --git a/pkg/tfgen/internal/testprovider/nesteddescriptions.go b/pkg/tfgen/internal/testprovider/nesteddescriptions.go new file mode 100644 index 000000000..5e37b280d --- /dev/null +++ b/pkg/tfgen/internal/testprovider/nesteddescriptions.go @@ -0,0 +1,54 @@ +// Copyright 2016-2022, Pulumi Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package testprovider + +import ( + testproviderdata "github.com/pulumi/pulumi-terraform-bridge/v3/internal/testprovider" + "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge" + shimv2 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2" +) + +func ProviderNestedDescriptions() tfbridge.ProviderInfo { + return tfbridge.ProviderInfo{ + P: shimv2.NewProvider(testproviderdata.ProviderNestedDescriptions()), + Name: "cloudflare", + Description: "A Pulumi package to safely use cloudflare in Pulumi programs.", + Keywords: []string{"pulumi", "random"}, + License: "Apache-2.0", + Homepage: "https://pulumi.io", + Repository: "https://github.com/pulumi/pulumi-cloudflare", + Resources: map[string]*tfbridge.ResourceInfo{ + "cloudflare_ruleset": { + Tok: tfbridge.MakeResource("cloudflare", "index", "Ruleset"), + Fields: map[string]*tfbridge.SchemaInfo{ + "rules": { + Elem: &tfbridge.SchemaInfo{ + Fields: map[string]*tfbridge.SchemaInfo{ + "action_parameters": { + MaxItemsOne: tfbridge.True(), + Elem: &tfbridge.SchemaInfo{ + Fields: map[string]*tfbridge.SchemaInfo{ + "phases": {MaxItemsOne: tfbridge.True()}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} diff --git a/pkg/tfgen/test_data/nested-descriptions-schema.json b/pkg/tfgen/test_data/nested-descriptions-schema.json new file mode 100644 index 000000000..b9fa51117 --- /dev/null +++ b/pkg/tfgen/test_data/nested-descriptions-schema.json @@ -0,0 +1,138 @@ +{ + "name": "cloudflare", + "description": "A Pulumi package to safely use cloudflare in Pulumi programs.", + "keywords": [ + "pulumi", + "random" + ], + "homepage": "https://pulumi.io", + "license": "Apache-2.0", + "attribution": "This Pulumi package is based on the [`cloudflare` Terraform Provider](https://github.com/terraform-providers/terraform-provider-cloudflare).", + "repository": "https://github.com/pulumi/pulumi-cloudflare", + "meta": { + "moduleFormat": "(.*)(?:/[^/]*)" + }, + "language": { + "nodejs": { + "packageDescription": "A Pulumi package to safely use cloudflare in Pulumi programs.", + "readme": "\u003e This provider is a derived work of the [Terraform Provider](https://github.com/terraform-providers/terraform-provider-cloudflare)\n\u003e distributed under [MPL 2.0](https://www.mozilla.org/en-US/MPL/2.0/). If you encounter a bug or missing feature,\n\u003e first check the [`pulumi-cloudflare` repo](https://github.com/pulumi/pulumi-cloudflare/issues); however, if that doesn't turn up anything,\n\u003e please consult the source [`terraform-provider-cloudflare` repo](https://github.com/terraform-providers/terraform-provider-cloudflare/issues).", + "compatibility": "tfbridge20", + "disableUnionOutputTypes": true + }, + "python": { + "readme": "\u003e This provider is a derived work of the [Terraform Provider](https://github.com/terraform-providers/terraform-provider-cloudflare)\n\u003e distributed under [MPL 2.0](https://www.mozilla.org/en-US/MPL/2.0/). If you encounter a bug or missing feature,\n\u003e first check the [`pulumi-cloudflare` repo](https://github.com/pulumi/pulumi-cloudflare/issues); however, if that doesn't turn up anything,\n\u003e please consult the source [`terraform-provider-cloudflare` repo](https://github.com/terraform-providers/terraform-provider-cloudflare/issues).", + "compatibility": "tfbridge20", + "pyproject": {} + } + }, + "config": {}, + "types": { + "cloudflare:index/RulesetRule:RulesetRule": { + "properties": { + "actionParameters": { + "$ref": "#/types/cloudflare:index/RulesetRuleActionParameters:RulesetRuleActionParameters", + "description": "List of parameters that configure the behavior of the ruleset rule action.\n" + }, + "id": { + "type": "string", + "description": "Unique rule identifier.\n" + }, + "version": { + "type": "string", + "description": "Version of the ruleset to deploy.\n" + } + }, + "type": "object", + "language": { + "nodejs": { + "requiredOutputs": [ + "id", + "version" + ] + } + } + }, + "cloudflare:index/RulesetRuleActionParameters:RulesetRuleActionParameters": { + "properties": { + "id": { + "type": "string" + }, + "translateField": { + "type": "string", + "description": "When cloudflare.Ruleset is mentioned, it should be translated.\n" + } + }, + "type": "object" + } + }, + "provider": { + "description": "The provider type for the cloudflare package. By default, resources use package-wide configuration\nsettings, however an explicit `Provider` instance may be created and passed during resource\nconstruction to achieve fine-grained programmatic control over provider settings. See the\n[documentation](https://www.pulumi.com/docs/reference/programming-model/#providers) for more information.\n" + }, + "resources": { + "cloudflare:index/ruleset:Ruleset": { + "properties": { + "description": { + "type": "string", + "description": "Brief summary of the ruleset and its intended use.\n" + }, + "name": { + "type": "string", + "description": "Name of the ruleset.\n" + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/types/cloudflare:index/RulesetRule:RulesetRule" + }, + "description": "List of rules to apply to the ruleset.\n" + } + }, + "required": [ + "name" + ], + "inputProperties": { + "description": { + "type": "string", + "description": "Brief summary of the ruleset and its intended use.\n" + }, + "name": { + "type": "string", + "description": "Name of the ruleset.\n", + "willReplaceOnChanges": true + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/types/cloudflare:index/RulesetRule:RulesetRule" + }, + "description": "List of rules to apply to the ruleset.\n" + } + }, + "requiredInputs": [ + "name" + ], + "stateInputs": { + "description": "Input properties used for looking up and filtering Ruleset resources.\n", + "properties": { + "description": { + "type": "string", + "description": "Brief summary of the ruleset and its intended use.\n" + }, + "name": { + "type": "string", + "description": "Name of the ruleset.\n", + "willReplaceOnChanges": true + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/types/cloudflare:index/RulesetRule:RulesetRule" + }, + "description": "List of rules to apply to the ruleset.\n" + } + }, + "type": "object" + } + } + } +} diff --git a/pkg/tfgen/test_data/regress-minicloudflare-schema.json b/pkg/tfgen/test_data/regress-minicloudflare-schema.json index a352fc8c8..6caff3dd3 100644 --- a/pkg/tfgen/test_data/regress-minicloudflare-schema.json +++ b/pkg/tfgen/test_data/regress-minicloudflare-schema.json @@ -30,13 +30,16 @@ "cloudflare:index/RulesetRule:RulesetRule": { "properties": { "actionParameters": { - "$ref": "#/types/cloudflare:index/RulesetRuleActionParameters:RulesetRuleActionParameters" + "$ref": "#/types/cloudflare:index/RulesetRuleActionParameters:RulesetRuleActionParameters", + "description": "List of parameters that configure the behavior of the ruleset rule action.\n" }, "id": { - "type": "string" + "type": "string", + "description": "Unique rule identifier.\n" }, "version": { - "type": "string" + "type": "string", + "description": "Version of the ruleset to deploy.\n" } }, "type": "object", @@ -52,7 +55,8 @@ "cloudflare:index/RulesetRuleActionParameters:RulesetRuleActionParameters": { "properties": { "id": { - "type": "string" + "type": "string", + "description": "Identifier of the action parameter to modify.\n" }, "phases": { "$ref": "#/types/cloudflare:index/RulesetRuleActionParametersPhases:RulesetRuleActionParametersPhases"