gapic-generator 0.3.3 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 141fbba25c93dca9ccac5c4a380f7a0f8c1c1643ef2e9517fbb158ba92db822c
4
- data.tar.gz: c61466f199a4d34b6c1fefea9aa8773abc7d9514dfb232385a1e6806e49140f2
3
+ metadata.gz: 6eb09d3958e2bf3212a940df300ab29228dabdb7dabc31b1d9755eddee129c5b
4
+ data.tar.gz: e9431a7bc6f8680553e0bd682d68cdf6ec5fc61a6c564fec5c074f4884d362c9
5
5
  SHA512:
6
- metadata.gz: 1cefa5cb936a4d9f211c0af9f03a9bcbd4ba76f35417cc3a1723164c949dc93b0f9f8be3602ac882d19c2a1109eed7b47150f4be4587ab5d5a368d7942df14f5
7
- data.tar.gz: eab763dd18a81db68af29cc55e54b69f7f8fe504bca56aa93925a66e0c8f548335a4700c0cb89cb13aef65f5de7d640dc8dc0a704190e6a06f7ecdaeb294b065
6
+ metadata.gz: 554bdbb8d1b6ca6dbfb646656cb91dc5f1080d60e8e7103771ca8e3352f09e33a0b9ef3edd86547c173cfc98e18d45da1be8b9648aef40525b1bfb13c5579d62
7
+ data.tar.gz: c998693373a980357d17d540fdbaa891959666bfb2b2dd12b2843eb9b8df0bca1808259305c25614a3951f695b004fa28b862888e1e9e4fa706ce6cfcd2b4f5f
@@ -1,5 +1,14 @@
1
1
  # Release History for gapic-generator
2
2
 
3
+ ### 0.4.0 / 2020-04-20
4
+
5
+ * Support generating clients of "common" interfaces by delegating to another service config.
6
+ * Added an accessor for the long-running-operation client from the main client.
7
+ * Generate tests for the configure method and operations client accessor.
8
+ * Prevent generation of RPC or factory methods with reserved names.
9
+ * Fixed: LRO clients weren't inheriting custom endpoints from the main client.
10
+ * Fixed: Cross-references weren't interpreted if the text included backticks, spaces, or hyphens.
11
+
3
12
  ### 0.3.3 / 2020-04-13
4
13
 
5
14
  * Fix cross-reference links to multi-word enum values.
@@ -22,7 +22,7 @@ module Gapic
22
22
  #
23
23
  module FormattingUtils
24
24
  @brace_detector = /\A(?<pre>[^`]*(`[^`]*`[^`]*)*[^`\\])?\{(?<inside>[^\s][^}]*)\}(?<post>.*)\z/m
25
- @xref_detector = /\A(?<pre>[^`]*(`[^`]*`[^`]*)*)?\[(?<text>[\w\.]+)\]\[(?<addr>[\w\.]+)\](?<post>.*)\z/m
25
+ @xref_detector = /\A(?<pre>[^`]*(`[^`]*`[^`]*)*)?\[(?<text>[\w\. `-]+)\]\[(?<addr>[\w\.]+)\](?<post>.*)\z/m
26
26
  @list_element_detector = /\A\s*(\*|\+|-|[0-9a-zA-Z]+\.)\s/
27
27
 
28
28
  class << self
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Gapic
18
18
  module Generator
19
- VERSION = "0.3.3"
19
+ VERSION = "0.4.0"
20
20
  end
21
21
  end
@@ -16,6 +16,7 @@
16
16
 
17
17
  require "active_support/inflector"
18
18
  require "gapic/path_template"
19
+ require "gapic/ruby_info"
19
20
  require "gapic/helpers/namespace_helper"
20
21
 
21
22
  module Gapic
@@ -36,7 +37,11 @@ module Gapic
36
37
  end
37
38
 
38
39
  def name
39
- ActiveSupport::Inflector.underscore @method.name
40
+ @name ||= begin
41
+ candidate = ActiveSupport::Inflector.underscore @method.name
42
+ candidate = "call_#{candidate}" if Gapic::RubyInfo.excluded_method_names.include? candidate
43
+ candidate
44
+ end
40
45
  end
41
46
 
42
47
  def kind
@@ -53,10 +53,17 @@ module Gapic
53
53
  namespace.split("::").last
54
54
  end
55
55
 
56
+ # Services whose clients should be generated in this package namespace.
56
57
  def services
57
58
  @services ||= begin
58
59
  files = @api.generate_files.select { |f| f.package == @package }
59
- files.map(&:services).flatten.map { |s| ServicePresenter.new @api, s }
60
+ services = files.map(&:services).flatten
61
+ # Omit common services in this package. Common service clients do not
62
+ # go into their own package.
63
+ normal_services = services.select { |s| @api.delegate_service_for(s).nil? }
64
+ # But include common services that delegate to normal services in this package.
65
+ common_services = normal_services.flat_map { |s| @api.common_services_for s }
66
+ (normal_services + common_services).map { |s| ServicePresenter.new @api, s }
60
67
  end
61
68
  end
62
69
 
@@ -55,7 +55,25 @@ module Gapic
55
55
  @service.address
56
56
  end
57
57
 
58
+ # Returns a presenter for this service's delegate (if it is a common service)
59
+ # otherwise returns `nil`.
60
+ def common_service_delegate
61
+ unless defined? @common_service_delegate
62
+ delegate = @api.delegate_service_for @service
63
+ @common_service_delegate = delegate ? ServicePresenter.new(@api, delegate) : nil
64
+ end
65
+ @common_service_delegate
66
+ end
67
+
68
+ # The namespace of the client. Normally this is the version module. This
69
+ # may be different from the proto namespace for a common service.
58
70
  def namespace
71
+ # If this service is a common service, its client should go into its
72
+ # delegate's namespace rather than its own. For example, KMS includes
73
+ # the common IAMPolicy service, but that service's client should go
74
+ # into the KMS namespace.
75
+ return common_service_delegate.namespace if common_service_delegate
76
+
59
77
  return @service.ruby_package if @service.ruby_package.present?
60
78
 
61
79
  namespace = ruby_namespace_for_address @service.address[0...-1]
@@ -74,12 +92,22 @@ module Gapic
74
92
  @service.name
75
93
  end
76
94
 
95
+ # The namespace of the protos. This may be different from the client
96
+ # namespace for a common service.
97
+ def proto_namespace
98
+ return @service.ruby_package if @service.ruby_package.present?
99
+
100
+ namespace = ruby_namespace_for_address @service.address[0...-1]
101
+ @api.override_proto_namespaces? ? fix_namespace(@api, namespace) : namespace
102
+ end
103
+
77
104
  def proto_service_name_full
78
- fix_namespace @api, "#{namespace}::#{name}"
105
+ name_full = "#{proto_namespace}::#{name}"
106
+ @api.override_proto_namespaces? ? fix_namespace(@api, name_full) : name_full
79
107
  end
80
108
 
81
109
  def module_name
82
- proto_service_name_full.split("::").last
110
+ service_name_full.split("::").last
83
111
  end
84
112
 
85
113
  def proto_service_file_path
@@ -110,6 +138,10 @@ module Gapic
110
138
  "#{proto_service_name_full}::Stub"
111
139
  end
112
140
 
141
+ def service_name_full
142
+ fix_namespace @api, "#{namespace}::#{name}"
143
+ end
144
+
113
145
  def service_file_path
114
146
  service_require + ".rb"
115
147
  end
@@ -123,7 +155,7 @@ module Gapic
123
155
  end
124
156
 
125
157
  def service_require
126
- ruby_file_path @api, proto_service_name_full
158
+ ruby_file_path @api, service_name_full
127
159
  end
128
160
 
129
161
  def client_name
@@ -131,7 +163,7 @@ module Gapic
131
163
  end
132
164
 
133
165
  def client_name_full
134
- fix_namespace @api, "#{proto_service_name_full}::#{client_name}"
166
+ fix_namespace @api, "#{service_name_full}::#{client_name}"
135
167
  end
136
168
 
137
169
  def create_client_call
@@ -155,12 +187,17 @@ module Gapic
155
187
  end
156
188
 
157
189
  def client_endpoint
158
- return @parent_service.client_endpoint if @parent_service
159
- @service.host || default_config(:default_host) || "localhost"
190
+ @parent_service&.client_endpoint ||
191
+ common_service_delegate&.client_endpoint ||
192
+ @service.host ||
193
+ default_config(:default_host) ||
194
+ "localhost"
160
195
  end
161
196
 
162
197
  def client_scopes
163
- @service.scopes || default_config(:oauth_scopes)
198
+ common_service_delegate&.client_scopes ||
199
+ @service.scopes ||
200
+ default_config(:oauth_scopes)
164
201
  end
165
202
 
166
203
  def client_proto_name
@@ -172,7 +209,7 @@ module Gapic
172
209
  end
173
210
 
174
211
  def credentials_name_full
175
- fix_namespace @api, "#{proto_service_name_full}::#{credentials_name}"
212
+ fix_namespace @api, "#{service_name_full}::#{credentials_name}"
176
213
  end
177
214
 
178
215
  def credentials_class_xref
@@ -200,7 +237,7 @@ module Gapic
200
237
  end
201
238
 
202
239
  def helpers_require
203
- ruby_file_path @api, "#{proto_service_name_full}::Helpers"
240
+ ruby_file_path @api, "#{service_name_full}::Helpers"
204
241
  end
205
242
 
206
243
  def references
@@ -216,7 +253,7 @@ module Gapic
216
253
  end
217
254
 
218
255
  def paths_name_full
219
- fix_namespace @api, "#{proto_service_name_full}::#{paths_name}"
256
+ fix_namespace @api, "#{service_name_full}::#{paths_name}"
220
257
  end
221
258
 
222
259
  def paths_file_path
@@ -228,7 +265,7 @@ module Gapic
228
265
  end
229
266
 
230
267
  def paths_require
231
- ruby_file_path @api, "#{proto_service_name_full}::#{paths_name}"
268
+ ruby_file_path @api, "#{service_name_full}::#{paths_name}"
232
269
  end
233
270
 
234
271
  def test_client_file_path
@@ -260,7 +297,7 @@ module Gapic
260
297
  end
261
298
 
262
299
  def operations_name_full
263
- fix_namespace @api, "#{proto_service_name_full}::#{operations_name}"
300
+ fix_namespace @api, "#{service_name_full}::#{operations_name}"
264
301
  end
265
302
 
266
303
  def operations_file_path
@@ -272,7 +309,7 @@ module Gapic
272
309
  end
273
310
 
274
311
  def operations_require
275
- ruby_file_path @api, "#{proto_service_name_full}::#{operations_name}"
312
+ ruby_file_path @api, "#{service_name_full}::#{operations_name}"
276
313
  end
277
314
 
278
315
  def lro_service
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2020 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
+ ##
19
+ # Various Ruby language information useful for generators.
20
+ #
21
+ module RubyInfo
22
+ class << self
23
+ ##
24
+ # A sorted list of Ruby's keywords.
25
+ #
26
+ # @see https://docs.ruby-lang.org/en/2.7.0/keywords_rdoc.html
27
+ #
28
+ # @return [Array<String>]
29
+ #
30
+ def keywords
31
+ @keywords ||= [
32
+ "__ENCODING__",
33
+ "__LINE__",
34
+ "__FILE__",
35
+ "BEGIN",
36
+ "END",
37
+ "alias",
38
+ "and",
39
+ "begin",
40
+ "break",
41
+ "case",
42
+ "class",
43
+ "def",
44
+ "defined?",
45
+ "do",
46
+ "else",
47
+ "elsif",
48
+ "end",
49
+ "ensure",
50
+ "false",
51
+ "for",
52
+ "if",
53
+ "in",
54
+ "module",
55
+ "next",
56
+ "nil",
57
+ "not",
58
+ "or",
59
+ "redo",
60
+ "rescue",
61
+ "retry",
62
+ "return",
63
+ "self",
64
+ "super",
65
+ "then",
66
+ "true",
67
+ "undef",
68
+ "unless",
69
+ "until",
70
+ "when",
71
+ "while",
72
+ "yield"
73
+ ].freeze
74
+ end
75
+
76
+ ##
77
+ # A sorted list of method names that generated code should avoid.
78
+ # This includes methods of the Object class (including BasicObject and
79
+ # Kernel), Ruby keywords, and a few special names including "initialize"
80
+ # and "configure".
81
+ #
82
+ # @return [Array<String>]
83
+ #
84
+ def excluded_method_names
85
+ @excluded_method_names ||= begin
86
+ object_methods = (Object.instance_methods + Object.private_instance_methods).map(&:to_s)
87
+ other_methods = ["configure", "initialize"]
88
+ (object_methods + other_methods + keywords).sort.freeze
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -202,7 +202,7 @@ module Gapic
202
202
  config = config_file ? YAML.load_file(config_file) : {}
203
203
  protoc_options.each do |k, v|
204
204
  next if k == "configuration"
205
- branch = key_to_str(k).split(".").reverse.inject(v) { |m, s| { str_to_key(s) => m } }
205
+ branch = parse_key(key_to_str(k)).reverse.inject(v) { |m, s| { str_to_key(s) => m } }
206
206
  config = deep_merge config, branch
207
207
  end
208
208
  config
@@ -225,6 +225,21 @@ module Gapic
225
225
  configuration[:generate_path_helpers_output] ||= false
226
226
  end
227
227
 
228
+ # Whether the override_proto_namespaces parameter was given in the configuration
229
+ def override_proto_namespaces_defined?
230
+ configuration.key? :override_proto_namespaces
231
+ end
232
+
233
+ # Sets the override_proto_namespaces parameter in the configuration
234
+ def override_proto_namespaces= value
235
+ configuration[:override_proto_namespaces] = value
236
+ end
237
+
238
+ # Whether namespace overrides apply to proto/grpc class references
239
+ def override_proto_namespaces?
240
+ configuration[:override_proto_namespaces] ||= false
241
+ end
242
+
228
243
  # Raw parsed json of the combined grpc service config files if provided
229
244
  # or an empty hash if no config was provided
230
245
  def grpc_service_config_raw
@@ -249,6 +264,28 @@ module Gapic
249
264
  @resource_types[resource_type]
250
265
  end
251
266
 
267
+ # Given a service, find all common services that use it as a delegate.
268
+ def common_services_for delegate
269
+ @delegate_to_common ||= begin
270
+ (configuration[:common_services] || {}).each_with_object({}) do |(c, d), mapping|
271
+ (mapping[d] ||= []) << c
272
+ end
273
+ end
274
+ all_services = services
275
+ @delegate_to_common.fetch(delegate.address.join("."), []).map do |addr|
276
+ addr = addr.split "."
277
+ all_services.find { |s| s.address == addr }
278
+ end.compact.uniq
279
+ end
280
+
281
+ # Given a common service, return its delegate.
282
+ def delegate_service_for common
283
+ addr = (configuration[:common_services] || {})[common.address.join "."]
284
+ return nil unless addr
285
+ addr = addr.split "."
286
+ services.find { |s| s.address == addr }
287
+ end
288
+
252
289
  private
253
290
 
254
291
  # Does a pre-analysis of all resources defined in the job. This has
@@ -291,6 +328,8 @@ module Gapic
291
328
  end
292
329
  end
293
330
 
331
+ # Parse a comma-delimited list of equals-delimited lists of strings, while
332
+ # mapping backslash-escaped commas and equal signs to literal characters.
294
333
  def parse_parameter str
295
334
  str.scan(/\\.|,|=|[^\\,=]+/)
296
335
  .each_with_object([[String.new]]) do |tok, arr|
@@ -307,6 +346,22 @@ module Gapic
307
346
  end
308
347
  end
309
348
 
349
+ # split the string on periods, but map backslash-escaped periods to
350
+ # literal periods.
351
+ def parse_key str
352
+ str.scan(/\.|\\.|[^\.\\]+/)
353
+ .each_with_object([String.new]) do |tok, arr|
354
+ if tok == "."
355
+ arr.append String.new
356
+ elsif tok.start_with? "\\"
357
+ arr.last << tok[1]
358
+ else
359
+ arr.last << tok
360
+ end
361
+ arr
362
+ end
363
+ end
364
+
310
365
  def str_to_key str
311
366
  str = str.to_s
312
367
  str.start_with?(":") ? str[1..-1].to_sym : str
@@ -2,5 +2,5 @@
2
2
  <%= render partial: "service/client/client",
3
3
  layout: "layouts/ruby",
4
4
  locals: { service: service,
5
- namespace: service.proto_service_name_full }
5
+ namespace: service.service_name_full }
6
6
  %>
@@ -105,6 +105,7 @@ class <%= service.client_name %>
105
105
  <%- if service.lro? -%>
106
106
  <%= service.lro_client_ivar %> = <%= service.operations_name %>.new do |config|
107
107
  config.credentials = credentials
108
+ config.endpoint = @config.endpoint
108
109
  end
109
110
 
110
111
  <%- end -%>
@@ -117,6 +118,15 @@ class <%= service.client_name %>
117
118
  )
118
119
  end
119
120
 
121
+ <%- if service.lro? -%>
122
+ ##
123
+ # Get the associated client for long-running operations.
124
+ #
125
+ # @return [<%= service.operations_name_full %>]
126
+ #
127
+ attr_reader :<%= service.lro_client_var %>
128
+
129
+ <%- end -%>
120
130
  # Service calls
121
131
  <%- service.methods.each do |method| -%>
122
132
 
@@ -2,5 +2,5 @@
2
2
  <%= render partial: "service/client/credentials",
3
3
  layout: "layouts/ruby",
4
4
  locals: { service: service,
5
- namespace: service.proto_service_name_full }
5
+ namespace: service.service_name_full }
6
6
  %>
@@ -2,5 +2,5 @@
2
2
  <%= render partial: "service/client/operations",
3
3
  layout: "layouts/ruby",
4
4
  locals: { service: service,
5
- namespace: service.proto_service_name_full }
5
+ namespace: service.service_name_full }
6
6
  %>
@@ -2,5 +2,5 @@
2
2
  <%= render partial: "service/client/paths",
3
3
  layout: "layouts/ruby",
4
4
  locals: { service: service,
5
- namespace: service.proto_service_name_full }
5
+ namespace: service.service_name_full }
6
6
  %>
@@ -17,8 +17,22 @@ class <%= service.client_name_full %>Test < Minitest::Test
17
17
  <% service.methods.each do |method| %>
18
18
  <%= indent render(partial: "service/test/method/#{method.kind}",
19
19
  locals: { method: method }), 2 %>
20
- <% if method != service.methods.last %>
21
20
 
22
21
  <% end %>
23
- <% end %>
22
+ <%= indent render(partial: "service/test/method/configure", locals: { service: service }), 2 %>
23
+ <%- if service.lro? -%>
24
+
25
+ def test_<%= service.lro_client_var %>
26
+ grpc_channel = GRPC::Core::Channel.new "localhost:8888", nil, :this_channel_is_insecure
27
+
28
+ client = nil
29
+ Gapic::ServiceStub.stub :new, nil do
30
+ client = <%= service.client_name_full =%>.new do |config|
31
+ config.credentials = grpc_channel
32
+ end
33
+ end
34
+
35
+ assert_kind_of <%= service.operations_name_full %>, client.<%= service.lro_client_var %>
36
+ end
37
+ <%- end -%>
24
38
  end
@@ -17,8 +17,8 @@ class <%= service.operations_name_full %>Test < Minitest::Test
17
17
  <% service.lro_service.methods.each do |method| %>
18
18
  <%= indent render(partial: "service/test/method/#{method.kind}",
19
19
  locals: { client_name_full: service.operations_name_full, method: method }), 2 %>
20
- <% if method != service.lro_service.methods.last %>
21
20
 
22
21
  <% end %>
23
- <% end %>
22
+ <%= indent render(partial: "service/test/method/configure",
23
+ locals: { service: service, client_name_full: service.operations_name_full }), 2 %>
24
24
  end
@@ -0,0 +1,19 @@
1
+ <%- assert_locals service -%>
2
+ <%- full_client_name = defined?(client_name_full) ? client_name_full : service.client_name_full -%>
3
+ def test_configure
4
+ grpc_channel = GRPC::Core::Channel.new "localhost:8888", nil, :this_channel_is_insecure
5
+
6
+ client = block_config = config = nil
7
+ Gapic::ServiceStub.stub :new, nil do
8
+ client = <%= full_client_name =%>.new do |config|
9
+ config.credentials = grpc_channel
10
+ end
11
+ end
12
+
13
+ config = client.configure do |c|
14
+ block_config = c
15
+ end
16
+
17
+ assert_same block_config, config
18
+ assert_kind_of <%= full_client_name %>::Configuration, config
19
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gapic-generator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ernest Landrito
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-04-13 00:00:00.000000000 Z
13
+ date: 2020-04-20 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: actionpack
@@ -233,6 +233,7 @@ files:
233
233
  - lib/gapic/presenters/sample_presenter.rb
234
234
  - lib/gapic/presenters/service_presenter.rb
235
235
  - lib/gapic/resource_lookup.rb
236
+ - lib/gapic/ruby_info.rb
236
237
  - lib/gapic/runner.rb
237
238
  - lib/gapic/schema.rb
238
239
  - lib/gapic/schema/api.rb
@@ -323,6 +324,7 @@ files:
323
324
  - templates/default/service/test/method/_assert_response.erb
324
325
  - templates/default/service/test/method/_bidi.erb
325
326
  - templates/default/service/test/method/_client.erb
327
+ - templates/default/service/test/method/_configure.erb
326
328
  - templates/default/service/test/method/_normal.erb
327
329
  - templates/default/service/test/method/_server.erb
328
330
  - templates/default/service/test/method/_setup.erb