-
Notifications
You must be signed in to change notification settings - Fork 88
Add "exposed" operation for system nexus endpoint #736
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
Open
spkane31
wants to merge
11
commits into
master
Choose a base branch
from
spk/signal-with-start
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
b37d25e
Add "exposed" operation for system nexus endpoint
spkane31 d70e3ca
merge conflicts
spkane31 b517764
linter fixes
spkane31 f0760b3
remove local nexusannotations and use nexus-rpc repo
spkane31 3f17a76
add nexus annotations to buf.yaml
spkane31 ba43a56
buf.lock
spkane31 ab1b41d
add target to Makefile for downloading updates
spkane31 e263cf2
Merge branch 'master' of github.com:temporalio/api into spk/signal-wi…
spkane31 4979ae3
Merge branch 'master' of github.com:temporalio/api into spk/signal-wi…
spkane31 65d1c56
first draft of a nexusrpc{.langs}.yaml files
spkane31 9558edf
use json pointer format instead of dot notation
spkane31 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,196 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "slices" | ||
| "sort" | ||
| "strings" | ||
|
|
||
| nexusannotationsv1 "github.com/nexus-rpc/nexus-proto-annotations/go/nexusannotations/v1" | ||
| "google.golang.org/protobuf/compiler/protogen" | ||
| "google.golang.org/protobuf/proto" | ||
| "google.golang.org/protobuf/reflect/protoreflect" | ||
| "google.golang.org/protobuf/types/descriptorpb" | ||
| "gopkg.in/yaml.v3" | ||
| ) | ||
|
|
||
| func generate(gen *protogen.Plugin) error { | ||
| nexusDoc := newDoc() | ||
| langsDoc := newDoc() | ||
|
|
||
| for _, f := range gen.Files { | ||
| if !f.Generate { | ||
| continue | ||
| } | ||
| for _, svc := range f.Services { | ||
| for _, m := range svc.Methods { | ||
| opts, ok := m.Desc.Options().(*descriptorpb.MethodOptions) | ||
| if !ok || opts == nil { | ||
| continue | ||
| } | ||
| if !proto.HasExtension(opts, nexusannotationsv1.E_Operation) { | ||
| continue | ||
| } | ||
| opOpts := proto.GetExtension(opts, nexusannotationsv1.E_Operation).(*nexusannotationsv1.OperationOptions) | ||
| if !slices.Contains(opOpts.GetTags(), "exposed") { | ||
| continue | ||
| } | ||
|
|
||
| svcName := string(svc.Desc.Name()) | ||
| methodName := string(m.Desc.Name()) | ||
|
|
||
| addOperation(nexusDoc, svcName, methodName, | ||
| map[string]string{"$ref": openAPIRef(m.Input.Desc)}, | ||
| map[string]string{"$ref": openAPIRef(m.Output.Desc)}, | ||
| ) | ||
|
|
||
| addOperation(langsDoc, svcName, methodName, | ||
| langRefs(f.Desc, m.Input.Desc), | ||
| langRefs(f.Desc, m.Output.Desc), | ||
| ) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if err := writeFile(gen, "nexus/nexusrpc.yaml", nexusDoc); err != nil { | ||
| return err | ||
| } | ||
| return writeFile(gen, "nexus/nexusrpc.langs.yaml", langsDoc) | ||
| } | ||
|
|
||
| // openAPIRef returns the nexus-rpc-gen multi-file $ref string for a message type, | ||
| // referencing the openapiv3.yaml components/schemas entry. The path is relative to nexus/. | ||
| // | ||
| // Schema key convention used by protoc-gen-openapi (v3): | ||
| // | ||
| // {MessageName} (no package prefix) | ||
| // | ||
| // e.g. message "SignalWithStartWorkflowExecutionRequest" | ||
| // → "../openapi/openapiv3.yaml#/components/schemas/SignalWithStartWorkflowExecutionRequest" | ||
| func openAPIRef(msg protoreflect.MessageDescriptor) string { | ||
| return "../openapi/openapiv3.yaml#/components/schemas/" + string(msg.Name()) | ||
| } | ||
|
|
||
| // langRefs builds the map of language-specific type refs for a message, | ||
| // derived from proto file-level options. Only keys with non-empty values are included. | ||
| // Order is canonical: go → java → ruby → csharp. | ||
| func langRefs(file protoreflect.FileDescriptor, msg protoreflect.MessageDescriptor) map[string]string { | ||
| opts, ok := file.Options().(*descriptorpb.FileOptions) | ||
| if !ok || opts == nil { | ||
| return nil | ||
| } | ||
| name := string(msg.Name()) | ||
| refs := make(map[string]string) | ||
|
|
||
| if pkg := opts.GetGoPackage(); pkg != "" { | ||
| // strip the ";alias" suffix (e.g. "go.temporal.io/api/workflowservice/v1;workflowservice") | ||
| pkg = strings.SplitN(pkg, ";", 2)[0] | ||
| refs["$goRef"] = pkg + "." + name | ||
| } | ||
| if pkg := opts.GetJavaPackage(); pkg != "" { | ||
| refs["$javaRef"] = pkg + "." + name | ||
| } | ||
| if pkg := opts.GetRubyPackage(); pkg != "" { | ||
| refs["$rubyRef"] = pkg + "::" + name | ||
| } | ||
| if pkg := opts.GetCsharpNamespace(); pkg != "" { | ||
| refs["$csharpRef"] = pkg + "." + name | ||
| } | ||
| if len(refs) == 0 { | ||
| return nil | ||
| } | ||
| return refs | ||
| } | ||
|
|
||
| // newDoc creates a yaml.Node document with the "nexusrpc: 1.0.0" header | ||
| // and an empty "services" mapping node, returned as a *yaml.Node (document node). | ||
| func newDoc() *yaml.Node { | ||
| doc := &yaml.Node{Kind: yaml.DocumentNode} | ||
| root := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} | ||
| doc.Content = []*yaml.Node{root} | ||
|
|
||
| root.Content = append(root.Content, | ||
| scalarNode("nexusrpc"), | ||
| scalarNode("1.0.0"), | ||
| scalarNode("services"), | ||
| &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}, | ||
| ) | ||
| return doc | ||
| } | ||
|
|
||
| // servicesNode returns the "services" mapping node from a doc created by newDoc. | ||
| func servicesNode(doc *yaml.Node) *yaml.Node { | ||
| root := doc.Content[0] | ||
| for i := 0; i < len(root.Content)-1; i += 2 { | ||
| if root.Content[i].Value == "services" { | ||
| return root.Content[i+1] | ||
| } | ||
| } | ||
| panic("services node not found") | ||
| } | ||
|
|
||
| // addOperation inserts a service → operation → {input, output} entry into doc. | ||
| // Services and operations are inserted in the order first encountered. | ||
| func addOperation(doc *yaml.Node, svcName, methodName string, input, output map[string]string) { | ||
| svcs := servicesNode(doc) | ||
|
|
||
| // find or create service node | ||
| var svcOps *yaml.Node | ||
| for i := 0; i < len(svcs.Content)-1; i += 2 { | ||
| if svcs.Content[i].Value == svcName { | ||
| // find "operations" within service mapping | ||
| svcMap := svcs.Content[i+1] | ||
| for j := 0; j < len(svcMap.Content)-1; j += 2 { | ||
| if svcMap.Content[j].Value == "operations" { | ||
| svcOps = svcMap.Content[j+1] | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if svcOps == nil { | ||
| svcMap := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} | ||
| svcOps = &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} | ||
| svcMap.Content = append(svcMap.Content, | ||
| scalarNode("operations"), | ||
| svcOps, | ||
| ) | ||
| svcs.Content = append(svcs.Content, scalarNode(svcName), svcMap) | ||
| } | ||
|
|
||
| // build operation node | ||
| opNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} | ||
| if len(input) > 0 { | ||
| opNode.Content = append(opNode.Content, scalarNode("input"), mapNode(input)) | ||
| } | ||
| if len(output) > 0 { | ||
| opNode.Content = append(opNode.Content, scalarNode("output"), mapNode(output)) | ||
| } | ||
| svcOps.Content = append(svcOps.Content, scalarNode(methodName), opNode) | ||
| } | ||
|
|
||
| // mapNode serializes a map[string]string as a yaml mapping node with keys in sorted order. | ||
| func mapNode(m map[string]string) *yaml.Node { | ||
| keys := make([]string, 0, len(m)) | ||
| for k := range m { | ||
| keys = append(keys, k) | ||
| } | ||
| sort.Strings(keys) | ||
| node := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"} | ||
| for _, k := range keys { | ||
| node.Content = append(node.Content, scalarNode(k), scalarNode(m[k])) | ||
| } | ||
| return node | ||
| } | ||
|
|
||
| func scalarNode(value string) *yaml.Node { | ||
| return &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: value} | ||
| } | ||
|
|
||
| func writeFile(gen *protogen.Plugin, name string, doc *yaml.Node) error { | ||
| f := gen.NewGeneratedFile(name, "") | ||
| enc := yaml.NewEncoder(f) | ||
| enc.SetIndent(2) | ||
| if err := enc.Encode(doc); err != nil { | ||
| return err | ||
| } | ||
| return enc.Close() | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| module github.com/temporalio/api/cmd/protoc-gen-nexus-rpc-yaml | ||
|
|
||
| go 1.25.4 | ||
|
|
||
| require ( | ||
| google.golang.org/protobuf v1.36.1 | ||
| gopkg.in/yaml.v3 v3.0.1 | ||
| ) | ||
|
|
||
| require github.com/nexus-rpc/nexus-proto-annotations v0.0.0-20260330194009-e558d6edaf84 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= | ||
| github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||
| github.com/nexus-rpc/nexus-proto-annotations v0.0.0-20260330194009-e558d6edaf84 h1:SWHt3Coj0VvF0Km1A0wlY+IjnHKsjQLgO29io84r3wY= | ||
| github.com/nexus-rpc/nexus-proto-annotations v0.0.0-20260330194009-e558d6edaf84/go.mod h1:n3UjF1bPCW8llR8tHvbxJ+27yPWrhpo8w/Yg1IOuY0Y= | ||
| golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= | ||
| golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
| google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= | ||
| google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= | ||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| // protoc-gen-nexus-rpc-yaml is a protoc plugin that generates nexus/nexusrpc.yaml | ||
| // and nexus/nexusrpc.langs.yaml from proto service methods annotated with | ||
| // option (nexusannotations.v1.operation).tags = "exposed". | ||
| package main | ||
|
|
||
| import ( | ||
| "google.golang.org/protobuf/compiler/protogen" | ||
| ) | ||
|
|
||
| func main() { | ||
| protogen.Options{}.Run(func(gen *protogen.Plugin) error { | ||
| return generate(gen) | ||
| }) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| nexusrpc: 1.0.0 | ||
| services: | ||
| WorkflowService: | ||
| operations: | ||
| SignalWithStartWorkflowExecution: | ||
| input: | ||
| $csharpRef: Temporalio.Api.WorkflowService.V1.SignalWithStartWorkflowExecutionRequest | ||
| $goRef: go.temporal.io/api/workflowservice/v1.SignalWithStartWorkflowExecutionRequest | ||
| $javaRef: io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionRequest | ||
| $rubyRef: Temporalio::Api::WorkflowService::V1::SignalWithStartWorkflowExecutionRequest | ||
| output: | ||
| $csharpRef: Temporalio.Api.WorkflowService.V1.SignalWithStartWorkflowExecutionResponse | ||
| $goRef: go.temporal.io/api/workflowservice/v1.SignalWithStartWorkflowExecutionResponse | ||
| $javaRef: io.temporal.api.workflowservice.v1.SignalWithStartWorkflowExecutionResponse | ||
| $rubyRef: Temporalio::Api::WorkflowService::V1::SignalWithStartWorkflowExecutionResponse |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| nexusrpc: 1.0.0 | ||
| services: | ||
| WorkflowService: | ||
| operations: | ||
| SignalWithStartWorkflowExecution: | ||
| input: | ||
| $ref: ../openapi/openapiv3.yaml#/components/schemas/SignalWithStartWorkflowExecutionRequest | ||
| output: | ||
| $ref: ../openapi/openapiv3.yaml#/components/schemas/SignalWithStartWorkflowExecutionResponse |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| syntax = "proto3"; | ||
|
|
||
| package nexusannotations.v1; | ||
|
|
||
| import "google/protobuf/descriptor.proto"; | ||
|
|
||
| option go_package = "github.com/nexus-rpc/nexus-proto-annotations/go/nexusannotations/v1"; | ||
|
|
||
| extend google.protobuf.ServiceOptions { | ||
| optional ServiceOptions service = 8233; | ||
| } | ||
|
|
||
| extend google.protobuf.MethodOptions { | ||
| optional OperationOptions operation = 8234; | ||
| } | ||
|
|
||
| message OperationOptions { | ||
| // Nexus operation name (defaults to proto method name). | ||
| string name = 1; | ||
| // Tags to attach to the operation. Used by code generators to include and exclude operations. | ||
| repeated string tags = 2; | ||
| } | ||
|
|
||
| message ServiceOptions { | ||
| // Nexus service name (defaults to proto service full name). | ||
| string name = 1; | ||
| // Tags to attach to the service. Used by code generators to include and exclude services. | ||
| repeated string tags = 2; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we have the same make target for google? Seems like we can sync both. But probably don't sync google as part of this PR if there are any changes there, better to do that separately.