This is an automated email from the ASF dual-hosted git repository.
Alanxtl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git
The following commit(s) were added to refs/heads/develop by this push:
new e50cfc62f feat(openapi): generate descriptions from proto comments
(#3630)
e50cfc62f is described below
commit e50cfc62f0e3ba62fd64b0a43d7349f7df3a7793
Author: XiaoFei <[email protected]>
AuthorDate: Mon Aug 10 16:14:10 2026 +0800
feat(openapi): generate descriptions from proto comments (#3630)
* feat(openapi): generate descriptions from proto comments
* fix: reuse protobuf description helper in triple openapi converter
---
tools/protoc-gen-triple-openapi/example/greet.proto | 8 ++++++++
.../example/greet.triple.openapi.json | 18 +++++++++++++-----
.../example/greet.triple.openapi.yaml | 8 ++++++++
.../internal/converter/convert.go | 7 ++++---
.../internal/converter/convert_test.go | 20 ++++++++++++++++++++
.../internal/converter/schema/util.go | 17 ++++++++++-------
6 files changed, 63 insertions(+), 15 deletions(-)
diff --git a/tools/protoc-gen-triple-openapi/example/greet.proto
b/tools/protoc-gen-triple-openapi/example/greet.proto
index 897fe6630..1af03e2b1 100644
--- a/tools/protoc-gen-triple-openapi/example/greet.proto
+++ b/tools/protoc-gen-triple-openapi/example/greet.proto
@@ -26,11 +26,17 @@ enum GreetingType {
GREETING_TYPE_FORMAL = 1;
}
+// A request to the Greet RPC.
message GreetRequest {
+ // Name of the person to greet.
string name = 1;
+ // Alternative names for the person.
repeated string aliases = 2;
+ // Additional request metadata.
map<string, string> metadata = 3;
+ // Preferred greeting style.
GreetingType type = 4;
+ // Profile details for the person.
GreetProfile profile = 5;
repeated GreetingType types = 6;
repeated GreetProfile profiles = 7;
@@ -54,7 +60,9 @@ message GreetUserResponse {
string greeting = 1;
}
+// APIs for greeting users.
service GreetService {
+ // Returns a greeting for a request.
rpc Greet(GreetRequest) returns (GreetResponse) {}
rpc GreetUser(GreetUserRequest) returns (GreetUserResponse) {}
diff --git a/tools/protoc-gen-triple-openapi/example/greet.triple.openapi.json
b/tools/protoc-gen-triple-openapi/example/greet.triple.openapi.json
index 289675c87..a2cf154fb 100644
--- a/tools/protoc-gen-triple-openapi/example/greet.triple.openapi.json
+++ b/tools/protoc-gen-triple-openapi/example/greet.triple.openapi.json
@@ -17,6 +17,7 @@
"tags": [
"greet.GreetService"
],
+ "description": "Returns a greeting for a request.",
"operationId": "Greet",
"requestBody": {
"content": {
@@ -130,28 +131,33 @@
"properties": {
"name": {
"type": "string",
- "title": "name"
+ "title": "name",
+ "description": "Name of the person to greet."
},
"aliases": {
"type": "array",
"items": {
"type": "string"
},
- "title": "aliases"
+ "title": "aliases",
+ "description": "Alternative names for the person."
},
"metadata": {
"type": "object",
"title": "metadata",
"additionalProperties": {
"type": "string"
- }
+ },
+ "description": "Additional request metadata."
},
"type": {
"title": "type",
+ "description": "Preferred greeting style.",
"$ref": "#/components/schemas/greet.GreetingType"
},
"profile": {
"title": "profile",
+ "description": "Profile details for the person.",
"$ref": "#/components/schemas/greet.GreetProfile"
},
"types": {
@@ -183,7 +189,8 @@
}
}
},
- "title": "GreetRequest"
+ "title": "GreetRequest",
+ "description": "A request to the Greet RPC."
},
"greet.GreetRequest.MetadataEntry": {
"type": "object",
@@ -285,7 +292,8 @@
"security": [],
"tags": [
{
- "name": "greet.GreetService"
+ "name": "greet.GreetService",
+ "description": "APIs for greeting users."
}
]
}
\ No newline at end of file
diff --git a/tools/protoc-gen-triple-openapi/example/greet.triple.openapi.yaml
b/tools/protoc-gen-triple-openapi/example/greet.triple.openapi.yaml
index 975cf78a1..72687d3d7 100644
--- a/tools/protoc-gen-triple-openapi/example/greet.triple.openapi.yaml
+++ b/tools/protoc-gen-triple-openapi/example/greet.triple.openapi.yaml
@@ -11,6 +11,7 @@ paths:
post:
tags:
- greet.GreetService
+ description: Returns a greeting for a request.
operationId: Greet
requestBody:
content:
@@ -82,21 +83,26 @@ components:
name:
type: string
title: name
+ description: Name of the person to greet.
aliases:
type: array
items:
type: string
title: aliases
+ description: Alternative names for the person.
metadata:
type: object
title: metadata
additionalProperties:
type: string
+ description: Additional request metadata.
type:
title: type
+ description: Preferred greeting style.
$ref: '#/components/schemas/greet.GreetingType'
profile:
title: profile
+ description: Profile details for the person.
$ref: '#/components/schemas/greet.GreetProfile'
types:
type: array
@@ -119,6 +125,7 @@ components:
additionalProperties:
$ref: '#/components/schemas/greet.GreetingType'
title: GreetRequest
+ description: A request to the Greet RPC.
greet.GreetRequest.MetadataEntry:
type: object
properties:
@@ -190,3 +197,4 @@ components:
security: []
tags:
- name: greet.GreetService
+ description: APIs for greeting users.
diff --git a/tools/protoc-gen-triple-openapi/internal/converter/convert.go
b/tools/protoc-gen-triple-openapi/internal/converter/convert.go
index f663eb682..e01153028 100644
--- a/tools/protoc-gen-triple-openapi/internal/converter/convert.go
+++ b/tools/protoc-gen-triple-openapi/internal/converter/convert.go
@@ -42,6 +42,7 @@ import (
import (
"dubbo.apache.org/dubbo-go/v3/tools/protoc-gen-triple-openapi/constant"
+
"dubbo.apache.org/dubbo-go/v3/tools/protoc-gen-triple-openapi/internal/converter/schema"
"dubbo.apache.org/dubbo-go/v3/tools/protoc-gen-triple-openapi/internal/options"
)
@@ -130,8 +131,8 @@ func convert(req *pluginpb.CodeGeneratorRequest)
(*pluginpb.CodeGeneratorRespons
service := services.Get(i)
tags = append(tags, &base.Tag{
- Name: string(service.FullName()),
- // TODO: add serivce description
+ Name: string(service.FullName()),
+ Description: schema.ProtoDescription(service),
})
methods := service.Methods()
@@ -142,7 +143,7 @@ func convert(req *pluginpb.CodeGeneratorRequest)
(*pluginpb.CodeGeneratorRespons
operation := &openapimodel.Operation{
OperationId: string(md.Name()),
Tags:
[]string{string(service.FullName())},
- // TODO: add operation description
+ Description:
schema.ProtoDescription(md),
}
// RequestBody
diff --git a/tools/protoc-gen-triple-openapi/internal/converter/convert_test.go
b/tools/protoc-gen-triple-openapi/internal/converter/convert_test.go
index d2ba3f71a..3f5be21fb 100644
--- a/tools/protoc-gen-triple-openapi/internal/converter/convert_test.go
+++ b/tools/protoc-gen-triple-openapi/internal/converter/convert_test.go
@@ -188,6 +188,18 @@ func greetRequest(format string)
*pluginpb.CodeGeneratorRequest {
},
},
},
+ SourceCodeInfo: &descriptorpb.SourceCodeInfo{
+ Location:
[]*descriptorpb.SourceCodeInfo_Location{
+ sourceComment([]int32{4, 0}, "A
request to the Greet RPC."),
+ sourceComment([]int32{4, 0, 2,
0}, "Name of the person to greet."),
+ sourceComment([]int32{4, 0, 2,
1}, "Alternative names for the person."),
+ sourceComment([]int32{4, 0, 2,
2}, "Additional request metadata."),
+ sourceComment([]int32{4, 0, 2,
3}, "Preferred greeting style."),
+ sourceComment([]int32{4, 0, 2,
4}, "Profile details for the person."),
+ sourceComment([]int32{6, 0},
"APIs for greeting users."),
+ sourceComment([]int32{6, 0, 2,
0}, "Returns a greeting for a request."),
+ },
+ },
},
},
}
@@ -291,3 +303,11 @@ func field(name, jsonName string, number int32, label
descriptorpb.FieldDescript
}
return fd
}
+
+func sourceComment(path []int32, comment string)
*descriptorpb.SourceCodeInfo_Location {
+ return &descriptorpb.SourceCodeInfo_Location{
+ Path: path,
+ Span: []int32{0, 0, 0, 1},
+ LeadingComments: proto.String(comment),
+ }
+}
diff --git a/tools/protoc-gen-triple-openapi/internal/converter/schema/util.go
b/tools/protoc-gen-triple-openapi/internal/converter/schema/util.go
index f51719762..ece1cfe95 100644
--- a/tools/protoc-gen-triple-openapi/internal/converter/schema/util.go
+++ b/tools/protoc-gen-triple-openapi/internal/converter/schema/util.go
@@ -19,6 +19,7 @@ package schema
import (
"fmt"
+ "strings"
)
import (
@@ -32,9 +33,8 @@ import (
func messageToSchema(tt protoreflect.MessageDescriptor) (string, *base.Schema)
{
s := &base.Schema{
- Title: string(tt.Name()),
- // TODO: add Description
- Description: "",
+ Title: string(tt.Name()),
+ Description: ProtoDescription(tt),
Type: []string{"object"},
}
@@ -65,7 +65,7 @@ func fieldToSchema(parent *base.SchemaProxy, tt
protoreflect.FieldDescriptor) *b
default:
root.AdditionalProperties =
&base.DynamicValue[*base.SchemaProxy, bool]{A:
base.CreateSchemaProxy(ScalarFieldToSchema(parent, value, true))}
}
- root.Description = ""
+ root.Description = ProtoDescription(tt)
return base.CreateSchemaProxy(root)
} else if tt.IsList() {
var itemSchema *base.SchemaProxy
@@ -80,8 +80,7 @@ func fieldToSchema(parent *base.SchemaProxy, tt
protoreflect.FieldDescriptor) *b
s := &base.Schema{
Title: string(tt.Name()),
ParentProxy: parent,
- // TODO: todo
- Description: "",
+ Description: ProtoDescription(tt),
Type: []string{"array"},
Items: &base.DynamicValue[*base.SchemaProxy,
bool]{A: itemSchema},
}
@@ -108,7 +107,7 @@ func ScalarFieldToSchema(parent *base.SchemaProxy, tt
protoreflect.FieldDescript
}
if !inContainer {
s.Title = string(tt.Name())
- // TODO: add description
+ s.Description = ProtoDescription(tt)
}
switch tt.Kind() {
@@ -175,3 +174,7 @@ func CreateStringNode(str string) *yaml.Node {
}
return n
}
+
+func ProtoDescription(descriptor protoreflect.Descriptor) string {
+ return
strings.TrimSpace(descriptor.ParentFile().SourceLocations().ByDescriptor(descriptor).LeadingComments)
+}