Skip to content

Commit

Permalink
cmd/cue: support optional comments in get go
Browse files Browse the repository at this point in the history
The Kuberentes ecosystem use comments to denote whether a field is
optional or required. The comment has a direct effect on the produced
OpenAPI schema, and often means otherwise correct Go "schemas" will be
represented incorrectly with CUE.

https://github.com/kubernetes/community/blob/e977e6ea355f26130ca555d1e8704893727ee024/contributors/devel/sig-architecture/api-conventions.md#optional-vs-required

In addition to the heuristics of the "omitempty" struct tag, the
"// +optional" comment will now also mark a field as optional. The
behaviour from the Kubernetes project which parses this comment as a
key/value pair (tag) is also preserved.

https://pkg.go.dev/k8s.io/gengo/types#ExtractCommentTags

Fixes #2679

Change-Id: Ieeb2e7bee61e16ed9910ea46e68cb1a3eaa47197
Signed-off-by: Thomas Way <[email protected]>
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1171971
Reviewed-by: Daniel Martí <[email protected]>
TryBot-Result: CUEcueckoo <[email protected]>
Unity-Result: CUE porcuepine <[email protected]>
  • Loading branch information
uhthomas authored and mvdan committed Nov 10, 2023
1 parent 112b0b2 commit 67ea9cf
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 6 deletions.
23 changes: 17 additions & 6 deletions cmd/cue/cmd/get_go.go
Original file line number Diff line number Diff line change
Expand Up @@ -1292,15 +1292,15 @@ func (e *extractor) addFields(x *types.Struct, st *cueast.StructLit) {
if name == "-" {
continue
}

doc := docs[i]

// TODO: check referrers
kind := regular
if e.isOptional(tag) {
kind = optional
}
if _, ok := f.Type().(*types.Pointer); ok {
if e.isOptional(f, doc, tag) {
kind = optional
}
field, cueType := e.makeField(name, kind, f.Type(), docs[i], count > 0)
field, cueType := e.makeField(name, kind, f.Type(), doc, count > 0)
add(field)

if s := reflect.StructTag(tag).Get("cue"); s != "" {
Expand Down Expand Up @@ -1395,7 +1395,18 @@ func (e *extractor) isInline(tag string) bool {
hasFlag(tag, "yaml", "inline", 1)
}

func (e *extractor) isOptional(tag string) bool {
func (e *extractor) isOptional(f *types.Var, doc *ast.CommentGroup, tag string) bool {
if _, ok := f.Type().(*types.Pointer); ok {
return true
}

for _, line := range strings.Split(doc.Text(), "\n") {
before, _, _ := strings.Cut(strings.TrimSpace(line), "=")
if before == "+optional" {
return true
}
}

// TODO: also when the type is a list or other kind of pointer.
return hasFlag(tag, "json", "omitempty", 1) ||
hasFlag(tag, "yaml", "omitempty", 1)
Expand Down
56 changes: 56 additions & 0 deletions cmd/cue/cmd/testdata/script/get_go_types.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,35 @@ type Foozer struct {
Embed struct{ CustomJSON }

Unsupported map[int]string

OptionalOmitEmptyJSON string `json:"optionalOmitEmptyJSON,omitempty"`

OptionalOmitEmptyYAML string `yaml:"optionalOmitEmptyYAML,omitempty"`

// +optional
OptionalComment string `json:"optionalComment"`

//+optional
OptionalCommentNoSpace string `json:"optionalCommentNoSpace"`

// Something before
//
// +optional
//
// Something after
OptionalCommentExtra string `json:"optionalCommentExtra"`

// +optional=
OptionalCommentTag string `json:"optionalCommentTag"`

// +optional=some-value
OptionalCommentTagValue string `json:"optionalCommentTagValue"`

// some-prefix+optional
RequiredCommentPrefix string `json:"requiredCommentPrefix"`

// +optional-some-suffix
RequiredCommentSuffix string `json:"requiredCommentSuffix"`
}

type Identifier string
Expand Down Expand Up @@ -293,6 +322,33 @@ import (
Embed: {
CustomJSON: #CustomJSON
} @go(,struct{CustomJSON})
optionalOmitEmptyJSON?: string @go(OptionalOmitEmptyJSON)
optionalOmitEmptyYAML?: string @go(OptionalOmitEmptyYAML)

// +optional
optionalComment?: string @go(OptionalComment)

//+optional
optionalCommentNoSpace?: string @go(OptionalCommentNoSpace)

// Something before
//
// +optional
//
// Something after
optionalCommentExtra?: string @go(OptionalCommentExtra)

// +optional=
optionalCommentTag?: string @go(OptionalCommentTag)

// +optional=some-value
optionalCommentTagValue?: string @go(OptionalCommentTagValue)

// some-prefix+optional
requiredCommentPrefix: string @go(RequiredCommentPrefix)

// +optional-some-suffix
requiredCommentSuffix: string @go(RequiredCommentSuffix)
}

#Identifier: string // #enumIdentifier
Expand Down

0 comments on commit 67ea9cf

Please sign in to comment.