Skip to content

Commit

Permalink
fix: create nested types for map of array of objects
Browse files Browse the repository at this point in the history
We were previously not nesting maps of arrays, and treating them as
generic types instead. This is an issue in Golang codegen, generating
generic Pulumi input/output types that don't exists. This commit ensures
we also flatten map of arrays so Golang codegen works.

Fixes: #147
  • Loading branch information
rquitales committed Sep 16, 2024
1 parent f670a71 commit 21d7655
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 21 deletions.
73 changes: 52 additions & 21 deletions pkg/codegen/customresourcegenerator.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func flattenOpenAPI(sw *spec.Swagger) error {

func flattenRecursively(sw *spec.Swagger, parentName string, currSpec spec.Schema) (spec.Schema, error) {
// If at bottom of the stack, return the spec.
if currSpec.Properties == nil && currSpec.Items == nil {
if currSpec.Properties == nil && currSpec.Items == nil && currSpec.AdditionalProperties == nil {
return currSpec, nil
}

Expand All @@ -86,43 +86,50 @@ func flattenRecursively(sw *spec.Swagger, parentName string, currSpec spec.Schem
return currSpec, nil
}

// If the property is an object with additional properties, we can skip it. We only care about
// If the property is an object with additional properties, we can skip it if it is not an array of inline objects. We only care about
// nested objects that are explicitly defined.
if currSpec.AdditionalProperties != nil {
// Not an array of inline objects, so we can skip processing.
if currSpec.AdditionalProperties.Schema.Items == nil {
return currSpec, nil
}

// Property is an array of inline objects.
s, ref, err := flattedArrayObject(parentName, sw, currSpec.AdditionalProperties.Schema.Items.Schema)
if err != nil {
return currSpec, fmt.Errorf("error flattening OpenAPI object of array property: %w", err)
}

currSpec.AdditionalProperties.Schema.Items.Schema = &s

if ref != nil {
currSpec.AdditionalProperties.Schema.Items.Schema.Ref = spec.Ref{Ref: *ref}
currSpec.AdditionalProperties.Schema.Items.Schema.Type = nil
currSpec.AdditionalProperties.Schema.Items.Schema.Properties = nil
}

return currSpec, nil
}

// If the property is an array, we need to remove any inline objects and replace them with references.
if currSpec.Items != nil {
if currSpec.Items.Schema == nil {
return currSpec, fmt.Errorf("error flattening OpenAPI spec: items schema is nil")
}

nestedDefinitionName := parentName

s, err := flattenRecursively(sw, nestedDefinitionName, *(currSpec.Items.Schema))
s, ref, err := flattedArrayObject(parentName, sw, currSpec.Items.Schema)
if err != nil {
return currSpec, fmt.Errorf("error flattening OpenAPI spec: %w", err)
return currSpec, fmt.Errorf("error flattening OpenAPI array property: %w", err)
}

currSpec.Items.Schema = &s

if len(currSpec.Items.Schema.Properties) == 0 {
return currSpec, nil
if ref != nil {
currSpec.Items.Schema.Ref = spec.Ref{Ref: *ref}
currSpec.Items.Schema.Type = nil
currSpec.Items.Schema.Properties = nil
}

sw.Definitions[nestedDefinitionName] = s

// Reset the property to be a reference to the nested object if the item is an object.
refName := definitionPrefix + nestedDefinitionName
ref, err := jsonreference.New(refName)
if err != nil {
return currSpec, fmt.Errorf("error creating OpenAPI json reference for nested object: %w", err)
}

currSpec.Items.Schema.Ref = spec.Ref{Ref: ref}
currSpec.Items.Schema.Type = nil
currSpec.Items.Schema.Properties = nil

return currSpec, nil
}

Expand Down Expand Up @@ -169,6 +176,30 @@ func flattenRecursively(sw *spec.Swagger, parentName string, currSpec spec.Schem
return currSpec, nil
}

// flattedArrayObject flattens an OpenAPI array property.
func flattedArrayObject(parentName string, sw *spec.Swagger, itemsSchema *spec.Schema) (spec.Schema, *jsonreference.Ref, error) {
nestedDefinitionName := parentName

s, err := flattenRecursively(sw, nestedDefinitionName, *itemsSchema)
if err != nil {
return s, nil, fmt.Errorf("error flattening OpenAPI spec: %w", err)
}

if len(s.Properties) == 0 {
return s, nil, nil
}

sw.Definitions[nestedDefinitionName] = s

refName := definitionPrefix + nestedDefinitionName
ref, err := jsonreference.New(refName)
if err != nil {
return s, nil, fmt.Errorf("error creating OpenAPI json reference for nested object: %w", err)
}

return s, &ref, nil
}

func sanitizeReferenceName(fieldName string) string {
// If the field name is "arg" or "args", we need to change it to "Arguments" to avoid conflicts with Go reserved words.
if s := strings.ToLower(fieldName); s == "arg" || s == "args" {
Expand Down
5 changes: 5 additions & 0 deletions tests/crds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@ func TestCRDsFromUrl(t *testing.T) {
name: "Argo Application Set",
url: "https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/crds/applicationset-crd.yaml",
},
{
// https://github.com/pulumi/crd2pulumi/issues/147
name: "Prometheus Operator",
url: "https://github.com/prometheus-operator/prometheus-operator/releases/download/v0.76.2/bundle.yaml",
},
}

for _, tt := range tests {
Expand Down

0 comments on commit 21d7655

Please sign in to comment.