From 7ba2228d01ff58f2334d10c6da3f60cceacd20e3 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Tue, 7 Apr 2026 14:00:18 -0400 Subject: [PATCH] fix swagger generation inline json tag detection --- .../field_name_docs_check.go | 7 +++- cmd/genswaggertypedocs/swagger_type_docs.go | 7 +++- .../storage/v1/types_swagger_doc_generated.go | 1 + .../v1alpha1/types_swagger_doc_generated.go | 1 + .../v1beta1/types_swagger_doc_generated.go | 1 + .../pkg/runtime/swagger_doc_generator.go | 32 +++++++++++++------ 6 files changed, 37 insertions(+), 12 deletions(-) diff --git a/cmd/fieldnamedocscheck/field_name_docs_check.go b/cmd/fieldnamedocscheck/field_name_docs_check.go index 15e2961b1bc..4c5d16fa812 100644 --- a/cmd/fieldnamedocscheck/field_name_docs_check.go +++ b/cmd/fieldnamedocscheck/field_name_docs_check.go @@ -23,6 +23,7 @@ import ( "strings" flag "github.com/spf13/pflag" + kruntime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/klog/v2" @@ -43,7 +44,11 @@ func main() { klog.Fatalf("Please define -s flag as it is the api type file") } - docsForTypes := kruntime.ParseDocumentationFrom(*typeSrc) + docsForTypes, err := kruntime.ParseDocumentationFrom(*typeSrc) + if err != nil { + fmt.Println(err) + os.Exit(1) + } rc := false for _, ks := range docsForTypes { diff --git a/cmd/genswaggertypedocs/swagger_type_docs.go b/cmd/genswaggertypedocs/swagger_type_docs.go index 699173c8614..a97ac639615 100644 --- a/cmd/genswaggertypedocs/swagger_type_docs.go +++ b/cmd/genswaggertypedocs/swagger_type_docs.go @@ -24,6 +24,7 @@ import ( kruntime "k8s.io/apimachinery/pkg/runtime" flag "github.com/spf13/pflag" + "k8s.io/klog/v2" ) @@ -52,7 +53,11 @@ func main() { funcOut = file } - docsForTypes := kruntime.ParseDocumentationFrom(*typeSrc) + docsForTypes, err := kruntime.ParseDocumentationFrom(*typeSrc) + if err != nil { + fmt.Println(err) + os.Exit(1) + } if *verify { rc, err := kruntime.VerifySwaggerDocsExist(docsForTypes, funcOut) diff --git a/staging/src/k8s.io/api/storage/v1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/storage/v1/types_swagger_doc_generated.go index 47a7e92492e..d78ca48f2e8 100644 --- a/staging/src/k8s.io/api/storage/v1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/storage/v1/types_swagger_doc_generated.go @@ -190,6 +190,7 @@ func (VolumeAttachmentList) SwaggerDoc() map[string]string { var map_VolumeAttachmentSource = map[string]string{ "": "VolumeAttachmentSource represents a volume that should be attached. Right now only PersistentVolumes can be attached via external attacher, in the future we may allow also inline volumes in pods. Exactly one member can be set.", "persistentVolumeName": "persistentVolumeName represents the name of the persistent volume to attach.", + "inlineVolumeSpec": "inlineVolumeSpec contains all the information necessary to attach a persistent volume defined by a pod's inline VolumeSource. This field is populated only for the CSIMigration feature. It contains translated fields from a pod's inline VolumeSource to a PersistentVolumeSpec. This field is beta-level and is only honored by servers that enabled the CSIMigration feature.", } func (VolumeAttachmentSource) SwaggerDoc() map[string]string { diff --git a/staging/src/k8s.io/api/storage/v1alpha1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/storage/v1alpha1/types_swagger_doc_generated.go index 713498b3727..1431600d39a 100644 --- a/staging/src/k8s.io/api/storage/v1alpha1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/storage/v1alpha1/types_swagger_doc_generated.go @@ -74,6 +74,7 @@ func (VolumeAttachmentList) SwaggerDoc() map[string]string { var map_VolumeAttachmentSource = map[string]string{ "": "VolumeAttachmentSource represents a volume that should be attached. Right now only PersistentVolumes can be attached via external attacher, in the future we may allow also inline volumes in pods. Exactly one member can be set.", "persistentVolumeName": "persistentVolumeName represents the name of the persistent volume to attach.", + "inlineVolumeSpec": "inlineVolumeSpec contains all the information necessary to attach a persistent volume defined by a pod's inline VolumeSource. This field is populated only for the CSIMigration feature. It contains translated fields from a pod's inline VolumeSource to a PersistentVolumeSpec. This field is alpha-level and is only honored by servers that enabled the CSIMigration feature.", } func (VolumeAttachmentSource) SwaggerDoc() map[string]string { diff --git a/staging/src/k8s.io/api/storage/v1beta1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/storage/v1beta1/types_swagger_doc_generated.go index 80b68839b4e..298c9dd53c1 100644 --- a/staging/src/k8s.io/api/storage/v1beta1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/storage/v1beta1/types_swagger_doc_generated.go @@ -190,6 +190,7 @@ func (VolumeAttachmentList) SwaggerDoc() map[string]string { var map_VolumeAttachmentSource = map[string]string{ "": "VolumeAttachmentSource represents a volume that should be attached. Right now only PersistentVolumes can be attached via external attacher, in the future we may allow also inline volumes in pods. Exactly one member can be set.", "persistentVolumeName": "persistentVolumeName represents the name of the persistent volume to attach.", + "inlineVolumeSpec": "inlineVolumeSpec contains all the information necessary to attach a persistent volume defined by a pod's inline VolumeSource. This field is populated only for the CSIMigration feature. It contains translated fields from a pod's inline VolumeSource to a PersistentVolumeSpec. This field is beta-level and is only honored by servers that enabled the CSIMigration feature.", } func (VolumeAttachmentSource) SwaggerDoc() map[string]string { diff --git a/staging/src/k8s.io/apimachinery/pkg/runtime/swagger_doc_generator.go b/staging/src/k8s.io/apimachinery/pkg/runtime/swagger_doc_generator.go index 5bc642bc8e9..0d5a3e709dd 100644 --- a/staging/src/k8s.io/apimachinery/pkg/runtime/swagger_doc_generator.go +++ b/staging/src/k8s.io/apimachinery/pkg/runtime/swagger_doc_generator.go @@ -25,7 +25,10 @@ import ( "go/token" "io" "reflect" + "strconv" "strings" + + "k8s.io/apimachinery/pkg/util/errors" ) // Pair of strings. We keed the name of fields and the doc @@ -94,23 +97,29 @@ func fmtRawDoc(rawDoc string) string { // fieldName returns the name of the field as it should appear in JSON format // "-" indicates that this field is not part of the JSON representation -func fieldName(field *ast.Field) string { +func fieldName(field *ast.Field) (string, error) { jsonTag := "" if field.Tag != nil { - jsonTag = reflect.StructTag(field.Tag.Value[1 : len(field.Tag.Value)-1]).Get("json") // Delete first and last quotation - if strings.Contains(jsonTag, "inline") { - return "-" + var jsonTagExists bool + tagValue, err := strconv.Unquote(field.Tag.Value) + if err != nil { + return "", err + } + jsonTag, jsonTagExists = reflect.StructTag(tagValue).Lookup("json") // Delete first and last quotation + // field is embedded, json tag is declared and has an empty name + if field.Names == nil && jsonTagExists && (jsonTag == "" || strings.HasPrefix(jsonTag, ",")) { + return "-", nil } } jsonTag = strings.Split(jsonTag, ",")[0] // This can return "-" if jsonTag == "" { if field.Names != nil { - return field.Names[0].Name + return field.Names[0].Name, nil } - return field.Type.(*ast.Ident).Name + return field.Type.(*ast.Ident).Name, nil } - return jsonTag + return jsonTag, nil } // A buffer of lines that will be written. @@ -171,8 +180,9 @@ func writeMapBody(b *buffer, kubeType []Pair, indent int) { // array. Each type is again represented as an array (we have to use arrays as we // need to be sure for the order of the fields). This function returns fields and // struct definitions that have no documentation as {name, ""}. -func ParseDocumentationFrom(src string) []KubeTypes { +func ParseDocumentationFrom(src string) ([]KubeTypes, error) { var docForTypes []KubeTypes + var errs []error pkg := astFrom(src) @@ -182,7 +192,9 @@ func ParseDocumentationFrom(src string) []KubeTypes { ks = append(ks, Pair{kubType.Name, fmtRawDoc(kubType.Doc)}) for _, field := range structType.Fields.List { - if n := fieldName(field); n != "-" { + if n, err := fieldName(field); err != nil { + errs = append(errs, err) + } else if n != "-" { fieldDoc := fmtRawDoc(field.Doc.Text()) ks = append(ks, Pair{n, fieldDoc}) } @@ -191,7 +203,7 @@ func ParseDocumentationFrom(src string) []KubeTypes { } } - return docForTypes + return docForTypes, errors.NewAggregate(errs) } // WriteSwaggerDocFunc writes a declaration of a function as a string. This function is used in