diff --git a/internal/gengapic/client_init.go b/internal/gengapic/client_init.go index c1bbac3171d..cc8aee75d81 100644 --- a/internal/gengapic/client_init.go +++ b/internal/gengapic/client_init.go @@ -154,7 +154,7 @@ func (g *generator) internalClientIntfInit(serv *descriptorpb.ServiceDescriptorP } // serviceDoc is a helper function similar to methodDoc that includes a deprecation notice for deprecated services. -func (g *generator) serviceDoc(serv *descriptorpb.ServiceDescriptorProto) { +func (g *generator) serviceDoc(serv *descriptorpb.ServiceDescriptorProto, includeAPIVersion bool) { com := g.comments[serv] // If there's no comment and the service is not deprecated, return. @@ -184,6 +184,12 @@ func (g *generator) serviceDoc(serv *descriptorpb.ServiceDescriptorProto) { // Prepend new line break before existing service comments. g.printf("//") g.comment(com) + + apiVersion := proto.GetExtension(serv.Options, annotations.E_ApiVersion).(string) + if apiVersion != "" && includeAPIVersion { + g.printf("//") + g.comment(fmt.Sprintf("This client uses %s version %s.", serv.GetName(), apiVersion)) + } } func (g *generator) clientInit(serv *descriptorpb.ServiceDescriptorProto, servName string, hasRPCForLRO bool) { @@ -192,7 +198,7 @@ func (g *generator) clientInit(serv *descriptorpb.ServiceDescriptorProto, servNa // client struct p("// %sClient is a client for interacting with %s.", servName, g.apiName) p("// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.") - g.serviceDoc(serv) + g.serviceDoc(serv, true) // include API version docs p("type %sClient struct {", servName) // Fields diff --git a/internal/gengapic/client_init_test.go b/internal/gengapic/client_init_test.go index 813ce164804..fdb0dfa8df9 100644 --- a/internal/gengapic/client_init_test.go +++ b/internal/gengapic/client_init_test.go @@ -260,16 +260,21 @@ func TestClientOpt(t *testing.T) { } func TestServiceDoc(t *testing.T) { + sOpts := &descriptorpb.ServiceOptions{} + proto.SetExtension(sOpts, annotations.E_ApiVersion, "2024-09-14") + serv := &descriptorpb.ServiceDescriptorProto{ - Name: proto.String("MyService"), + Name: proto.String("MyService"), + Options: sOpts, } var g generator g.comments = make(map[protoiface.MessageV1]string) for _, tst := range []struct { - in, want string - deprecated bool + in, want string + deprecated bool + includeAPIVersion bool }{ { in: "", @@ -279,6 +284,11 @@ func TestServiceDoc(t *testing.T) { in: "Does stuff.\n It also does other stuffs.", want: "//\n// Does stuff.\n// It also does other stuffs.\n", }, + { + in: "Does stuff.\n It also does other stuffs.", + want: "//\n// Does stuff.\n// It also does other stuffs.\n//\n// This client uses MyService version 2024-09-14.\n", + includeAPIVersion: true, + }, { in: "This is deprecated.\n It does not have a proper comment.", want: "//\n// This is deprecated.\n// It does not have a proper comment.\n//\n// Deprecated: MyService may be removed in a future version.\n", @@ -301,11 +311,10 @@ func TestServiceDoc(t *testing.T) { }, } { g.comments[serv] = tst.in - serv.Options = &descriptorpb.ServiceOptions{ - Deprecated: proto.Bool(tst.deprecated), - } + serv.Options.Deprecated = proto.Bool(tst.deprecated) + g.pt.Reset() - g.serviceDoc(serv) + g.serviceDoc(serv, tst.includeAPIVersion) if diff := cmp.Diff(g.pt.String(), tst.want); diff != "" { t.Errorf("comment() got(-),want(+):\n%s", diff) } diff --git a/internal/gengapic/gengrpc.go b/internal/gengapic/gengrpc.go index 9c97e7b2e97..f0b2b7d9ea3 100644 --- a/internal/gengapic/gengrpc.go +++ b/internal/gengapic/gengrpc.go @@ -326,7 +326,7 @@ func (g *generator) grpcClientUtilities(serv *descriptorpb.ServiceDescriptorProt // Factory function p("// New%sClient creates a new %s client based on gRPC.", servName, clientName) p("// The returned client must be Closed when it is done being used to clean up its underlying connections.") - g.serviceDoc(serv) + g.serviceDoc(serv, false) // exclude API version docs p("func New%[1]sClient(ctx context.Context, opts ...option.ClientOption) (*%[1]sClient, error) {", servName) p(" clientOpts := default%[1]sGRPCClientOptions()", servName) diff --git a/internal/gengapic/genrest.go b/internal/gengapic/genrest.go index 3dd356230bd..d0308187331 100644 --- a/internal/gengapic/genrest.go +++ b/internal/gengapic/genrest.go @@ -159,7 +159,7 @@ func (g *generator) restClientUtilities(serv *descriptorpb.ServiceDescriptorProt opServ, hasCustomOp := g.customOpServices[serv] p("// New%sRESTClient creates a new %s rest client.", servName, clientName) - g.serviceDoc(serv) + g.serviceDoc(serv, false) // exclude API version docs p("func New%[1]sRESTClient(ctx context.Context, opts ...option.ClientOption) (*%[1]sClient, error) {", servName) p(" clientOpts := append(default%sRESTClientOptions(), opts...)", servName) p(" httpClient, endpoint, err := httptransport.NewClient(ctx, clientOpts...)") diff --git a/internal/gengapic/testdata/empty_client_init.want b/internal/gengapic/testdata/empty_client_init.want index ad37c877181..cbf05d3afb6 100644 --- a/internal/gengapic/testdata/empty_client_init.want +++ b/internal/gengapic/testdata/empty_client_init.want @@ -10,6 +10,8 @@ type internalClient interface { // Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. // // Foo service does stuff. +// +// This client uses Foo version v1_20240425. type Client struct { // The internal transport-dependent client. internalClient internalClient diff --git a/internal/gengapic/testdata/foo_client_init.want b/internal/gengapic/testdata/foo_client_init.want index 0b4a655bb72..dd0006ef3cb 100644 --- a/internal/gengapic/testdata/foo_client_init.want +++ b/internal/gengapic/testdata/foo_client_init.want @@ -15,6 +15,8 @@ type internalFooClient interface { // Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. // // Foo service does stuff. +// +// This client uses Foo version v1_20240425. type FooClient struct { // The internal transport-dependent client. internalClient internalFooClient diff --git a/internal/gengapic/testdata/foo_rest_client_init.want b/internal/gengapic/testdata/foo_rest_client_init.want index d15cca94a1e..a50a98942fe 100644 --- a/internal/gengapic/testdata/foo_rest_client_init.want +++ b/internal/gengapic/testdata/foo_rest_client_init.want @@ -15,6 +15,8 @@ type internalFooClient interface { // Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. // // Foo service does stuff. +// +// This client uses Foo version v1_20240425. type FooClient struct { // The internal transport-dependent client. internalClient internalFooClient diff --git a/internal/gengapic/testdata/lro_client_init.want b/internal/gengapic/testdata/lro_client_init.want index 70578426c47..93689df9674 100644 --- a/internal/gengapic/testdata/lro_client_init.want +++ b/internal/gengapic/testdata/lro_client_init.want @@ -16,6 +16,8 @@ type internalFooClient interface { // Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. // // Foo service does stuff. +// +// This client uses Foo version v1_20240425. type FooClient struct { // The internal transport-dependent client. internalClient internalFooClient