gapic-generator 0.10.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/lib/gapic/generator/version.rb +1 -1
  4. data/lib/gapic/generators/default_generator.rb +2 -0
  5. data/lib/gapic/generators/default_generator_parameters.rb +3 -1
  6. data/lib/gapic/grpc_service_config/{service_config.rb → config.rb} +2 -2
  7. data/lib/gapic/grpc_service_config/parser.rb +8 -8
  8. data/lib/gapic/model/method/http_annotation.rb +123 -0
  9. data/lib/gapic/model/method/lro.rb +160 -0
  10. data/lib/gapic/model/method/routing.rb +263 -0
  11. data/lib/gapic/model/mixins.rb +181 -0
  12. data/lib/gapic/model/model_error.rb +26 -0
  13. data/lib/gapic/model/service/nonstandard_lro_provider.rb +293 -0
  14. data/lib/gapic/model.rb +22 -0
  15. data/lib/gapic/path_pattern/pattern.rb +46 -0
  16. data/lib/gapic/path_pattern/segment.rb +97 -9
  17. data/lib/gapic/presenters/gem_presenter.rb +34 -2
  18. data/lib/gapic/presenters/{service_config_presenter.rb → grpc_service_config_presenter.rb} +1 -1
  19. data/lib/gapic/presenters/method_presenter.rb +43 -3
  20. data/lib/gapic/presenters/method_rest_presenter.rb +33 -55
  21. data/lib/gapic/presenters/service/lro_client_presenter.rb +90 -0
  22. data/lib/gapic/presenters/service_presenter.rb +185 -3
  23. data/lib/gapic/presenters/service_rest_presenter.rb +81 -0
  24. data/lib/gapic/presenters/snippet_presenter.rb +1 -0
  25. data/lib/gapic/presenters.rb +3 -1
  26. data/lib/gapic/schema/api.rb +56 -2
  27. data/lib/gapic/schema/loader.rb +4 -1
  28. data/lib/gapic/schema/service_config_parser.rb +118 -0
  29. data/lib/gapic/schema/wrappers.rb +124 -1
  30. data/lib/google/api/auth.pb.rb +75 -0
  31. data/lib/google/api/backend.pb.rb +59 -0
  32. data/lib/google/api/billing.pb.rb +53 -0
  33. data/lib/google/api/context.pb.rb +47 -0
  34. data/lib/google/api/control.pb.rb +38 -0
  35. data/lib/google/api/documentation.pb.rb +56 -0
  36. data/lib/google/api/endpoint.pb.rb +42 -0
  37. data/lib/google/api/label.pb.rb +49 -0
  38. data/lib/google/api/launch_stage.pb.rb +37 -0
  39. data/lib/google/api/log.pb.rb +47 -0
  40. data/lib/google/api/logging.pb.rb +48 -0
  41. data/lib/google/api/metric.pb.rb +90 -0
  42. data/lib/google/api/monitored_resource.pb.rb +68 -0
  43. data/lib/google/api/monitoring.pb.rb +48 -0
  44. data/lib/google/api/quota.pb.rb +63 -0
  45. data/lib/google/api/routing.pb.rb +58 -0
  46. data/lib/google/api/service.pb.rb +90 -0
  47. data/lib/google/api/source_info.pb.rb +44 -0
  48. data/lib/google/api/system_parameter.pb.rb +51 -0
  49. data/lib/google/api/usage.pb.rb +47 -0
  50. data/lib/google/cloud/extended_operations.pb.rb +57 -0
  51. data/lib/google/protobuf/any.pb.rb +1 -1
  52. data/lib/google/protobuf/api.pb.rb +69 -0
  53. data/lib/google/protobuf/descriptor.pb.rb +1 -1
  54. data/lib/google/protobuf/duration.pb.rb +41 -0
  55. data/lib/google/protobuf/source_context.pb.rb +39 -0
  56. data/lib/google/protobuf/struct.pb.rb +65 -0
  57. data/lib/google/protobuf/type.pb.rb +128 -0
  58. data/lib/google/protobuf/wrappers.pb.rb +80 -0
  59. data/templates/default/gem/yardopts.erb +1 -1
  60. data/templates/default/lib/_package.erb +4 -0
  61. data/templates/default/lib/_service.erb +6 -0
  62. data/templates/default/service/client/_client.erb +20 -8
  63. data/templates/default/service/client/_nonstandard_lro.erb +57 -0
  64. data/templates/default/service/client/_self_configure_defaults.erb +2 -2
  65. data/templates/default/service/client/method/def/_options_defaults.erb +1 -8
  66. data/templates/default/service/client/method/def/_response.erb +2 -0
  67. data/templates/default/service/client/method/def/_response_nonstandard_lro.erb +23 -0
  68. data/templates/default/service/client/method/def/_routing_params.erb +36 -0
  69. data/templates/default/service/nonstandard_lro.erb +6 -0
  70. data/templates/default/service/rest/client/_client.erb +32 -5
  71. data/templates/default/service/rest/client/method/def/_response.erb +2 -2
  72. data/templates/default/service/rest/client/method/def/_response_nonstandard_lro.erb +23 -0
  73. data/templates/default/service/test/method/_assert_response.erb +3 -0
  74. metadata +61 -7
  75. data/templates/default/service/rest/client/method/def/_response_lro.erb +0 -7
@@ -0,0 +1,263 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2021 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "gapic/path_pattern"
18
+
19
+ module Gapic
20
+ module Model
21
+ module Method
22
+ ##
23
+ # Routing headers info determined from the proto method
24
+ #
25
+ # @!attribute [r] routing
26
+ # @return [::Google::Api::RoutingRule] Explicit routing annotation for the Api
27
+ class Routing
28
+ attr_reader :routing
29
+
30
+ ##
31
+ # @param routing [::Google::Api::RoutingRule] Explict routing annotation for the Api
32
+ # @param http [Gapic::Model::Method::HttpAnnotation] Model for the Http annotation
33
+ #
34
+ def initialize routing, http
35
+ @routing = routing
36
+ @http = http
37
+ end
38
+
39
+ ##
40
+ # Whether routing parameters are specified
41
+ #
42
+ # @return [Boolean]
43
+ def routing_params?
44
+ explicit_params? || implicit_params?
45
+ end
46
+
47
+ ##
48
+ # Whether an explicit routing annotation (`google.api.routing`) is present
49
+ #
50
+ # @return [Boolean]
51
+ def explicit_annotation?
52
+ !@routing.nil?
53
+ end
54
+
55
+ ##
56
+ # Whether an annotation that might contain implicit routing (`google.api.http`) is present
57
+ #
58
+ # @return [Boolean]
59
+ def implicit_annotation?
60
+ !@http.nil?
61
+ end
62
+
63
+ ##
64
+ # Whether explicit routing parameters are present
65
+ #
66
+ # @return [Boolean]
67
+ def explicit_params?
68
+ return false unless explicit_annotation?
69
+
70
+ explicit_params.any?
71
+ end
72
+
73
+ ##
74
+ # Explicit routing parameters, if present.
75
+ # Grouped by the routing key, in order, with the extraction and matching information.
76
+ #
77
+ # @return [Hash<String, Array>]
78
+ def explicit_params
79
+ all_explicit_params.group_by(&:key).transform_values do |params|
80
+ params.sort_by(&:order).to_a
81
+ end
82
+ end
83
+
84
+ ##
85
+ # Whether implict routing parameters from `google.api.http` annotation are present
86
+ #
87
+ # @return [Boolean]
88
+ def implicit_params?
89
+ @http.routing_params?
90
+ end
91
+
92
+ ##
93
+ # Implicit routing parameters.
94
+ # These strings are both field and routing header key names.
95
+ #
96
+ # @return [Array<String>]
97
+ def implicit_params
98
+ return {} unless implicit_params?
99
+ @http.routing_params
100
+ end
101
+
102
+ ##
103
+ # Full routing parameter information, including parsing order
104
+ # and matching/extraction patterns and regexes.
105
+ #
106
+ # @!attribute [r] order
107
+ # @return [Integer] Order of the parameter in the annotation
108
+ #
109
+ # @!attribute [r] field
110
+ # @return [String] Field to extract the routing header from
111
+ #
112
+ # @!attribute [r] raw_template
113
+ # @return [String, nil] Raw template as given in the annotation
114
+ #
115
+ # @!attribute [r] path_template
116
+ # @return [String] 'Processed' template, handling such cases as
117
+ # empty or nameless template
118
+ #
119
+ # @!attribute [r] key
120
+ # @return [String] Name of the key to add to the routing header
121
+ #
122
+ # @!attribute [r] value_pattern
123
+ # @return [String] The pattern of the value to be extracted
124
+ #
125
+ # @!attribute [r] field_pattern
126
+ # @return [String] The pattern of the full field (simplified)
127
+ # The field as a whole should match this pattern
128
+ # This pattern is simplified, stipped of the names of the
129
+ # resource id segments.
130
+ # (e.g. `collections/{resource_id=foo/*}` => `collections/foo/*`)
131
+ #
132
+ # @!attribute [r] field_regex_str
133
+ # @return [String] The regex matching the `field_pattern`
134
+ # (the regex form of the simplified pattern)
135
+ #
136
+ # @!attribute [r] field_full_regex_str
137
+ # @return [String] The regex matching the full unsimplified field pattern
138
+ # (it will contain the named capture corresponding to the
139
+ # resource id segment name)
140
+ #
141
+ class RoutingParameter
142
+ attr_reader :order
143
+ attr_reader :field
144
+ attr_reader :raw_template
145
+ attr_reader :path_template
146
+ attr_reader :key
147
+ attr_reader :value_pattern
148
+ attr_reader :field_pattern
149
+ attr_reader :field_regex_str
150
+ attr_reader :field_full_regex_str
151
+
152
+ ##
153
+ # @param routing_parameter [::Google::Api::RoutingParameter]
154
+ # Routing parameter annotation
155
+ #
156
+ # @param order [Integer]
157
+ # Order of this annotation among its peers
158
+ def initialize routing_parameter, order
159
+ @order = order
160
+ @field = routing_parameter.field
161
+ @raw_template = routing_parameter.path_template
162
+ @path_template = infer_template @raw_template, @field
163
+ @path_pattern = Gapic::PathPattern.parse @path_template
164
+
165
+ resource_segment = @path_pattern.segments.find(&:resource_id_segment?)
166
+
167
+ # Only one segment providing an argument and only one argument in the segment
168
+ # (no `{foo}~{bar}` segments)
169
+ valid = @path_pattern.segments.count(&:resource_id_segment?) == 1 &&
170
+ resource_segment.arguments.count == 1
171
+
172
+ unless valid
173
+ error_text = create_invalid_error_text @path_pattern, @raw_template
174
+ raise ModelError, error_text
175
+ end
176
+
177
+ @field_pattern = @path_pattern.simplified_pattern
178
+ @field_full_regex_str = to_field_pattern @path_pattern
179
+ @field_regex_str = to_field_pattern Gapic::PathPattern.parse(@field_pattern)
180
+
181
+ @key = resource_segment.arguments[0]
182
+ @value_pattern = resource_segment.resource_patterns[0]
183
+ end
184
+
185
+ ##
186
+ # Whether pattern matching is not needed
187
+ # since the patterns allow all strings
188
+ # @return [Boolean]
189
+ def pattern_matching_not_needed?
190
+ field_pattern == "**" && value_pattern == "**"
191
+ end
192
+
193
+ ##
194
+ # Whether the value to be added to the routing header
195
+ # is the value of the whole field
196
+ # @return [Boolean]
197
+ def value_is_full_field?
198
+ @path_pattern.segments.count == 1
199
+ end
200
+
201
+ private
202
+
203
+ # Makes a regex pattern match a field
204
+ # - adds markers for the beginning and end of the string
205
+ # - adds handling of an optional tail `/` if needed
206
+ # @param pattern [String]
207
+ # @return [String]
208
+ def to_field_pattern pattern
209
+ tail_slash_accept = if pattern.segments.last.simplified_pattern == "**"
210
+ ""
211
+ else
212
+ "/?"
213
+ end
214
+ "^#{pattern.to_regex_str}#{tail_slash_accept}$"
215
+ end
216
+
217
+ # Converts path template simplified forms into canonical
218
+ # ResourceId representations by adding a field as a Resource Id
219
+ # @param template [String]
220
+ # @param field [String]
221
+ # @return [String]
222
+ def infer_template template, field
223
+ if template.nil? || template.empty?
224
+ return "{#{field}=**}"
225
+ end
226
+
227
+ if template.strip == "**"
228
+ return "{#{field}=**}"
229
+ end
230
+
231
+ if template.strip == "*"
232
+ return "{#{field}=*}"
233
+ end
234
+
235
+ template
236
+ end
237
+
238
+ def create_invalid_error_text path_pattern, raw_template
239
+ reason = if path_pattern.segments.count(&:resource_id_segment?).zero?
240
+ "it contains no ResourceId (e.g. `{foo=*}`) segments"
241
+ elsif path_pattern.segments.count(&:resource_id_segment?) > 1
242
+ "it contains more than one ResourceId (e.g. `{foo=*}`) segments "
243
+ else
244
+ "it contains a multivariate ResourceId segment (e.g. `{foo}~{bar}`)"
245
+ end
246
+
247
+ "A routing header parameter with the path_template #{raw_template}\n " \
248
+ "is invalid: #{reason}"
249
+ end
250
+ end
251
+
252
+ private
253
+
254
+ # All explicit routing parameters in an array.
255
+ # @return [Array<RoutingParameter>]
256
+ def all_explicit_params
257
+ return [] unless explicit_annotation?
258
+ @routing.routing_parameters.each_with_index.map { |param, index| RoutingParameter.new param, index }.to_a
259
+ end
260
+ end
261
+ end
262
+ end
263
+ end
@@ -0,0 +1,181 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2021 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module Gapic
18
+ module Model
19
+ # Aggregated information about the mixin services
20
+ # that should be referenced from their gems in the
21
+ # generated client libraries
22
+ class Mixins
23
+ # LRO might be specified in the mixins but it is not generated
24
+ # as a mixin
25
+ LRO_SERVICE = "google.longrunning.Operations"
26
+
27
+ # Locations and Iam are generated as mixins
28
+ LOCATIONS_SERVICE = "google.cloud.location.Locations"
29
+ IAM_SERVICE = "google.iam.v1.IAMPolicy"
30
+
31
+ # @return [Enumerable<String>] List of services from the Api model
32
+ attr_accessor :api_services
33
+
34
+ ##
35
+ # @param api_services [Enumerable<String>]
36
+ # List of services from the Api model
37
+ # @param service_config [Google::Api::Service]
38
+ # The service config
39
+ def initialize api_services, service_config
40
+ @api_services = api_services
41
+ @service_config = service_config
42
+ end
43
+
44
+ # @return [Boolean] Whether there are any mix-in services
45
+ def mixins?
46
+ mixin_services.any?
47
+ end
48
+
49
+ # @return [Enumerable<Mixin>]
50
+ # List of Mixin objects, providing the information that is needed
51
+ # to add the mixin service references to the generated library
52
+ def mixins
53
+ @mixins ||= mixin_services.map { |service| create_mixin(service) }
54
+ end
55
+
56
+ # @return [Enumerable<String>] Full proto names of the mix-in services
57
+ def mixin_services
58
+ @mixin_services ||= services_in_config.select do |service|
59
+ service != LRO_SERVICE && !@api_services.include?(service)
60
+ end
61
+ end
62
+
63
+ # @return [Hash<String, String>]
64
+ # Aggregated dependencies for the mix-in services
65
+ def dependencies
66
+ @dependencies ||= mixins.reduce({}) { |deps, mixin| deps.merge mixin.dependency }
67
+ end
68
+
69
+ # Model of a single mixin service
70
+ # @!attribute [r] service
71
+ # Full name of the service
72
+ # @return [String]
73
+ # @!attribute [r] dependency
74
+ # Service dependencies, in the
75
+ # `{ gem_name => version pattern }` format
76
+ # @return [Hash<String, String>]
77
+ # @!attribute [r] require_str
78
+ # Path to `require` the client of the service
79
+ # @return [String]
80
+ # @!attribute [r] client_class_name
81
+ # Full name of the class of the client of the service
82
+ # @return [String]
83
+ # @!attribute [r] client_class_docname
84
+ # Name of the class as it should appear in the documentation
85
+ # @return [String]
86
+ # @!attribute [r] client_var_name
87
+ # Name for the variable for the client of the
88
+ # mixin service to use when generating library's service
89
+ # @return [String]
90
+ class Mixin
91
+ attr_reader :service
92
+ attr_reader :dependency
93
+ attr_reader :require_str
94
+ attr_reader :client_class_name
95
+ attr_reader :client_class_docname
96
+ attr_reader :client_var_name
97
+
98
+ # @param service [String]
99
+ # Full name of the service
100
+ # @param dependency [Hash<String, String>]
101
+ # Service dependencies, in the
102
+ # `{ gem_name => version pattern }` format
103
+ # @param require_str [String]
104
+ # Path to require the client of the service
105
+ # @param client_class_name [String]
106
+ # Full name of the class of the client of the service
107
+ # @param client_var_name [String]
108
+ # Name for the variable for the client of the mixin service
109
+ # to use when generating library's service
110
+ def initialize service, dependency, require_str, client_class_name, client_var_name
111
+ @service = service
112
+ @dependency = dependency
113
+ @require_str = require_str
114
+ @client_class_name = client_class_name
115
+ @client_class_docname = client_class_name # For mixins, the doc name should be the full class name
116
+ @client_var_name = client_var_name
117
+ end
118
+
119
+ # @return [String] The description to place in the comments to the
120
+ # mixin's attribute in the library services's client class
121
+ def service_description
122
+ "mix-in of the #{client_class_name.split('::')[-2]}"
123
+ end
124
+ end
125
+
126
+ private
127
+
128
+ # @return [Enumerable<String>] Names of all services that are specified
129
+ # in the Service Config. These include mixin services, as well as
130
+ # some, all, or none of the library's own services
131
+ def services_in_config
132
+ return [] unless @service_config&.apis
133
+ @service_config.apis.map(&:name)
134
+ end
135
+
136
+ # Since mixins are scope-limited to a couple of services, it is easier to
137
+ # have these in lookup tables than to construct a ServicePresenter
138
+
139
+ SERVICE_TO_DEPENDENCY = {
140
+ LOCATIONS_SERVICE => { "google-cloud-location" => "~> 0.1" },
141
+ IAM_SERVICE => { "google-iam-v1" => "~> 0.1" }
142
+ }.freeze
143
+
144
+ SERVICE_TO_REQUIRE_STR = {
145
+ LOCATIONS_SERVICE => "google/cloud/location",
146
+ IAM_SERVICE => "google/iam/v1/iam_policy"
147
+ }.freeze
148
+
149
+ SERVICE_TO_CLIENT_CLASS_NAME = {
150
+ LOCATIONS_SERVICE => "Google::Cloud::Location::Locations::Client",
151
+ IAM_SERVICE => "Google::Iam::V1::IAMPolicy::Client"
152
+ }.freeze
153
+
154
+ SERVICE_TO_CLIENT_ATTR_NAME = {
155
+ LOCATIONS_SERVICE => "location_client",
156
+ IAM_SERVICE => "iam_policy_client"
157
+ }.freeze
158
+
159
+ # @param service [String] full grpc name of the service
160
+ # @raise [ModelError]
161
+ # @return [Mixin]
162
+ def create_mixin service
163
+ unless SERVICE_TO_DEPENDENCY.key?(service) &&
164
+ SERVICE_TO_REQUIRE_STR.key?(service) &&
165
+ SERVICE_TO_CLIENT_CLASS_NAME.key?(service)
166
+ SERVICE_TO_CLIENT_ATTR_NAME.key? service
167
+
168
+ error_text = "A mixin service #{service} is specified in service config, but " \
169
+ "the Generator does not know of it."
170
+ raise ModelError, error_text
171
+ end
172
+
173
+ Mixin.new service,
174
+ SERVICE_TO_DEPENDENCY[service],
175
+ SERVICE_TO_REQUIRE_STR[service],
176
+ SERVICE_TO_CLIENT_CLASS_NAME[service],
177
+ SERVICE_TO_CLIENT_ATTR_NAME[service]
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2021 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module Gapic
18
+ module Model
19
+ ##
20
+ # Represents an error due to inconsistency in the Model
21
+ # that the Generator is attempting to Generate
22
+ #
23
+ class ModelError < StandardError
24
+ end
25
+ end
26
+ end