From 5cdcd83691222f15599772caf6c15853d1619bdd Mon Sep 17 00:00:00 2001 From: Manuel Pedrozo Date: Tue, 4 Nov 2025 12:09:22 +0100 Subject: [PATCH 1/2] Improve TF schema attribute name generation --- go.mod | 1 - go.sum | 2 - .../common/autogen/stringcase/string_case.go | 75 ++++++++----------- .../autogen/stringcase/string_case_test.go | 75 ++++++++++++++++++- .../serviceapi/clusterapi/resource_schema.go | 13 ++-- .../serviceapi/clusterapi/resource_test.go | 2 +- .../databaseuserapi/resource_schema.go | 8 +- .../codespec/api_to_provider_spec_mapper.go | 16 ++-- .../api_to_provider_spec_mapper_test.go | 18 +++-- tools/codegen/codespec/attribute.go | 16 ++-- tools/codegen/codespec/config.go | 15 ++-- tools/codegen/codespec/merge_attributes.go | 6 +- tools/codegen/codespec/model.go | 53 +++++++------ .../config-nested-schema-overrides.yml | 1 + tools/codegen/config.yml | 20 ++--- .../gofilegen/resource/resource_file.go | 6 +- .../gofilegen/resource/resource_file_test.go | 16 ++-- tools/codegen/gofilegen/schema/schema_file.go | 2 +- .../gofilegen/schema/schema_file_test.go | 15 ++-- tools/codegen/gofilegen/schema/typed_model.go | 2 +- tools/codegen/main.go | 4 +- tools/codegen/models/auditing_api.yaml | 1 + tools/codegen/models/cluster_api.yaml | 9 ++- tools/codegen/models/custom_db_role_api.yaml | 1 + tools/codegen/models/database_user_api.yaml | 5 +- .../models/maintenance_window_api.yaml | 1 + .../models/org_service_account_api.yaml | 1 + tools/codegen/models/project_api.yaml | 1 + .../codegen/models/project_settings_api.yaml | 1 + .../models/push_based_log_export_api.yaml | 1 + tools/codegen/models/resource_policy_api.yaml | 1 + .../codegen/models/search_deployment_api.yaml | 1 + tools/codegen/models/search_index_api.yaml | 1 + tools/codegen/models/stream_instance_api.yaml | 1 + .../codegen/models/stream_processor_api.yaml | 1 + 35 files changed, 235 insertions(+), 157 deletions(-) diff --git a/go.mod b/go.mod index eed32d4867..29b7544581 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,6 @@ require ( github.com/hashicorp/terraform-plugin-mux v0.21.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 github.com/hashicorp/terraform-plugin-testing v1.13.3 - github.com/huandu/xstrings v1.5.0 github.com/jarcoal/httpmock v1.4.1 github.com/mongodb-forks/digest v1.1.0 github.com/mongodb/atlas-sdk-go v1.0.1-0.20251103084024-4a19449c6541 diff --git a/go.sum b/go.sum index de802a12e2..1f8c1ac80d 100644 --- a/go.sum +++ b/go.sum @@ -345,8 +345,6 @@ github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8 github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= -github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= diff --git a/internal/common/autogen/stringcase/string_case.go b/internal/common/autogen/stringcase/string_case.go index e3c8433a37..6c4faa857d 100644 --- a/internal/common/autogen/stringcase/string_case.go +++ b/internal/common/autogen/stringcase/string_case.go @@ -1,60 +1,49 @@ package stringcase import ( - "fmt" "regexp" "strings" "unicode" "unicode/utf8" - - "github.com/huandu/xstrings" -) - -var ( - camelCase = regexp.MustCompile(`([a-z])[A-Z]`) - unsupportedCharacters = regexp.MustCompile(`[^a-zA-Z0-9_]+`) ) -type SnakeCaseString string - -func (snake SnakeCaseString) SnakeCase() string { - return string(snake) -} - -func (snake SnakeCaseString) PascalCase() string { - return xstrings.ToPascalCase(string(snake)) -} - -func (snake SnakeCaseString) CamelCase() string { - return xstrings.ToCamelCase(string(snake)) -} - -func (snake SnakeCaseString) LowerCaseNoUnderscore() string { - return strings.ReplaceAll(string(snake), "_", "") -} +var unsupportedCharacters = regexp.MustCompile(`[^a-zA-Z0-9_]+`) -func FromCamelCase(input string) SnakeCaseString { - if input == "" { - return SnakeCaseString(input) +// ToSnakeCase Multiple consecutive uppercase letters are treated as part of the same word except for the last one. +// Example: "MongoDBMajorVersion" -> "mongo_db_major_version" +func ToSnakeCase(str string) string { + if str == "" { + return str } - removedUnsupported := unsupportedCharacters.ReplaceAllString(input, "") - - insertedUnderscores := camelCase.ReplaceAllStringFunc(removedUnsupported, func(s string) string { - firstChar := s[0] - restOfString := s[1:] - return fmt.Sprintf("%c_%s", firstChar, strings.ToLower(restOfString)) - }) - - return SnakeCaseString(strings.ToLower(insertedUnderscores)) -} + str = unsupportedCharacters.ReplaceAllString(str, "") -func ToCamelCase(str string) string { - return xstrings.ToCamelCase(str) -} + builder := &strings.Builder{} + runes := []rune(str) + length := len(runes) + + prevIsUpper := unicode.IsUpper(runes[0]) + builder.WriteRune(unicode.ToLower(runes[0])) + + for i := 1; i < length; i++ { + current := runes[i] + currentIsUpper := unicode.IsUpper(runes[i]) + + // Write an underscore before uppercase letter if: + // - Previous char was lowercase, so this is the first uppercase. + // - Next char is lowercase, so this is the last uppercase in a sequence. + if currentIsUpper { + if !prevIsUpper || (i+1 != length && unicode.IsLower(runes[i+1])) { + builder.WriteByte('_') + } + current = unicode.ToLower(current) + } + + builder.WriteRune(current) + prevIsUpper = currentIsUpper + } -func ToSnakeCase(str string) string { - return xstrings.ToSnakeCase(str) + return builder.String() } func Capitalize(str string) string { diff --git a/internal/common/autogen/stringcase/string_case_test.go b/internal/common/autogen/stringcase/string_case_test.go index 097e9ac882..0bcaef0585 100644 --- a/internal/common/autogen/stringcase/string_case_test.go +++ b/internal/common/autogen/stringcase/string_case_test.go @@ -46,7 +46,7 @@ func TestCapitalize(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if actual := stringcase.Capitalize(tt.input); actual != tt.expected { - t.Errorf("Capitalize() returned %v, expected %v", actual, tt.expected) + t.Errorf("Capitalize(%q) returned %q, expected %q", tt.input, actual, tt.expected) } }) } @@ -92,7 +92,78 @@ func TestUncapitalize(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if actual := stringcase.Uncapitalize(tt.input); actual != tt.expected { - t.Errorf("Uncapitalize() returned %v, expected %v", actual, tt.expected) + t.Errorf("Uncapitalize(%q) returned %q, expected %q", tt.input, actual, tt.expected) + } + }) + } +} + +func TestToSnakeCase(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + { + name: "Empty string", + input: "", + expected: "", + }, + { + name: "Single letter", + input: "a", + expected: "a", + }, + { + name: "Single uppercase letter", + input: "A", + expected: "a", + }, + { + name: "Simple camelCase", + input: "camelCase", + expected: "camel_case", + }, + { + name: "Simple PascalCase", + input: "PascalCase", + expected: "pascal_case", + }, + { + name: "All lowercase", + input: "word", + expected: "word", + }, + { + name: "All uppercase", + input: "WORD", + expected: "word", + }, + { + name: "Consecutive uppercase at start, middle and end", + input: "THISIsANExampleWORD", + expected: "this_is_an_example_word", + }, + { + name: "Numbers do not split words", + input: "Example123Word456WithNUMBERS789", + expected: "example123_word456_with_numbers789", + }, + { + name: "Already snake_case", + input: "already_snake_case", + expected: "already_snake_case", + }, + { + name: "Unsupported characters are removed", + input: "Example#!Unsup-.ported%&Chars", + expected: "example_unsupported_chars", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if actual := stringcase.ToSnakeCase(tt.input); actual != tt.expected { + t.Errorf("ToSnakeCase(%q) returned %q, expected %q", tt.input, actual, tt.expected) } }) } diff --git a/internal/serviceapi/clusterapi/resource_schema.go b/internal/serviceapi/clusterapi/resource_schema.go index 6e704a4044..f306e901f2 100755 --- a/internal/serviceapi/clusterapi/resource_schema.go +++ b/internal/serviceapi/clusterapi/resource_schema.go @@ -219,7 +219,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, - "mongo_dbemployee_access_grant": schema.SingleNestedAttribute{ + "mongo_db_employee_access_grant": schema.SingleNestedAttribute{ Optional: true, MarkdownDescription: "MongoDB employee granted access level and expiration for a cluster.", CustomType: customtypes.NewObjectType[TFMongoDBEmployeeAccessGrantModel](ctx), @@ -234,12 +234,11 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, - "mongo_dbmajor_version": schema.StringAttribute{ - Computed: true, + "mongo_db_major_version": schema.StringAttribute{ Optional: true, MarkdownDescription: "MongoDB major version of the cluster. Set to the binary major version. \n\nOn creation: Choose from the available versions of MongoDB, or leave unspecified for the current recommended default in the MongoDB Cloud platform. The recommended version is a recent Long Term Support version. The default is not guaranteed to be the most recently released version throughout the entire release cycle. For versions available in a specific project, see the linked documentation or use the API endpoint for [project LTS versions endpoint](#tag/Projects/operation/getProjectLtsVersions).\n\n On update: Increase version only by 1 major version at a time. If the cluster is pinned to a MongoDB feature compatibility version exactly one major version below the current MongoDB version, the MongoDB version can be downgraded to the previous major version.", }, - "mongo_dbversion": schema.StringAttribute{ + "mongo_db_version": schema.StringAttribute{ Computed: true, MarkdownDescription: "Version of MongoDB that the cluster runs.", }, @@ -653,14 +652,14 @@ type TFModel struct { Tags customtypes.NestedListValue[TFTagsModel] `tfsdk:"tags"` ReplicationSpecs customtypes.NestedListValue[TFReplicationSpecsModel] `tfsdk:"replication_specs"` InternalClusterRole types.String `tfsdk:"internal_cluster_role" autogen:"omitjson"` - MongoDBVersion types.String `tfsdk:"mongo_dbversion" autogen:"omitjson"` + MongoDBVersion types.String `tfsdk:"mongo_db_version" autogen:"omitjson"` ConfigServerManagementMode types.String `tfsdk:"config_server_management_mode"` ConfigServerType types.String `tfsdk:"config_server_type" autogen:"omitjson"` ConnectionStrings customtypes.ObjectValue[TFConnectionStringsModel] `tfsdk:"connection_strings" autogen:"omitjson"` CreateDate types.String `tfsdk:"create_date" autogen:"omitjson"` DiskWarmingMode types.String `tfsdk:"disk_warming_mode"` EncryptionAtRestProvider types.String `tfsdk:"encryption_at_rest_provider"` - MongoDBMajorVersion types.String `tfsdk:"mongo_dbmajor_version"` + MongoDBMajorVersion types.String `tfsdk:"mongo_db_major_version"` FeatureCompatibilityVersionExpirationDate types.String `tfsdk:"feature_compatibility_version_expiration_date" autogen:"omitjson"` Timeouts timeouts.Value `tfsdk:"timeouts" autogen:"omitjson"` GroupId types.String `tfsdk:"group_id" autogen:"omitjson"` @@ -669,7 +668,7 @@ type TFModel struct { ClusterType types.String `tfsdk:"cluster_type"` BiConnector customtypes.ObjectValue[TFBiConnectorModel] `tfsdk:"bi_connector"` FeatureCompatibilityVersion types.String `tfsdk:"feature_compatibility_version" autogen:"omitjson"` - MongoDBEmployeeAccessGrant customtypes.ObjectValue[TFMongoDBEmployeeAccessGrantModel] `tfsdk:"mongo_dbemployee_access_grant"` + MongoDBEmployeeAccessGrant customtypes.ObjectValue[TFMongoDBEmployeeAccessGrantModel] `tfsdk:"mongo_db_employee_access_grant"` Name types.String `tfsdk:"name"` VersionReleaseSystem types.String `tfsdk:"version_release_system"` AdvancedConfiguration customtypes.ObjectValue[TFAdvancedConfigurationModel] `tfsdk:"advanced_configuration"` diff --git a/internal/serviceapi/clusterapi/resource_test.go b/internal/serviceapi/clusterapi/resource_test.go index 4b4ba107e5..7310b8101f 100644 --- a/internal/serviceapi/clusterapi/resource_test.go +++ b/internal/serviceapi/clusterapi/resource_test.go @@ -43,7 +43,7 @@ func TestAccClusterAPI_basic(t *testing.T) { ImportStateVerifyIdentifierAttribute: "name", ImportStateVerifyIgnore: []string{ "retain_backups_enabled", // This field is TF specific and not returned by Atlas, so Import can't fill it in. - "mongo_dbmajor_version", // Risks plan change of 8 --> 8.0 (always normalized to `major.minor`) + "mongo_db_major_version", // Risks plan change of 8 --> 8.0 (always normalized to `major.minor`) "state_name", // Cluster state can change from IDLE to UPDATING and risks making the test flaky "delete_on_create_timeout", // This field is TF specific and not returned by Atlas, so Import can't fill it in. }, diff --git a/internal/serviceapi/databaseuserapi/resource_schema.go b/internal/serviceapi/databaseuserapi/resource_schema.go index ebc9b0a262..7cff2a917e 100755 --- a/internal/serviceapi/databaseuserapi/resource_schema.go +++ b/internal/serviceapi/databaseuserapi/resource_schema.go @@ -13,7 +13,7 @@ import ( func ResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ - "aws_iamtype": schema.StringAttribute{ + "aws_iam_type": schema.StringAttribute{ Computed: true, Optional: true, MarkdownDescription: "Human-readable label that indicates whether the new database user authenticates with the Amazon Web Services (AWS) Identity and Access Management (IAM) credentials associated with the user or the user's role.", @@ -109,7 +109,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { Required: true, MarkdownDescription: "Human-readable label that represents the user that authenticates to MongoDB. The format of this label depends on the method of authentication:\n\n| Authentication Method | Parameter Needed | Parameter Value | username Format |\n|---|---|---|---|\n| AWS IAM | awsIAMType | ROLE | ARN |\n| AWS IAM | awsIAMType | USER | ARN |\n| x.509 | x509Type | CUSTOMER | [RFC 2253](https://tools.ietf.org/html/2253) Distinguished Name |\n| x.509 | x509Type | MANAGED | [RFC 2253](https://tools.ietf.org/html/2253) Distinguished Name |\n| LDAP | ldapAuthType | USER | [RFC 2253](https://tools.ietf.org/html/2253) Distinguished Name |\n| LDAP | ldapAuthType | GROUP | [RFC 2253](https://tools.ietf.org/html/2253) Distinguished Name |\n| OIDC Workforce | oidcAuthType | IDP_GROUP | Atlas OIDC IdP ID (found in federation settings), followed by a '/', followed by the IdP group name |\n| OIDC Workload | oidcAuthType | USER | Atlas OIDC IdP ID (found in federation settings), followed by a '/', followed by the IdP user name |\n| SCRAM-SHA | awsIAMType, x509Type, ldapAuthType, oidcAuthType | NONE | Alphanumeric string |\n", }, - "x509type": schema.StringAttribute{ + "x509_type": schema.StringAttribute{ Computed: true, Optional: true, MarkdownDescription: "X.509 method that MongoDB Cloud uses to authenticate the database user.\n\n- For application-managed X.509, specify `MANAGED`.\n- For self-managed X.509, specify `CUSTOMER`.\n\nUsers created with the `CUSTOMER` method require a Common Name (CN) in the **username** parameter. You must create externally authenticated users on the `$external` database.", @@ -119,7 +119,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { } type TFModel struct { - AwsIAMType types.String `tfsdk:"aws_iamtype"` + AwsIAMType types.String `tfsdk:"aws_iam_type"` DatabaseName types.String `tfsdk:"database_name"` DeleteAfterDate types.String `tfsdk:"delete_after_date"` Description types.String `tfsdk:"description" autogen:"includenullonupdate"` @@ -131,7 +131,7 @@ type TFModel struct { Roles customtypes.NestedListValue[TFRolesModel] `tfsdk:"roles"` Scopes customtypes.NestedListValue[TFScopesModel] `tfsdk:"scopes"` Username types.String `tfsdk:"username"` - X509Type types.String `tfsdk:"x509type"` + X509Type types.String `tfsdk:"x509_type"` } type TFLabelsModel struct { Key types.String `tfsdk:"key"` diff --git a/tools/codegen/codespec/api_to_provider_spec_mapper.go b/tools/codegen/codespec/api_to_provider_spec_mapper.go index 07be001fbc..8e9edf5d1d 100644 --- a/tools/codegen/codespec/api_to_provider_spec_mapper.go +++ b/tools/codegen/codespec/api_to_provider_spec_mapper.go @@ -6,7 +6,6 @@ import ( "log" "strings" - "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/autogen/stringcase" high "github.com/pb33f/libopenapi/datamodel/high/v3" low "github.com/pb33f/libopenapi/datamodel/low/v3" "github.com/pb33f/libopenapi/orderedmap" @@ -47,12 +46,12 @@ func ToCodeSpecModel(atlasAdminAPISpecFilePath, configPath string, resourceName for name, resourceConfig := range resourceConfigsToIterate { log.Printf("[INFO] Generating resource model: %s", name) // find resource operations, schemas, etc from OAS - oasResource, err := getAPISpecResource(&apiSpec.Model, &resourceConfig, stringcase.SnakeCaseString(name)) + oasResource, err := getAPISpecResource(&apiSpec.Model, &resourceConfig, name) if err != nil { return nil, fmt.Errorf("unable to get APISpecResource schema: %v", err) } // map OAS resource model to CodeSpecModel - resource, err := apiSpecResourceToCodeSpecModel(oasResource, &resourceConfig, stringcase.SnakeCaseString(name)) + resource, err := apiSpecResourceToCodeSpecModel(oasResource, &resourceConfig, name) if err != nil { return nil, fmt.Errorf("unable to map to code spec model for %s: %w", name, err) } @@ -81,7 +80,7 @@ func validateRequiredOperations(resourceConfigs map[string]config.Resource) erro return nil } -func apiSpecResourceToCodeSpecModel(oasResource APISpecResource, resourceConfig *config.Resource, name stringcase.SnakeCaseString) (*Resource, error) { +func apiSpecResourceToCodeSpecModel(oasResource APISpecResource, resourceConfig *config.Resource, name string) (*Resource, error) { createOp := oasResource.CreateOp updateOp := oasResource.UpdateOp readOp := oasResource.ReadOp @@ -117,9 +116,10 @@ func apiSpecResourceToCodeSpecModel(oasResource APISpecResource, resourceConfig operations.VersionHeader = getLatestVersionFromAPISpec(readOp) } resource := &Resource{ - Name: name, - Schema: schema, - Operations: operations, + Name: name, + PackageName: strings.ReplaceAll(name, "_", ""), + Schema: schema, + Operations: operations, } applyTransformationsWithConfigOpts(resourceConfig, resource) @@ -234,7 +234,7 @@ func opResponseToAttributes(op *high.Operation) Attributes { return responseAttributes } -func getAPISpecResource(spec *high.Document, resourceConfig *config.Resource, name stringcase.SnakeCaseString) (APISpecResource, error) { +func getAPISpecResource(spec *high.Document, resourceConfig *config.Resource, name string) (APISpecResource, error) { var errResult error var resourceDeprecationMsg *string diff --git a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go index fbcc38d33d..f6f09b67c1 100644 --- a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go +++ b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go @@ -109,7 +109,8 @@ func TestConvertToProviderSpec(t *testing.T) { }, }, }, - Name: "test_resource_no_schema_opts", + Name: "test_resource_no_schema_opts", + PackageName: "testresourcenoschemaopts", Operations: codespec.APIOperations{ Create: codespec.APIOperation{ Path: "/api/atlas/v2/groups/{groupId}/testResource", @@ -365,7 +366,8 @@ func TestConvertToProviderSpec_nested(t *testing.T) { }, }, }, - Name: "test_resource_with_nested_attr", + Name: "test_resource_with_nested_attr", + PackageName: "testresourcewithnestedattr", Operations: codespec.APIOperations{ Create: codespec.APIOperation{ Path: "/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/nestedTestResource", @@ -496,7 +498,8 @@ func TestConvertToProviderSpec_nested_schemaOverrides(t *testing.T) { }, }, }, - Name: "test_resource_with_nested_attr_overrides", + Name: "test_resource_with_nested_attr_overrides", + PackageName: "testresourcewithnestedattroverrides", Operations: codespec.APIOperations{ Create: codespec.APIOperation{ Path: "/api/atlas/v2/groups/{projectId}/clusters/{clusterName}/nestedTestResource", @@ -562,7 +565,8 @@ func TestConvertToProviderSpec_pathParamPresentInPostRequest(t *testing.T) { }, }, }, - Name: "test_resource_path_param_in_post_req", + Name: "test_resource_path_param_in_post_req", + PackageName: "testresourcepathparaminpostreq", Operations: codespec.APIOperations{ Create: codespec.APIOperation{ Path: "/api/atlas/v2/groups/{groupId}/pathparaminpostreq", @@ -618,7 +622,8 @@ func TestConvertToProviderSpec_singletonResourceNoDeleteOperation(t *testing.T) }, }, }, - Name: "test_singleton_resource_no_delete_op", + Name: "test_singleton_resource_no_delete_op", + PackageName: "testsingletonresourcenodeleteop", Operations: codespec.APIOperations{ Create: codespec.APIOperation{ Path: "/api/atlas/v2/groups/{groupId}/testSingletonResource", @@ -688,7 +693,8 @@ func TestConvertToProviderSpec_typeOverride(t *testing.T) { }, }, }, - Name: "test_resource_with_overridden_collection_types", + Name: "test_resource_with_overridden_collection_types", + PackageName: "testresourcewithoverriddencollectiontypes", Operations: codespec.APIOperations{ Create: codespec.APIOperation{ Path: "/api/atlas/v2/groups/{groupId}/testResourceWithCollections", diff --git a/tools/codegen/codespec/attribute.go b/tools/codegen/codespec/attribute.go index 54ab092ac7..2e4f012c92 100644 --- a/tools/codegen/codespec/attribute.go +++ b/tools/codegen/codespec/attribute.go @@ -63,7 +63,7 @@ func (s *APISpecSchema) buildResourceAttr(name, ancestorsName string, computabil func (s *APISpecSchema) buildStringAttr(name string, computability ComputedOptionalRequired) (*Attribute, error) { result := &Attribute{ - TFSchemaName: stringcase.FromCamelCase(name), + TFSchemaName: stringcase.ToSnakeCase(name), TFModelName: stringcase.Capitalize(name), ComputedOptionalRequired: computability, DeprecationMessage: s.GetDeprecationMessage(), @@ -86,7 +86,7 @@ func (s *APISpecSchema) buildStringAttr(name string, computability ComputedOptio func (s *APISpecSchema) buildIntegerAttr(name string, computability ComputedOptionalRequired) (*Attribute, error) { result := &Attribute{ - TFSchemaName: stringcase.FromCamelCase(name), + TFSchemaName: stringcase.ToSnakeCase(name), TFModelName: stringcase.Capitalize(name), ComputedOptionalRequired: computability, DeprecationMessage: s.GetDeprecationMessage(), @@ -109,7 +109,7 @@ func (s *APISpecSchema) buildIntegerAttr(name string, computability ComputedOpti func (s *APISpecSchema) buildNumberAttr(name string, computability ComputedOptionalRequired) (*Attribute, error) { if s.Schema.Format == OASFormatDouble || s.Schema.Format == OASFormatFloat { result := &Attribute{ - TFSchemaName: stringcase.FromCamelCase(name), + TFSchemaName: stringcase.ToSnakeCase(name), TFModelName: stringcase.Capitalize(name), ComputedOptionalRequired: computability, DeprecationMessage: s.GetDeprecationMessage(), @@ -130,7 +130,7 @@ func (s *APISpecSchema) buildNumberAttr(name string, computability ComputedOptio } return &Attribute{ - TFSchemaName: stringcase.FromCamelCase(name), + TFSchemaName: stringcase.ToSnakeCase(name), TFModelName: stringcase.Capitalize(name), ComputedOptionalRequired: computability, DeprecationMessage: s.GetDeprecationMessage(), @@ -141,7 +141,7 @@ func (s *APISpecSchema) buildNumberAttr(name string, computability ComputedOptio func (s *APISpecSchema) buildBoolAttr(name string, computability ComputedOptionalRequired) (*Attribute, error) { result := &Attribute{ - TFSchemaName: stringcase.FromCamelCase(name), + TFSchemaName: stringcase.ToSnakeCase(name), TFModelName: stringcase.Capitalize(name), ComputedOptionalRequired: computability, DeprecationMessage: s.GetDeprecationMessage(), @@ -176,7 +176,7 @@ func (s *APISpecSchema) buildArrayAttr(name, ancestorsName string, computability createAttribute := func(nestedObject *NestedAttributeObject, nestedObjectName *string, elemType ElemType) *Attribute { var ( attr = &Attribute{ - TFSchemaName: stringcase.FromCamelCase(name), + TFSchemaName: stringcase.ToSnakeCase(name), TFModelName: tfModelName, ComputedOptionalRequired: computability, DeprecationMessage: s.GetDeprecationMessage(), @@ -247,7 +247,7 @@ func (s *APISpecSchema) buildMapAttr(name, ancestorsName string, computability C } result := &Attribute{ - TFSchemaName: stringcase.FromCamelCase(name), + TFSchemaName: stringcase.ToSnakeCase(name), TFModelName: stringcase.Capitalize(name), ComputedOptionalRequired: computability, DeprecationMessage: s.GetDeprecationMessage(), @@ -284,7 +284,7 @@ func (s *APISpecSchema) buildMapAttr(name, ancestorsName string, computability C func (s *APISpecSchema) buildSingleNestedAttr(name, ancestorsName string, computability ComputedOptionalRequired, isFromRequest bool) (*Attribute, error) { attr := &Attribute{ - TFSchemaName: stringcase.FromCamelCase(name), + TFSchemaName: stringcase.ToSnakeCase(name), TFModelName: stringcase.Capitalize(name), ComputedOptionalRequired: computability, DeprecationMessage: s.GetDeprecationMessage(), diff --git a/tools/codegen/codespec/config.go b/tools/codegen/codespec/config.go index 88adb89d54..d7f50ba3e4 100644 --- a/tools/codegen/codespec/config.go +++ b/tools/codegen/codespec/config.go @@ -5,7 +5,6 @@ import ( "log" "strings" - "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/autogen/stringcase" "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" "github.com/mongodb/terraform-provider-mongodbatlas/tools/codegen/config" ) @@ -39,7 +38,7 @@ func applyAttributeTransformations(schemaOptions config.SchemaOptions, attribute for i := range *attributes { attr := &(*attributes)[i] - attrPathName := getAttributePathName(string(attr.TFSchemaName), parentName) + attrPathName := getAttributePathName(attr.TFSchemaName, parentName) if shouldIgnoreAttribute(attrPathName, ignoredAttrs) { continue @@ -96,7 +95,7 @@ func applyAliasToAttribute(attr *Attribute, attrPathName *string, schemaOptions parts[i] = newName if i == len(parts)-1 { - attr.TFSchemaName = stringcase.SnakeCaseString(newName) + attr.TFSchemaName = newName } } } @@ -106,13 +105,11 @@ func applyAliasToAttribute(attr *Attribute, attrPathName *string, schemaOptions func applyAliasToPathParams(resource *Resource, aliases map[string]string) { for original, alias := range aliases { - originalCamel := stringcase.SnakeCaseString(original).CamelCase() - aliasCamel := stringcase.SnakeCaseString(alias).CamelCase() - resource.Operations.Create.Path = strings.ReplaceAll(resource.Operations.Create.Path, fmt.Sprintf("{%s}", originalCamel), fmt.Sprintf("{%s}", aliasCamel)) - resource.Operations.Read.Path = strings.ReplaceAll(resource.Operations.Read.Path, fmt.Sprintf("{%s}", originalCamel), fmt.Sprintf("{%s}", aliasCamel)) - resource.Operations.Update.Path = strings.ReplaceAll(resource.Operations.Update.Path, fmt.Sprintf("{%s}", originalCamel), fmt.Sprintf("{%s}", aliasCamel)) + resource.Operations.Create.Path = strings.ReplaceAll(resource.Operations.Create.Path, fmt.Sprintf("{%s}", original), fmt.Sprintf("{%s}", alias)) + resource.Operations.Read.Path = strings.ReplaceAll(resource.Operations.Read.Path, fmt.Sprintf("{%s}", original), fmt.Sprintf("{%s}", alias)) + resource.Operations.Update.Path = strings.ReplaceAll(resource.Operations.Update.Path, fmt.Sprintf("{%s}", original), fmt.Sprintf("{%s}", alias)) if resource.Operations.Delete != nil { - resource.Operations.Delete.Path = strings.ReplaceAll(resource.Operations.Delete.Path, fmt.Sprintf("{%s}", originalCamel), fmt.Sprintf("{%s}", aliasCamel)) + resource.Operations.Delete.Path = strings.ReplaceAll(resource.Operations.Delete.Path, fmt.Sprintf("{%s}", original), fmt.Sprintf("{%s}", alias)) } } } diff --git a/tools/codegen/codespec/merge_attributes.go b/tools/codegen/codespec/merge_attributes.go index dc1078924a..1008ad4ba9 100644 --- a/tools/codegen/codespec/merge_attributes.go +++ b/tools/codegen/codespec/merge_attributes.go @@ -9,7 +9,7 @@ func mergeNestedAttributes(existingAttrs *Attributes, newAttrs Attributes, reqBo mergedMap := make(map[string]*Attribute) if existingAttrs != nil { for i := range *existingAttrs { - mergedMap[(*existingAttrs)[i].TFSchemaName.SnakeCase()] = &(*existingAttrs)[i] + mergedMap[(*existingAttrs)[i].TFSchemaName] = &(*existingAttrs)[i] } } @@ -44,14 +44,14 @@ func mergeComputability(first, second ComputedOptionalRequired) ComputedOptional // addOrUpdate adds or updates an attribute in the merged map, including nested attributes func addOrUpdate(merged map[string]*Attribute, newAttr *Attribute, reqBodyUsage AttributeReqBodyUsage, isFromResponse bool) { - if existingAttr, found := merged[newAttr.TFSchemaName.SnakeCase()]; found { + if existingAttr, found := merged[newAttr.TFSchemaName]; found { updateAttrWithNewSource(existingAttr, newAttr, reqBodyUsage, isFromResponse) } else { if isFromResponse { newAttr.ComputedOptionalRequired = Computed // setting as computed as attribute was defined only in response } newAttr.ReqBodyUsage = reqBodyUsage - merged[newAttr.TFSchemaName.SnakeCase()] = newAttr + merged[newAttr.TFSchemaName] = newAttr } } diff --git a/tools/codegen/codespec/model.go b/tools/codegen/codespec/model.go index 074e0bf997..041b63113e 100644 --- a/tools/codegen/codespec/model.go +++ b/tools/codegen/codespec/model.go @@ -2,8 +2,6 @@ package codespec import ( "fmt" - - "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/autogen/stringcase" ) type ElemType int @@ -41,9 +39,10 @@ type Model struct { } type Resource struct { - Schema *Schema `yaml:"schema,omitempty"` - Operations APIOperations `yaml:"operations"` - Name stringcase.SnakeCaseString `yaml:"name"` + Schema *Schema `yaml:"schema,omitempty"` + Operations APIOperations `yaml:"operations"` + Name string `yaml:"name"` + PackageName string `yaml:"packageName"` } type APIOperations struct { @@ -82,28 +81,28 @@ type Attributes []Attribute // Add this field to the Attribute struct // Usage AttributeUsage type Attribute struct { - Set *SetAttribute `yaml:"set,omitempty"` - String *StringAttribute `yaml:"string,omitempty"` - Float64 *Float64Attribute `yaml:"float64,omitempty"` - List *ListAttribute `yaml:"list,omitempty"` - Bool *BoolAttribute `yaml:"bool,omitempty"` - ListNested *ListNestedAttribute `yaml:"list_nested,omitempty"` - Map *MapAttribute `yaml:"map,omitempty"` - MapNested *MapNestedAttribute `yaml:"map_nested,omitempty"` - Number *NumberAttribute `yaml:"number,omitempty"` - Int64 *Int64Attribute `yaml:"int64,omitempty"` - Timeouts *TimeoutsAttribute `yaml:"timeouts,omitempty"` - SingleNested *SingleNestedAttribute `yaml:"single_nested,omitempty"` - SetNested *SetNestedAttribute `yaml:"set_nested,omitempty"` - Description *string `yaml:"description,omitempty"` - DeprecationMessage *string `yaml:"deprecation_message,omitempty"` - CustomType *CustomType `yaml:"custom_type,omitempty"` - ComputedOptionalRequired ComputedOptionalRequired `yaml:"computed_optional_required"` - TFSchemaName stringcase.SnakeCaseString `yaml:"tf_schema_name"` - TFModelName string `yaml:"tf_model_name"` - ReqBodyUsage AttributeReqBodyUsage `yaml:"req_body_usage"` - Sensitive bool `yaml:"sensitive"` - CreateOnly bool `yaml:"create_only"` // leveraged for defining plan modifier which avoids updates on this attribute + Set *SetAttribute `yaml:"set,omitempty"` + String *StringAttribute `yaml:"string,omitempty"` + Float64 *Float64Attribute `yaml:"float64,omitempty"` + List *ListAttribute `yaml:"list,omitempty"` + Bool *BoolAttribute `yaml:"bool,omitempty"` + ListNested *ListNestedAttribute `yaml:"list_nested,omitempty"` + Map *MapAttribute `yaml:"map,omitempty"` + MapNested *MapNestedAttribute `yaml:"map_nested,omitempty"` + Number *NumberAttribute `yaml:"number,omitempty"` + Int64 *Int64Attribute `yaml:"int64,omitempty"` + Timeouts *TimeoutsAttribute `yaml:"timeouts,omitempty"` + SingleNested *SingleNestedAttribute `yaml:"single_nested,omitempty"` + SetNested *SetNestedAttribute `yaml:"set_nested,omitempty"` + Description *string `yaml:"description,omitempty"` + DeprecationMessage *string `yaml:"deprecation_message,omitempty"` + CustomType *CustomType `yaml:"custom_type,omitempty"` + ComputedOptionalRequired ComputedOptionalRequired `yaml:"computed_optional_required"` + TFSchemaName string `yaml:"tf_schema_name"` + TFModelName string `yaml:"tf_model_name"` + ReqBodyUsage AttributeReqBodyUsage `yaml:"req_body_usage"` + Sensitive bool `yaml:"sensitive"` + CreateOnly bool `yaml:"create_only"` // leveraged for defining plan modifier which avoids updates on this attribute } type ComputedOptionalRequired string diff --git a/tools/codegen/codespec/testdata/config-nested-schema-overrides.yml b/tools/codegen/codespec/testdata/config-nested-schema-overrides.yml index 7ae9c538b8..acd810b28e 100644 --- a/tools/codegen/codespec/testdata/config-nested-schema-overrides.yml +++ b/tools/codegen/codespec/testdata/config-nested-schema-overrides.yml @@ -15,6 +15,7 @@ resources: version_header: application/vnd.atlas.2035-01-01+json schema: aliases: + groupId: projectId group_id: project_id nested_list_array_attr.inner_num_attr: inner_num_attr_alias outer_object.nested_level1.level_field1: level_field1_alias diff --git a/tools/codegen/config.yml b/tools/codegen/config.yml index 12ecbb10b3..24cd37758f 100644 --- a/tools/codegen/config.yml +++ b/tools/codegen/config.yml @@ -61,9 +61,9 @@ resources: target_states: ["DELETED"] # DELETED is a special state value when API returns 404 or empty object version_header: application/vnd.atlas.2024-08-05+json schema: - ignores: ["links", "mongo_dbemployee_access_grant.links"] + ignores: ["links", "mongo_db_employee_access_grant.links"] aliases: - cluster_name: name # path param name does not match the API request property + clusterName: name # path param name does not match the API request property # These attributes are optional but when not configured, Atlas returns a default value. # If a nested attribute is optional/computed, all its optional child attributes must also be defined as optional/computed to avoid non-empty plans. overrides: @@ -211,7 +211,7 @@ resources: computability: optional: true computed: true - mongo_dbmajor_version: + mongo_db_major_version: computability: optional: true computed: true @@ -296,10 +296,6 @@ resources: method: PATCH version_header: application/vnd.atlas.2023-01-01+json schema: - aliases: - # "AI" is all uppercase and does not play nice with camelCase to snake_case conversion. - is_data_explorer_gen_aifeatures_enabled: is_data_explorer_gen_ai_features_enabled - is_data_explorer_gen_aisample_document_passing_enabled: is_data_explorer_gen_ai_sample_document_passing_enabled overrides: # These attributes are optional but when not configured, Atlas returns a default value. is_collect_database_specifics_statistics_enabled: @@ -348,7 +344,7 @@ resources: schema: ignores: ["links"] aliases: - group_id: id # path param name does not match the API response property + groupId: id # path param name does not match the API response property push_based_log_export_api: read: @@ -395,7 +391,7 @@ resources: version_header: application/vnd.atlas.2024-08-05+json schema: aliases: - resource_policy_id: id # path param name does not match the API response property + resourcePolicyId: id # path param name does not match the API response property search_deployment_api: read: @@ -453,7 +449,7 @@ resources: # TODO: investigate, latest_definition.mappings excluded because dynamic is a JSON string field but Atlas can also reply with true or false booleans. ignores: ["definition.mappings.fields", "latest_definition.mappings.fields", "latest_definition.mappings"] aliases: - indexId: IndexID # path param name does not match the API response property + indexId: indexID # path param name does not match the API response property # Update doesn't work because API defines incorrectly region and cloud_provider at root level in PATCH instead of inside data_process_region as in the other endpoints. # id should be Computed but is ignored because it's defined as _id which is not a legal name for a Terraform attribute as they can't start with an underscore. @@ -491,7 +487,7 @@ resources: "stream_config.links", ] aliases: - tenant_name: name # path param name does not match the API request property + tenantName: name # path param name does not match the API request property # id should be Computed but is ignored because it's defined as _id which is not a legal name for a Terraform attribute as they can't start with an underscore. # Custom methods :startWith and :stop are not called so state attribute is not supported as Optional like in the curated resource, only as Computed. @@ -524,7 +520,7 @@ resources: schema: ignores: ["links", "options.links", "options.dlq.links", "_id"] aliases: - processor_name: name # path param name does not match the API request property. + processorName: name # path param name does not match the API request property. overrides: options: # optional but when not configured, Atlas returns a default value. computability: diff --git a/tools/codegen/gofilegen/resource/resource_file.go b/tools/codegen/gofilegen/resource/resource_file.go index 288829232f..e8c1b7d939 100644 --- a/tools/codegen/gofilegen/resource/resource_file.go +++ b/tools/codegen/gofilegen/resource/resource_file.go @@ -11,8 +11,8 @@ import ( func GenerateGoCode(input *codespec.Resource) []byte { tmplInputs := codetemplate.ResourceFileInputs{ - PackageName: input.Name.LowerCaseNoUnderscore(), - ResourceName: input.Name.SnakeCase(), + PackageName: input.PackageName, + ResourceName: input.Name, APIOperations: codetemplate.APIOperations{ VersionHeader: input.Operations.VersionHeader, Create: *toCodeTemplateOpModel(&input.Operations.Create), @@ -80,7 +80,7 @@ func getIDAttributes(readPath string) []string { params := getPathParams(readPath) result := make([]string, len(params)) for i, param := range params { - result[i] = stringcase.FromCamelCase(param.CamelCaseName).SnakeCase() + result[i] = stringcase.ToSnakeCase(param.CamelCaseName) } return result } diff --git a/tools/codegen/gofilegen/resource/resource_file_test.go b/tools/codegen/gofilegen/resource/resource_file_test.go index 96a890ae06..698a372e0f 100644 --- a/tools/codegen/gofilegen/resource/resource_file_test.go +++ b/tools/codegen/gofilegen/resource/resource_file_test.go @@ -3,7 +3,6 @@ package resource_test import ( "testing" - "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/autogen/stringcase" "github.com/mongodb/terraform-provider-mongodbatlas/tools/codegen/codespec" "github.com/mongodb/terraform-provider-mongodbatlas/tools/codegen/gofilegen/resource" "github.com/sebdah/goldie/v2" @@ -18,7 +17,8 @@ func TestResourceGenerationFromCodeSpec(t *testing.T) { testCases := map[string]resourceGenerationTestCase{ "Defining different operation URLs with different path params": { inputModel: codespec.Resource{ - Name: stringcase.SnakeCaseString("test_name"), + Name: "test_name", + PackageName: "testname", Operations: codespec.APIOperations{ Create: codespec.APIOperation{ HTTPMethod: "POST", @@ -43,7 +43,8 @@ func TestResourceGenerationFromCodeSpec(t *testing.T) { }, "Update operation using PUT": { inputModel: codespec.Resource{ - Name: stringcase.SnakeCaseString("test_name"), + Name: "test_name", + PackageName: "testname", Operations: codespec.APIOperations{ Create: codespec.APIOperation{ HTTPMethod: "POST", @@ -68,7 +69,8 @@ func TestResourceGenerationFromCodeSpec(t *testing.T) { }, "Defining wait configuration in create update and delete": { inputModel: codespec.Resource{ - Name: stringcase.SnakeCaseString("test_name"), + Name: "test_name", + PackageName: "testname", Operations: codespec.APIOperations{ Create: codespec.APIOperation{ HTTPMethod: "POST", @@ -117,7 +119,8 @@ func TestResourceGenerationFromCodeSpec(t *testing.T) { }, "Defining static request body in delete operation": { inputModel: codespec.Resource{ - Name: stringcase.SnakeCaseString("test_name"), + Name: "test_name", + PackageName: "testname", Operations: codespec.APIOperations{ Create: codespec.APIOperation{ HTTPMethod: "POST", @@ -143,7 +146,8 @@ func TestResourceGenerationFromCodeSpec(t *testing.T) { }, "Defining a resource with no DELETE operation": { inputModel: codespec.Resource{ - Name: stringcase.SnakeCaseString("test_name"), + Name: "test_name", + PackageName: "testname", Operations: codespec.APIOperations{ Create: codespec.APIOperation{ HTTPMethod: "POST", diff --git a/tools/codegen/gofilegen/schema/schema_file.go b/tools/codegen/gofilegen/schema/schema_file.go index fb60d4847f..0df8977313 100644 --- a/tools/codegen/gofilegen/schema/schema_file.go +++ b/tools/codegen/gofilegen/schema/schema_file.go @@ -16,7 +16,7 @@ func GenerateGoCode(input *codespec.Resource) []byte { imports = append(imports, models.Imports...) tmplInputs := codetemplate.SchemaFileInputs{ - PackageName: input.Name.LowerCaseNoUnderscore(), + PackageName: input.PackageName, Imports: imports, SchemaAttributes: schemaAttrs.Code, Models: models.Code, diff --git a/tools/codegen/gofilegen/schema/schema_file_test.go b/tools/codegen/gofilegen/schema/schema_file_test.go index f394c7fa84..58096bb4e9 100644 --- a/tools/codegen/gofilegen/schema/schema_file_test.go +++ b/tools/codegen/gofilegen/schema/schema_file_test.go @@ -52,7 +52,8 @@ func TestSchemaGenerationFromCodeSpec(t *testing.T) { schemaGenFromCodeSpecTestCases := map[string]schemaGenerationTestCase{ "Primitive attributes": { inputModel: codespec.Resource{ - Name: "test_name", + Name: "test_name", + PackageName: "testname", Schema: &codespec.Schema{ Attributes: []codespec.Attribute{ { @@ -121,7 +122,8 @@ func TestSchemaGenerationFromCodeSpec(t *testing.T) { }, "Custom type attributes": { inputModel: codespec.Resource{ - Name: "test_name", + Name: "test_name", + PackageName: "testname", Schema: &codespec.Schema{ Attributes: []codespec.Attribute{ { @@ -218,7 +220,8 @@ func TestSchemaGenerationFromCodeSpec(t *testing.T) { }, "Timeout attribute": { inputModel: codespec.Resource{ - Name: "test_name", + Name: "test_name", + PackageName: "testname", Schema: &codespec.Schema{ Attributes: []codespec.Attribute{ { @@ -243,7 +246,8 @@ func TestSchemaGenerationFromCodeSpec(t *testing.T) { }, "Multiple nested models with same parent attribute name": { inputModel: codespec.Resource{ - Name: "test_name", + Name: "test_name", + PackageName: "testname", Schema: &codespec.Schema{ Attributes: []codespec.Attribute{ { @@ -277,7 +281,8 @@ func TestSchemaGenerationFromCodeSpec(t *testing.T) { }, "Plan modifiers using create only": { inputModel: codespec.Resource{ - Name: "test_name", + Name: "test_name", + PackageName: "testname", Schema: &codespec.Schema{ Attributes: []codespec.Attribute{ { diff --git a/tools/codegen/gofilegen/schema/typed_model.go b/tools/codegen/gofilegen/schema/typed_model.go index 47550c8651..30e435086b 100644 --- a/tools/codegen/gofilegen/schema/typed_model.go +++ b/tools/codegen/gofilegen/schema/typed_model.go @@ -74,7 +74,7 @@ func typedModelProperty(attr *codespec.Attribute) string { case codespec.IncludeNullOnUpdate: autogenTag = ` autogen:"includenullonupdate"` } - return fmt.Sprintf("%s %s", attr.TFModelName, propType) + " `" + fmt.Sprintf("tfsdk:%q", attr.TFSchemaName.SnakeCase()) + autogenTag + "`" + return fmt.Sprintf("%s %s", attr.TFModelName, propType) + " `" + fmt.Sprintf("tfsdk:%q", attr.TFSchemaName) + autogenTag + "`" } func attrModelType(attr *codespec.Attribute) string { diff --git a/tools/codegen/main.go b/tools/codegen/main.go index 9f1261d80a..7d500f88f0 100644 --- a/tools/codegen/main.go +++ b/tools/codegen/main.go @@ -78,14 +78,14 @@ func main() { log.Printf("[INFO] Generating resource code: %s", resourceModel.Name) schemaCode := schema.GenerateGoCode(resourceModel) - schemaFilePath := fmt.Sprintf("internal/serviceapi/%s/resource_schema.go", resourceModel.Name.LowerCaseNoUnderscore()) + schemaFilePath := fmt.Sprintf("internal/serviceapi/%s/resource_schema.go", resourceModel.PackageName) if err := writeToFile(schemaFilePath, schemaCode); err != nil { log.Fatalf("[ERROR] An error occurred when writing content to file: %v", err) } formatGoFile(schemaFilePath) resourceCode := resource.GenerateGoCode(resourceModel) - resourceFilePath := fmt.Sprintf("internal/serviceapi/%s/resource.go", resourceModel.Name.LowerCaseNoUnderscore()) + resourceFilePath := fmt.Sprintf("internal/serviceapi/%s/resource.go", resourceModel.PackageName) if err := writeToFile(resourceFilePath, resourceCode); err != nil { log.Fatalf("[ERROR] An error occurred when writing content to file: %v", err) } diff --git a/tools/codegen/models/auditing_api.yaml b/tools/codegen/models/auditing_api.yaml index 99e9dbb9d2..693fa9a5c9 100755 --- a/tools/codegen/models/auditing_api.yaml +++ b/tools/codegen/models/auditing_api.yaml @@ -62,3 +62,4 @@ operations: path: /api/atlas/v2/groups/{groupId}/auditLog version_header: application/vnd.atlas.2023-01-01+json name: auditing_api +packageName: auditingapi diff --git a/tools/codegen/models/cluster_api.yaml b/tools/codegen/models/cluster_api.yaml index 735e5e3915..0809077381 100755 --- a/tools/codegen/models/cluster_api.yaml +++ b/tools/codegen/models/cluster_api.yaml @@ -422,15 +422,15 @@ schema: model: customtypes.ObjectValue[TFMongoDBEmployeeAccessGrantModel] schema: customtypes.NewObjectType[TFMongoDBEmployeeAccessGrantModel](ctx) computed_optional_required: optional - tf_schema_name: mongo_dbemployee_access_grant + tf_schema_name: mongo_db_employee_access_grant tf_model_name: MongoDBEmployeeAccessGrant req_body_usage: all_request_bodies sensitive: false create_only: false - string: {} description: "MongoDB major version of the cluster. Set to the binary major version. \n\nOn creation: Choose from the available versions of MongoDB, or leave unspecified for the current recommended default in the MongoDB Cloud platform. The recommended version is a recent Long Term Support version. The default is not guaranteed to be the most recently released version throughout the entire release cycle. For versions available in a specific project, see the linked documentation or use the API endpoint for [project LTS versions endpoint](#tag/Projects/operation/getProjectLtsVersions).\n\n On update: Increase version only by 1 major version at a time. If the cluster is pinned to a MongoDB feature compatibility version exactly one major version below the current MongoDB version, the MongoDB version can be downgraded to the previous major version." - computed_optional_required: computed_optional - tf_schema_name: mongo_dbmajor_version + computed_optional_required: optional + tf_schema_name: mongo_db_major_version tf_model_name: MongoDBMajorVersion req_body_usage: all_request_bodies sensitive: false @@ -438,7 +438,7 @@ schema: - string: {} description: Version of MongoDB that the cluster runs. computed_optional_required: computed - tf_schema_name: mongo_dbversion + tf_schema_name: mongo_db_version tf_model_name: MongoDBVersion req_body_usage: omit_always sensitive: false @@ -1331,3 +1331,4 @@ operations: path: /api/atlas/v2/groups/{groupId}/clusters/{name} version_header: application/vnd.atlas.2024-08-05+json name: cluster_api +packageName: clusterapi diff --git a/tools/codegen/models/custom_db_role_api.yaml b/tools/codegen/models/custom_db_role_api.yaml index 514998b2e1..fce2f47964 100755 --- a/tools/codegen/models/custom_db_role_api.yaml +++ b/tools/codegen/models/custom_db_role_api.yaml @@ -125,3 +125,4 @@ operations: path: /api/atlas/v2/groups/{groupId}/customDBRoles/roles/{roleName} version_header: application/vnd.atlas.2023-01-01+json name: custom_db_role_api +packageName: customdbroleapi diff --git a/tools/codegen/models/database_user_api.yaml b/tools/codegen/models/database_user_api.yaml index eba1409860..34637b7d21 100755 --- a/tools/codegen/models/database_user_api.yaml +++ b/tools/codegen/models/database_user_api.yaml @@ -5,7 +5,7 @@ schema: default: NONE description: Human-readable label that indicates whether the new database user authenticates with the Amazon Web Services (AWS) Identity and Access Management (IAM) credentials associated with the user or the user's role. computed_optional_required: computed_optional - tf_schema_name: aws_iamtype + tf_schema_name: aws_iam_type tf_model_name: AwsIAMType req_body_usage: all_request_bodies sensitive: false @@ -201,7 +201,7 @@ schema: Users created with the `CUSTOMER` method require a Common Name (CN) in the **username** parameter. You must create externally authenticated users on the `$external` database. computed_optional_required: computed_optional - tf_schema_name: x509type + tf_schema_name: x509_type tf_model_name: X509Type req_body_usage: all_request_bodies sensitive: false @@ -221,3 +221,4 @@ operations: path: /api/atlas/v2/groups/{groupId}/databaseUsers/{databaseName}/{username} version_header: application/vnd.atlas.2023-01-01+json name: database_user_api +packageName: databaseuserapi diff --git a/tools/codegen/models/maintenance_window_api.yaml b/tools/codegen/models/maintenance_window_api.yaml index d6399463af..333ba9e7b1 100755 --- a/tools/codegen/models/maintenance_window_api.yaml +++ b/tools/codegen/models/maintenance_window_api.yaml @@ -114,3 +114,4 @@ operations: path: /api/atlas/v2/groups/{groupId}/maintenanceWindow version_header: application/vnd.atlas.2023-01-01+json name: maintenance_window_api +packageName: maintenancewindowapi diff --git a/tools/codegen/models/org_service_account_api.yaml b/tools/codegen/models/org_service_account_api.yaml index 31576740a2..7b119999a2 100755 --- a/tools/codegen/models/org_service_account_api.yaml +++ b/tools/codegen/models/org_service_account_api.yaml @@ -139,3 +139,4 @@ operations: path: /api/atlas/v2/orgs/{orgId}/serviceAccounts/{clientId} version_header: application/vnd.atlas.2024-08-05+json name: org_service_account_api +packageName: orgserviceaccountapi diff --git a/tools/codegen/models/project_api.yaml b/tools/codegen/models/project_api.yaml index 018a0c056c..b8d794f8ae 100755 --- a/tools/codegen/models/project_api.yaml +++ b/tools/codegen/models/project_api.yaml @@ -113,3 +113,4 @@ operations: path: /api/atlas/v2/groups/{id} version_header: application/vnd.atlas.2023-01-01+json name: project_api +packageName: projectapi diff --git a/tools/codegen/models/project_settings_api.yaml b/tools/codegen/models/project_settings_api.yaml index 9b2157d205..c12d6ee41a 100755 --- a/tools/codegen/models/project_settings_api.yaml +++ b/tools/codegen/models/project_settings_api.yaml @@ -89,3 +89,4 @@ operations: path: /api/atlas/v2/groups/{groupId}/settings version_header: application/vnd.atlas.2023-01-01+json name: project_settings_api +packageName: projectsettingsapi diff --git a/tools/codegen/models/push_based_log_export_api.yaml b/tools/codegen/models/push_based_log_export_api.yaml index fa670a59df..c94e6e60ba 100755 --- a/tools/codegen/models/push_based_log_export_api.yaml +++ b/tools/codegen/models/push_based_log_export_api.yaml @@ -119,3 +119,4 @@ operations: path: /api/atlas/v2/groups/{groupId}/pushBasedLogExport version_header: application/vnd.atlas.2023-01-01+json name: push_based_log_export_api +packageName: pushbasedlogexportapi diff --git a/tools/codegen/models/resource_policy_api.yaml b/tools/codegen/models/resource_policy_api.yaml index 341b34945f..287253a67c 100755 --- a/tools/codegen/models/resource_policy_api.yaml +++ b/tools/codegen/models/resource_policy_api.yaml @@ -162,3 +162,4 @@ operations: path: /api/atlas/v2/orgs/{orgId}/resourcePolicies/{id} version_header: application/vnd.atlas.2024-08-05+json name: resource_policy_api +packageName: resourcepolicyapi diff --git a/tools/codegen/models/search_deployment_api.yaml b/tools/codegen/models/search_deployment_api.yaml index f1ad591c65..3bcd9213d7 100755 --- a/tools/codegen/models/search_deployment_api.yaml +++ b/tools/codegen/models/search_deployment_api.yaml @@ -143,3 +143,4 @@ operations: path: /api/atlas/v2/groups/{groupId}/clusters/{clusterName}/search/deployment version_header: application/vnd.atlas.2025-03-12+json name: search_deployment_api +packageName: searchdeploymentapi diff --git a/tools/codegen/models/search_index_api.yaml b/tools/codegen/models/search_index_api.yaml index 83e0fefbec..e40f344a02 100755 --- a/tools/codegen/models/search_index_api.yaml +++ b/tools/codegen/models/search_index_api.yaml @@ -954,3 +954,4 @@ operations: path: /api/atlas/v2/groups/{groupId}/clusters/{clusterName}/search/indexes/{indexID} version_header: application/vnd.atlas.2024-05-30+json name: search_index_api +packageName: searchindexapi diff --git a/tools/codegen/models/stream_instance_api.yaml b/tools/codegen/models/stream_instance_api.yaml index aa413b4d2d..c3b05b278c 100755 --- a/tools/codegen/models/stream_instance_api.yaml +++ b/tools/codegen/models/stream_instance_api.yaml @@ -479,3 +479,4 @@ operations: path: /api/atlas/v2/groups/{groupId}/streams/{name} version_header: application/vnd.atlas.2023-02-01+json name: stream_instance_api +packageName: streaminstanceapi diff --git a/tools/codegen/models/stream_processor_api.yaml b/tools/codegen/models/stream_processor_api.yaml index d2a76614ee..491eaee8fc 100755 --- a/tools/codegen/models/stream_processor_api.yaml +++ b/tools/codegen/models/stream_processor_api.yaml @@ -189,3 +189,4 @@ operations: path: /api/atlas/v2/groups/{groupId}/streams/{tenantName}/processor/{name} version_header: application/vnd.atlas.2024-05-30+json name: stream_processor_api +packageName: streamprocessorapi From 8f51fd91dfd5c15e35e5e3ccf949606473b0b99e Mon Sep 17 00:00:00 2001 From: Manuel Pedrozo Date: Tue, 4 Nov 2025 12:16:31 +0100 Subject: [PATCH 2/2] Regenerate resources after version bump --- internal/serviceapi/clusterapi/resource_schema.go | 1 + tools/codegen/models/cluster_api.yaml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/serviceapi/clusterapi/resource_schema.go b/internal/serviceapi/clusterapi/resource_schema.go index f306e901f2..bc1208f647 100755 --- a/internal/serviceapi/clusterapi/resource_schema.go +++ b/internal/serviceapi/clusterapi/resource_schema.go @@ -235,6 +235,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, "mongo_db_major_version": schema.StringAttribute{ + Computed: true, Optional: true, MarkdownDescription: "MongoDB major version of the cluster. Set to the binary major version. \n\nOn creation: Choose from the available versions of MongoDB, or leave unspecified for the current recommended default in the MongoDB Cloud platform. The recommended version is a recent Long Term Support version. The default is not guaranteed to be the most recently released version throughout the entire release cycle. For versions available in a specific project, see the linked documentation or use the API endpoint for [project LTS versions endpoint](#tag/Projects/operation/getProjectLtsVersions).\n\n On update: Increase version only by 1 major version at a time. If the cluster is pinned to a MongoDB feature compatibility version exactly one major version below the current MongoDB version, the MongoDB version can be downgraded to the previous major version.", }, diff --git a/tools/codegen/models/cluster_api.yaml b/tools/codegen/models/cluster_api.yaml index 0809077381..f12994ec22 100755 --- a/tools/codegen/models/cluster_api.yaml +++ b/tools/codegen/models/cluster_api.yaml @@ -429,7 +429,7 @@ schema: create_only: false - string: {} description: "MongoDB major version of the cluster. Set to the binary major version. \n\nOn creation: Choose from the available versions of MongoDB, or leave unspecified for the current recommended default in the MongoDB Cloud platform. The recommended version is a recent Long Term Support version. The default is not guaranteed to be the most recently released version throughout the entire release cycle. For versions available in a specific project, see the linked documentation or use the API endpoint for [project LTS versions endpoint](#tag/Projects/operation/getProjectLtsVersions).\n\n On update: Increase version only by 1 major version at a time. If the cluster is pinned to a MongoDB feature compatibility version exactly one major version below the current MongoDB version, the MongoDB version can be downgraded to the previous major version." - computed_optional_required: optional + computed_optional_required: computed_optional tf_schema_name: mongo_db_major_version tf_model_name: MongoDBMajorVersion req_body_usage: all_request_bodies