From 56b7ed37dc76dbf8319e59de588896d5de74405a Mon Sep 17 00:00:00 2001 From: Praneet Loke <1466314+praneetloke@users.noreply.github.com> Date: Sun, 26 May 2024 17:45:12 -0700 Subject: [PATCH] Allow providers to pass a list of allowed plural resource names (#161) --- pkg/naming.go | 19 +++++++++++++++++++ pkg/openapi.go | 23 +++++++++++++---------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/pkg/naming.go b/pkg/naming.go index dd27317..7fea334 100644 --- a/pkg/naming.go +++ b/pkg/naming.go @@ -9,6 +9,7 @@ import ( ) var numbersRegexp = regexp.MustCompile("[0-9]+[_]*[a-zA-Z]+") +var defaultAllowedPluralResourceNames = []string{"Kubernetes"} // ToSdkName converts a property or attribute name to the lowerCamelCase convention that // is used in Pulumi schema's properties. @@ -80,3 +81,21 @@ func addNameOverride(key, value string, m map[string]string) { m[key] = value } + +// getSingularNameForResource returns a singular version of a resource name, +// as long as the name doesn't have one of the valid plural names as its +// suffix. +func getSingularNameForResource(resourceName string, allowedPluralNames []string) string { + allowPluralName := false + for _, n := range allowedPluralNames { + if strings.HasSuffix(resourceName, n) { + allowPluralName = true + } + } + + if !allowPluralName { + return strings.TrimSuffix(resourceName, "s") + } + + return resourceName +} diff --git a/pkg/openapi.go b/pkg/openapi.go index 879d2ad..28a3976 100644 --- a/pkg/openapi.go +++ b/pkg/openapi.go @@ -64,6 +64,10 @@ type OpenAPIContext struct { // TypeSpecNamespaceSeparator is the separator used in the operationId value. TypeSpecNamespaceSeparator string + // AllowedPluralResources is a slice of resource names that should not + // be converted to their singular version. + AllowedPluralResources []string + // resourceCRUDMap is a map of the Pulumi resource type // token to its CRUD endpoints. resourceCRUDMap map[string]*CRUDOperationsMap @@ -84,7 +88,8 @@ type OpenAPIContext struct { // to the SDK name used in the Pulumi schema. This can // be used by providers to look-up the value for a path // param in the inputs map. - pathParamNameMap map[string]string + pathParamNameMap map[string]string + allowedPluralResources []string } type duplicateEnumError struct { @@ -115,6 +120,8 @@ func (o *OpenAPIContext) GatherResourcesFromAPI(csharpNamespaces map[string]stri o.apiToSDKNameMap = make(map[string]string) o.pathParamNameMap = make(map[string]string) + o.allowedPluralResources = append(o.AllowedPluralResources, defaultAllowedPluralResourceNames...) + for _, path := range o.Doc.Paths.InMatchingOrder() { pathItem := o.Doc.Paths.Find(path) if pathItem == nil { @@ -268,6 +275,7 @@ func (o *OpenAPIContext) GatherResourcesFromAPI(csharpNamespaces map[string]stri } } else { resourceName := getResourceTitleFromOperationID(pathItem.Patch.OperationID, http.MethodPatch, o.OperationIdsHaveTypeSpecNamespace) + resourceName = getSingularNameForResource(resourceName, o.allowedPluralResources) typeToken := fmt.Sprintf("%s:%s:%s", o.Pkg.Name, module, resourceName) setUpdateOperationMapping(typeToken) } @@ -315,6 +323,7 @@ func (o *OpenAPIContext) GatherResourcesFromAPI(csharpNamespaces map[string]stri // to create resources if the endpoint itself requires the ID of the resource. if pathItem.Post == nil && !strings.HasSuffix(currentPath, "}") { resourceName := getResourceTitleFromOperationID(pathItem.Put.OperationID, http.MethodPut, o.OperationIdsHaveTypeSpecNamespace) + resourceName = getSingularNameForResource(resourceName, o.allowedPluralResources) parameters := pathItem.Parameters parameters = append(parameters, pathItem.Put.Parameters...) if err := o.gatherResource(currentPath, resourceName, *resourceType, nil /*response type*/, parameters, module); err != nil { @@ -357,17 +366,13 @@ func (o *OpenAPIContext) GatherResourcesFromAPI(csharpNamespaces map[string]stri } } else { resourceName := getResourceTitleFromOperationID(pathItem.Delete.OperationID, http.MethodDelete, o.OperationIdsHaveTypeSpecNamespace) - if !strings.HasSuffix(resourceName, "Kubernetes") { - resourceName = strings.TrimSuffix(resourceName, "s") - } + resourceName = getSingularNameForResource(resourceName, o.allowedPluralResources) typeToken := fmt.Sprintf("%s:%s:%s", o.Pkg.Name, module, resourceName) setDeleteOperationMapping(typeToken) } } else { resourceName := getResourceTitleFromOperationID(pathItem.Delete.OperationID, http.MethodDelete, o.OperationIdsHaveTypeSpecNamespace) - if !strings.HasSuffix(resourceName, "Kubernetes") { - resourceName = strings.TrimSuffix(resourceName, "s") - } + resourceName = getSingularNameForResource(resourceName, o.allowedPluralResources) typeToken := fmt.Sprintf("%s:%s:%s", o.Pkg.Name, module, resourceName) setDeleteOperationMapping(typeToken) } @@ -425,9 +430,7 @@ func (o *OpenAPIContext) GatherResourcesFromAPI(csharpNamespaces map[string]stri } resourceName := getResourceTitleFromOperationID(pathItem.Post.OperationID, http.MethodPost, o.OperationIdsHaveTypeSpecNamespace) - if !strings.HasSuffix(resourceName, "Kubernetes") { - resourceName = strings.TrimSuffix(resourceName, "s") - } + resourceName = getSingularNameForResource(resourceName, o.allowedPluralResources) resourceRequestType := jsonReq.Schema.Value parameters := pathItem.Parameters