Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

encoding/openapi: Duplicate enumeration values generated #3596

Open
inksnw opened this issue Nov 27, 2024 · 2 comments
Open

encoding/openapi: Duplicate enumeration values generated #3596

inksnw opened this issue Nov 27, 2024 · 2 comments

Comments

@inksnw
Copy link

inksnw commented Nov 27, 2024

What version of CUE are you using (cue version)?

$ cue version
v0.11.0

Does this issue reproduce with the latest stable release?

yes

What did you do?

package main

import (
	"cuelang.org/go/cue/cuecontext"
	"cuelang.org/go/encoding/openapi"
	"fmt"
)

func main() {
	def := `	
	#parameter: {
		volumes?: [...{
			type: *"emptyDir" | "pvc" 
			if type == "emptyDir" {
				medium: *"" | "Memory"
			}
		}]
	}
`
	ctx := cuecontext.New()
	value := ctx.CompileString(def)
	b, err := openapi.Gen(value, &openapi.Config{ExpandReferences: true})
	if err != nil {
		panic(err)
	}
	fmt.Println(string(b))
}

If I set ExpandReferences to false, it works, but it will generate links like "$ref": "#/components/schemas/xxx"

What did you expect to see?

{
    "medium": {
        "type": "string",
        "enum": [
            "",
            "Memory",
        ],
        "default": ""
    }
}

What did you see instead?

{
    "medium": {
        "type": "string",
        "enum": [
            "",
            "Memory",
            "Memory"
        ],
        "default": ""
    }
}
@inksnw inksnw added NeedsInvestigation Triage Requires triage/attention labels Nov 27, 2024
@inksnw inksnw changed the title Duplicate enumeration values generated Duplicate openapi enumeration values generated Nov 27, 2024
@rogpeppe
Copy link
Member

Here's a testscript reproducer of a slightly more minimal example:

exec go mod tidy
exec go run .
cmp stdout want-stdout

-- go.mod --
module test

require cuelang.org/go v0.11.0

-- main.go --
package main

import (
	"encoding/json"
	"bytes"
	"fmt"

	"cuelang.org/go/cue/cuecontext"
	"cuelang.org/go/encoding/openapi"
)

func main() {
	def := `
	#parameter: {
		if true {
			a: *"" | "x" | "y"
		}
	}
`
	ctx := cuecontext.New()
	value := ctx.CompileString(def)
	b, err := openapi.Gen(value, &openapi.Config{ExpandReferences: true})
	if err != nil {
		panic(err)
	}
	var buf bytes.Buffer
	json.Indent(&buf, b, "", "    ")
	fmt.Println(string(buf.Bytes()))
}
-- want-stdout --
{
    "openapi": "3.0.0",
    "info": {
        "title": "Generated by cue.",
        "version": "no version"
    },
    "paths": {},
    "components": {
        "schemas": {
            "parameter": {
                "type": "object",
                "required": [
                    "a"
                ],
                "properties": {
                    "a": {
                        "type": "string",
                        "enum": [
                            "",
                            "x",
                            "y",
                        ],
                        "default": ""
                    }
                }
            }
        }
    }
}

This fails with:

> exec go mod tidy
> exec go run .
[stdout]
{
    "openapi": "3.0.0",
    "info": {
        "title": "Generated by cue.",
        "version": "no version"
    },
    "paths": {},
    "components": {
        "schemas": {
            "parameter": {
                "type": "object",
                "required": [
                    "a"
                ],
                "properties": {
                    "a": {
                        "type": "string",
                        "enum": [
                            "",
                            "x",
                            "y",
                            "x",
                            "y"
                        ],
                        "default": ""
                    }
                }
            }
        }
    }
}
> cmp stdout want-stdout
diff stdout want-stdout
--- stdout
+++ want-stdout
@@ -19,8 +19,6 @@
                             "",
                             "x",
                             "y",
-                            "x",
-                            "y"
                         ],
                         "default": ""
                     }

FAIL: /tmp/z.txtar:3: stdout and want-stdout differ

It's clear that the if comprehension is causing the issue here.

@inksnw As a workaround until this gets fixed, would it be possible for you to
change the schema so it doesn't use comprehensions to define the enum?

For example:

#parameter: {
	volumes?: [...{
		type: *"emptyDir" | "pvc"
		medium?: *"" | "Memory"
		if type == "emptyDir" {
			medium: _
		}
	}]
}

FWIW it's generally considered to be better for schemas to be "pure" (i.e. avoid defining any regular fields or defaults),
so you might define the #parameter schema as just:

#parameter: {
	volumes?: [...{
		type!: "emptyDir" | "pvc"
		medium?: "" | "Memory"
	}]
}

and the defaults in a separate field, e.g.

parameter: #parameter & {
	volumes?: [...{
		type: *"emptyDir" | "pvc"
		if type == "emptyDir" {
		    medium: *"" | "Memory"
		}
	}]
}

@myitcv myitcv removed the Triage Requires triage/attention label Nov 27, 2024
@myitcv myitcv changed the title Duplicate openapi enumeration values generated encoding/openapi: Duplicate enumeration values generated Nov 27, 2024
@inksnw
Copy link
Author

inksnw commented Nov 28, 2024

Thanks for your reply. I'll give the workaround a try.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants