From facb1751c897cae78cadf3708e5ce783c66400cd Mon Sep 17 00:00:00 2001 From: Stuart McLaren Date: Thu, 15 Aug 2024 14:29:19 +0100 Subject: [PATCH] Allow overriding computed_optional_required This can be useful, for example, when the person writing the Terraform provider does not control the contents of the OpenAPI spec. For example to set an attribute to "required": ``` attributes: overrides: name: description: The new description for name computed_optional_required: required ``` --- internal/config/parse.go | 2 + internal/explorer/config_explorer.go | 5 +- internal/explorer/config_explorer_test.go | 6 +- internal/explorer/explorer.go | 3 +- .../attrmapper/data_source_attributes_test.go | 26 ++++- internal/mapper/attrmapper/int64.go | 19 ++++ internal/mapper/attrmapper/int64_test.go | 3 +- internal/mapper/attrmapper/list_nested.go | 19 ++++ .../mapper/attrmapper/list_nested_test.go | 5 +- .../attrmapper/resource_attributes_test.go | 96 +++++++++++++++++++ internal/mapper/attrmapper/single_nested.go | 19 ++++ .../mapper/attrmapper/single_nested_test.go | 5 +- internal/mapper/attrmapper/string.go | 36 +++++++ 13 files changed, 232 insertions(+), 12 deletions(-) diff --git a/internal/config/parse.go b/internal/config/parse.go index a628e8aa..8b2f6637 100644 --- a/internal/config/parse.go +++ b/internal/config/parse.go @@ -82,6 +82,8 @@ type AttributeOptions struct { type Override struct { // Description overrides the description that was mapped/merged from the OpenAPI specification. Description string `yaml:"description"` + // ComputedOptionalRequired overrides the inferred value from the OpenAPI specification. + ComputedOptionalRequired string `yaml:"computed_optional_required"` } // ParseConfig takes in a byte array (of YAML), unmarshals into a Config struct, and validates the result diff --git a/internal/explorer/config_explorer.go b/internal/explorer/config_explorer.go index cc5fa13d..7265f164 100644 --- a/internal/explorer/config_explorer.go +++ b/internal/explorer/config_explorer.go @@ -211,7 +211,10 @@ func extractSchemaOptions(cfgSchemaOpts config.SchemaOptions) SchemaOptions { func extractOverrides(cfgOverrides map[string]config.Override) map[string]Override { overrides := make(map[string]Override, len(cfgOverrides)) for key, cfgOverride := range cfgOverrides { - overrides[key] = Override{Description: cfgOverride.Description} + overrides[key] = Override{ + Description: cfgOverride.Description, + ComputedOptionalRequired: cfgOverride.ComputedOptionalRequired, + } } return overrides diff --git a/internal/explorer/config_explorer_test.go b/internal/explorer/config_explorer_test.go index d929c6f8..68e78fb8 100644 --- a/internal/explorer/config_explorer_test.go +++ b/internal/explorer/config_explorer_test.go @@ -271,7 +271,8 @@ func Test_ConfigExplorer_FindResources(t *testing.T) { }, Overrides: map[string]config.Override{ "test": { - Description: "test description for override", + Description: "test description for override", + ComputedOptionalRequired: "computed_optional", }, }, }, @@ -311,7 +312,8 @@ func Test_ConfigExplorer_FindResources(t *testing.T) { }, Overrides: map[string]explorer.Override{ "test": { - Description: "test description for override", + Description: "test description for override", + ComputedOptionalRequired: "computed_optional", }, }, }, diff --git a/internal/explorer/explorer.go b/internal/explorer/explorer.go index 908b62c9..0a49b8c7 100644 --- a/internal/explorer/explorer.go +++ b/internal/explorer/explorer.go @@ -50,5 +50,6 @@ type AttributeOptions struct { } type Override struct { - Description string + Description string + ComputedOptionalRequired string } diff --git a/internal/mapper/attrmapper/data_source_attributes_test.go b/internal/mapper/attrmapper/data_source_attributes_test.go index 1535d9bd..38642504 100644 --- a/internal/mapper/attrmapper/data_source_attributes_test.go +++ b/internal/mapper/attrmapper/data_source_attributes_test.go @@ -244,10 +244,16 @@ func TestDataSourceAttributes_ApplyOverrides(t *testing.T) { "matching overrides": { overrides: map[string]explorer.Override{ "string_attribute": { - Description: "new string description", + Description: "new string description", + ComputedOptionalRequired: "optional", }, "float64_attribute": { - Description: "new float64 description", + Description: "new float64 description", + ComputedOptionalRequired: "required", + }, + "computed_optional_attribute": { + Description: "new computed_optional", + ComputedOptionalRequired: "computed_optional", }, }, attributes: attrmapper.DataSourceAttributes{ @@ -265,12 +271,19 @@ func TestDataSourceAttributes_ApplyOverrides(t *testing.T) { Description: pointer("old description"), }, }, + &attrmapper.DataSourceStringAttribute{ + Name: "computed_optional_attribute", + StringAttribute: datasource.StringAttribute{ + ComputedOptionalRequired: schema.Required, + Description: pointer("old description"), + }, + }, }, expectedAttributes: attrmapper.DataSourceAttributes{ &attrmapper.DataSourceStringAttribute{ Name: "string_attribute", StringAttribute: datasource.StringAttribute{ - ComputedOptionalRequired: schema.Required, + ComputedOptionalRequired: schema.Optional, Description: pointer("new string description"), }, }, @@ -281,6 +294,13 @@ func TestDataSourceAttributes_ApplyOverrides(t *testing.T) { Description: pointer("new float64 description"), }, }, + &attrmapper.DataSourceStringAttribute{ + Name: "computed_optional_attribute", + StringAttribute: datasource.StringAttribute{ + ComputedOptionalRequired: schema.ComputedOptional, + Description: pointer("new computed_optional"), + }, + }, }, }, "matching nested overrides": { diff --git a/internal/mapper/attrmapper/int64.go b/internal/mapper/attrmapper/int64.go index 0c0fe758..849ff7ef 100644 --- a/internal/mapper/attrmapper/int64.go +++ b/internal/mapper/attrmapper/int64.go @@ -4,11 +4,13 @@ package attrmapper import ( + "fmt" "github.com/hashicorp/terraform-plugin-codegen-openapi/internal/explorer" "github.com/hashicorp/terraform-plugin-codegen-openapi/internal/mapper/util" "github.com/hashicorp/terraform-plugin-codegen-spec/datasource" "github.com/hashicorp/terraform-plugin-codegen-spec/provider" "github.com/hashicorp/terraform-plugin-codegen-spec/resource" + "github.com/hashicorp/terraform-plugin-codegen-spec/schema" ) type ResourceInt64Attribute struct { @@ -34,6 +36,23 @@ func (a *ResourceInt64Attribute) Merge(mergeAttribute ResourceAttribute) (Resour func (a *ResourceInt64Attribute) ApplyOverride(override explorer.Override) (ResourceAttribute, error) { a.Description = &override.Description + switch override.ComputedOptionalRequired { + case "": // No override + case "computed": + a.ComputedOptionalRequired = schema.Computed + case "optional": + a.ComputedOptionalRequired = schema.Optional + case "required": + a.ComputedOptionalRequired = schema.Required + case "computed_optional": + a.ComputedOptionalRequired = schema.ComputedOptional + default: + return nil, fmt.Errorf( + "invalid value for computed_optional_required: %s", + override.ComputedOptionalRequired, + ) + } + return a, nil } diff --git a/internal/mapper/attrmapper/int64_test.go b/internal/mapper/attrmapper/int64_test.go index a3300447..bea9eca3 100644 --- a/internal/mapper/attrmapper/int64_test.go +++ b/internal/mapper/attrmapper/int64_test.go @@ -145,11 +145,12 @@ func TestResourceInt64Attribute_ApplyOverride(t *testing.T) { }, override: explorer.Override{ Description: "new description", + ComputedOptionalRequired: string(schema.Computed), }, expectedAttribute: &attrmapper.ResourceInt64Attribute{ Name: "test_attribute", Int64Attribute: resource.Int64Attribute{ - ComputedOptionalRequired: schema.Required, + ComputedOptionalRequired: schema.Computed, Description: pointer("new description"), }, }, diff --git a/internal/mapper/attrmapper/list_nested.go b/internal/mapper/attrmapper/list_nested.go index 68e07375..52a32a73 100644 --- a/internal/mapper/attrmapper/list_nested.go +++ b/internal/mapper/attrmapper/list_nested.go @@ -4,11 +4,13 @@ package attrmapper import ( + "fmt" "github.com/hashicorp/terraform-plugin-codegen-openapi/internal/explorer" "github.com/hashicorp/terraform-plugin-codegen-openapi/internal/mapper/util" "github.com/hashicorp/terraform-plugin-codegen-spec/datasource" "github.com/hashicorp/terraform-plugin-codegen-spec/provider" "github.com/hashicorp/terraform-plugin-codegen-spec/resource" + "github.com/hashicorp/terraform-plugin-codegen-spec/schema" ) type ResourceListNestedAttribute struct { @@ -40,6 +42,23 @@ func (a *ResourceListNestedAttribute) Merge(mergeAttribute ResourceAttribute) (R func (a *ResourceListNestedAttribute) ApplyOverride(override explorer.Override) (ResourceAttribute, error) { a.Description = &override.Description + switch override.ComputedOptionalRequired { + case "": // No override + case "computed": + a.ComputedOptionalRequired = schema.Computed + case "optional": + a.ComputedOptionalRequired = schema.Optional + case "required": + a.ComputedOptionalRequired = schema.Required + case "computed_optional": + a.ComputedOptionalRequired = schema.ComputedOptional + default: + return nil, fmt.Errorf( + "invalid value for computed_optional_required: %s", + override.ComputedOptionalRequired, + ) + } + return a, nil } diff --git a/internal/mapper/attrmapper/list_nested_test.go b/internal/mapper/attrmapper/list_nested_test.go index 51dcf5d9..197c6cea 100644 --- a/internal/mapper/attrmapper/list_nested_test.go +++ b/internal/mapper/attrmapper/list_nested_test.go @@ -527,7 +527,8 @@ func TestResourceListNestedAttribute_ApplyNestedOverride(t *testing.T) { }, overridePath: []string{"nested_attribute", "double_nested_attribute"}, override: explorer.Override{ - Description: "new description", + Description: "new description", + ComputedOptionalRequired: string(schema.Optional), }, expectedAttribute: &attrmapper.ResourceListNestedAttribute{ Name: "attribute", @@ -540,7 +541,7 @@ func TestResourceListNestedAttribute_ApplyNestedOverride(t *testing.T) { &attrmapper.ResourceStringAttribute{ Name: "double_nested_attribute", StringAttribute: resource.StringAttribute{ - ComputedOptionalRequired: schema.Required, + ComputedOptionalRequired: schema.Optional, Description: pointer("new description"), }, }, diff --git a/internal/mapper/attrmapper/resource_attributes_test.go b/internal/mapper/attrmapper/resource_attributes_test.go index 45d0be90..2060b5d5 100644 --- a/internal/mapper/attrmapper/resource_attributes_test.go +++ b/internal/mapper/attrmapper/resource_attributes_test.go @@ -283,6 +283,102 @@ func TestResourceAttributes_ApplyOverrides(t *testing.T) { }, }, }, + "matching overrides computed": { + overrides: map[string]explorer.Override{ + "string_attribute": { + ComputedOptionalRequired: "computed", + }, + }, + attributes: attrmapper.ResourceAttributes{ + &attrmapper.ResourceStringAttribute{ + Name: "string_attribute", + StringAttribute: resource.StringAttribute{ + ComputedOptionalRequired: schema.Required, + }, + }, + }, + expectedAttributes: attrmapper.ResourceAttributes{ + &attrmapper.ResourceStringAttribute{ + Name: "string_attribute", + StringAttribute: resource.StringAttribute{ + ComputedOptionalRequired: schema.Computed, + Description: pointer(""), + }, + }, + }, + }, + "matching overrides optional": { + overrides: map[string]explorer.Override{ + "string_attribute": { + ComputedOptionalRequired: "optional", + }, + }, + attributes: attrmapper.ResourceAttributes{ + &attrmapper.ResourceStringAttribute{ + Name: "string_attribute", + StringAttribute: resource.StringAttribute{ + ComputedOptionalRequired: schema.Required, + }, + }, + }, + expectedAttributes: attrmapper.ResourceAttributes{ + &attrmapper.ResourceStringAttribute{ + Name: "string_attribute", + StringAttribute: resource.StringAttribute{ + ComputedOptionalRequired: schema.Optional, + Description: pointer(""), + }, + }, + }, + }, + "matching overrides required": { + overrides: map[string]explorer.Override{ + "string_attribute": { + ComputedOptionalRequired: "required", + }, + }, + attributes: attrmapper.ResourceAttributes{ + &attrmapper.ResourceStringAttribute{ + Name: "string_attribute", + StringAttribute: resource.StringAttribute{ + ComputedOptionalRequired: schema.Computed, + }, + }, + }, + expectedAttributes: attrmapper.ResourceAttributes{ + &attrmapper.ResourceStringAttribute{ + Name: "string_attribute", + StringAttribute: resource.StringAttribute{ + ComputedOptionalRequired: schema.Required, + Description: pointer(""), + }, + }, + }, + }, + "matching overrides computed_optional": { + overrides: map[string]explorer.Override{ + "string_attribute": { + ComputedOptionalRequired: "computed_optional", + }, + }, + attributes: attrmapper.ResourceAttributes{ + &attrmapper.ResourceStringAttribute{ + Name: "string_attribute", + StringAttribute: resource.StringAttribute{ + ComputedOptionalRequired: schema.Computed, + }, + }, + }, + expectedAttributes: attrmapper.ResourceAttributes{ + &attrmapper.ResourceStringAttribute{ + Name: "string_attribute", + StringAttribute: resource.StringAttribute{ + ComputedOptionalRequired: schema.ComputedOptional, + Description: pointer(""), + }, + }, + }, + }, "matching nested overrides": { overrides: map[string]explorer.Override{ "single_nested": { diff --git a/internal/mapper/attrmapper/single_nested.go b/internal/mapper/attrmapper/single_nested.go index e83f1055..624127cd 100644 --- a/internal/mapper/attrmapper/single_nested.go +++ b/internal/mapper/attrmapper/single_nested.go @@ -4,11 +4,13 @@ package attrmapper import ( + "fmt" "github.com/hashicorp/terraform-plugin-codegen-openapi/internal/explorer" "github.com/hashicorp/terraform-plugin-codegen-openapi/internal/mapper/util" "github.com/hashicorp/terraform-plugin-codegen-spec/datasource" "github.com/hashicorp/terraform-plugin-codegen-spec/provider" "github.com/hashicorp/terraform-plugin-codegen-spec/resource" + "github.com/hashicorp/terraform-plugin-codegen-spec/schema" ) type ResourceSingleNestedAttribute struct { @@ -40,6 +42,23 @@ func (a *ResourceSingleNestedAttribute) Merge(mergeAttribute ResourceAttribute) func (a *ResourceSingleNestedAttribute) ApplyOverride(override explorer.Override) (ResourceAttribute, error) { a.Description = &override.Description + switch override.ComputedOptionalRequired { + case "": // No override + case "computed": + a.ComputedOptionalRequired = schema.Computed + case "optional": + a.ComputedOptionalRequired = schema.Optional + case "required": + a.ComputedOptionalRequired = schema.Required + case "computed_optional": + a.ComputedOptionalRequired = schema.ComputedOptional + default: + return nil, fmt.Errorf( + "invalid value for computed_optional_required: %s", + override.ComputedOptionalRequired, + ) + } + return a, nil } diff --git a/internal/mapper/attrmapper/single_nested_test.go b/internal/mapper/attrmapper/single_nested_test.go index 3642fa88..a70a03f5 100644 --- a/internal/mapper/attrmapper/single_nested_test.go +++ b/internal/mapper/attrmapper/single_nested_test.go @@ -353,7 +353,8 @@ func TestResourceSingleNestedAttribute_ApplyOverride(t *testing.T) { }, }, override: explorer.Override{ - Description: "new description", + ComputedOptionalRequired: "computed", + Description: "new description", }, expectedAttribute: &attrmapper.ResourceSingleNestedAttribute{ Name: "test_attribute", @@ -366,7 +367,7 @@ func TestResourceSingleNestedAttribute_ApplyOverride(t *testing.T) { }, }, SingleNestedAttribute: resource.SingleNestedAttribute{ - ComputedOptionalRequired: schema.Required, + ComputedOptionalRequired: schema.Computed, Description: pointer("new description"), }, }, diff --git a/internal/mapper/attrmapper/string.go b/internal/mapper/attrmapper/string.go index fc54a6ab..c9f088ae 100644 --- a/internal/mapper/attrmapper/string.go +++ b/internal/mapper/attrmapper/string.go @@ -4,11 +4,13 @@ package attrmapper import ( + "fmt" "github.com/hashicorp/terraform-plugin-codegen-openapi/internal/explorer" "github.com/hashicorp/terraform-plugin-codegen-openapi/internal/mapper/util" "github.com/hashicorp/terraform-plugin-codegen-spec/datasource" "github.com/hashicorp/terraform-plugin-codegen-spec/provider" "github.com/hashicorp/terraform-plugin-codegen-spec/resource" + "github.com/hashicorp/terraform-plugin-codegen-spec/schema" ) type ResourceStringAttribute struct { @@ -34,6 +36,23 @@ func (a *ResourceStringAttribute) Merge(mergeAttribute ResourceAttribute) (Resou func (a *ResourceStringAttribute) ApplyOverride(override explorer.Override) (ResourceAttribute, error) { a.Description = &override.Description + switch override.ComputedOptionalRequired { + case "": // No override + case "computed": + a.ComputedOptionalRequired = schema.Computed + case "optional": + a.ComputedOptionalRequired = schema.Optional + case "required": + a.ComputedOptionalRequired = schema.Required + case "computed_optional": + a.ComputedOptionalRequired = schema.ComputedOptional + default: + return nil, fmt.Errorf( + "invalid value for computed_optional_required: %s", + override.ComputedOptionalRequired, + ) + } + return a, nil } @@ -67,6 +86,23 @@ func (a *DataSourceStringAttribute) Merge(mergeAttribute DataSourceAttribute) (D func (a *DataSourceStringAttribute) ApplyOverride(override explorer.Override) (DataSourceAttribute, error) { a.Description = &override.Description + switch override.ComputedOptionalRequired { + case "": // No override + case "computed": + a.ComputedOptionalRequired = schema.Computed + case "optional": + a.ComputedOptionalRequired = schema.Optional + case "required": + a.ComputedOptionalRequired = schema.Required + case "computed_optional": + a.ComputedOptionalRequired = schema.ComputedOptional + default: + return nil, fmt.Errorf( + "invalid value for computed_optional_required: %s", + override.ComputedOptionalRequired, + ) + } + return a, nil }