kruby 1.36.0.2 → 1.36.0.4

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: c0339eb1cc8a6f1d7402b0f089dca4cdd7fd20c0b0f0a049cec2b3fcd0a78276
4
- data.tar.gz: 3416b24a60f29e7715a9ff45a1f542dbc83c325c988c51e9c288e6a618403f85
3
+ metadata.gz: a427ec5d2c6e70a8edf267a9095e38b988bfef3501dc420145de416fd8aea1aa
4
+ data.tar.gz: 6ddad098a7d16fde73bf1861b2aa4c1b4dd7559821b4d238bd58474a28bc1a99
5
5
  SHA512:
6
- metadata.gz: 4d3b65bb69cb397cb29704318d5359d570aa55113c7e45e99930b11606628c301e08404671373f35bdb0bfb9e64e67399ea682f770f4900fb73e82c559c41b98
7
- data.tar.gz: bc2755b8608df879b0b5abffafb0255096abdde11d2a37d3e689e97d1113fa4c12818016c617b74308f3953f38aac989e2bae3cd6a732c9d59a11b5d3a100e3a
6
+ metadata.gz: 1ddbe0af5eaa1ae160af1e07d7c9b54209dd064fc20362a81e93b8f709ba01feb6f4835995652db3984d27b46501cf029a3b9dfbc87252175638392f40feb761
7
+ data.tar.gz: 5959a6ec6db11ae3e323f6759add33c9c9a57cde7d1f5727c37138f2603129b2814ec5e803fe015289e9d60be2c551e135ce58353c380cf27e310e1b0ed4ab59
@@ -15,10 +15,13 @@ require 'json'
15
15
  require 'logger'
16
16
  require 'tempfile'
17
17
  require 'time'
18
+ require 'thread'
18
19
  require 'typhoeus'
19
20
 
20
21
  module Kubernetes
21
22
  class ApiClient
23
+ @default_mutex = Mutex.new
24
+
22
25
  # The Configuration object holding settings to be used in the API client.
23
26
  attr_accessor :config
24
27
 
@@ -39,7 +42,17 @@ module Kubernetes
39
42
  end
40
43
 
41
44
  def self.default
42
- @@default ||= ApiClient.new
45
+ return @@default if defined?(@@default) && @@default
46
+
47
+ @default_mutex.synchronize do
48
+ @@default ||= ApiClient.new
49
+ end
50
+ end
51
+
52
+ def self.reset_default
53
+ @default_mutex.synchronize do
54
+ @@default = nil
55
+ end
43
56
  end
44
57
 
45
58
  # Call an API with given options.
@@ -47,34 +60,43 @@ module Kubernetes
47
60
  # @return [Array<(Object, Integer, Hash)>] an array of 3 elements:
48
61
  # the data deserialized from response body (could be nil), response status code and response headers.
49
62
  def call_api(http_method, path, opts = {})
50
- request = build_request(http_method, path, opts)
51
- response = request.run
63
+ retries_performed = 0
52
64
 
53
- if @config.debugging
54
- @config.logger.debug "HTTP response body ~BEGIN~\n#{response.body}\n~END~\n"
55
- end
65
+ loop do
66
+ request = build_request(http_method, path, opts)
67
+ response = request.run
56
68
 
57
- unless response.success?
58
- if response.timed_out?
59
- fail ApiError.new('Connection timed out')
60
- elsif response.code == 0
61
- # Errors from libcurl will be made visible here
62
- fail ApiError.new(:code => 0,
63
- :message => response.return_message)
64
- else
65
- fail ApiError.new(:code => response.code,
66
- :response_headers => response.headers,
67
- :response_body => response.body),
68
- response.status_message
69
+ if @config.debugging
70
+ @config.logger.debug "HTTP response body ~BEGIN~\n#{response.body}\n~END~\n"
69
71
  end
70
- end
71
72
 
72
- if opts[:return_type]
73
- data = deserialize(response, opts[:return_type])
74
- else
75
- data = nil
73
+ unless response.success?
74
+ if retry_request?(response, retries_performed)
75
+ interval_seconds = retry_interval_seconds(response, retries_performed)
76
+ log_retry_attempt(response, retries_performed + 1, interval_seconds)
77
+ sleep interval_seconds
78
+ retries_performed += 1
79
+ next
80
+ end
81
+
82
+ if response.timed_out?
83
+ fail ApiError.new(:code => 0,
84
+ :message => 'Connection timed out')
85
+ elsif response.code == 0
86
+ # Errors from libcurl will be made visible here
87
+ fail ApiError.new(:code => 0,
88
+ :message => response.return_message)
89
+ else
90
+ fail ApiError.new(:code => response.code,
91
+ :response_headers => response.headers,
92
+ :response_body => response.body),
93
+ response.status_message
94
+ end
95
+ end
96
+
97
+ data = opts[:return_type] ? deserialize(response, opts[:return_type]) : nil
98
+ return data, response.code, response.headers
76
99
  end
77
- return data, response.code, response.headers
78
100
  end
79
101
 
80
102
  # Builds the HTTP request
@@ -225,7 +247,12 @@ module Kubernetes
225
247
  # ensuring a default content type
226
248
  content_type = response.headers['Content-Type'] || 'application/json'
227
249
 
228
- fail "Content-Type is not supported: #{content_type}" unless json_mime?(content_type)
250
+ unless json_mime?(content_type)
251
+ fail ApiError.new(:code => response.code,
252
+ :response_headers => response.headers,
253
+ :response_body => body,
254
+ :message => "Content-Type is not supported: #{content_type}")
255
+ end
229
256
 
230
257
  begin
231
258
  data = JSON.parse("[#{body}]", :symbolize_names => true)[0]
@@ -399,5 +426,85 @@ module Kubernetes
399
426
  fail "unknown collection format: #{collection_format.inspect}"
400
427
  end
401
428
  end
429
+
430
+ def retry_request?(response, retries_performed)
431
+ return false if response.timed_out?
432
+ return false if response.code.to_i == 0
433
+ return false if max_retry_attempts <= 0
434
+ return false if retries_performed >= max_retry_attempts
435
+
436
+ retry_statuses.include?(response.code.to_i)
437
+ end
438
+
439
+ def retry_interval_seconds(response, retries_performed)
440
+ exponential_interval = retry_base_interval_seconds * (2**retries_performed)
441
+ server_interval = server_retry_after_seconds(response)
442
+
443
+ server_interval ? [exponential_interval, server_interval].max : exponential_interval
444
+ end
445
+
446
+ def log_retry_attempt(response, retry_number, interval_seconds)
447
+ @config.logger.info(
448
+ "Retrying API request after HTTP #{response.code} (retry #{retry_number}/#{max_retry_attempts}) in #{interval_seconds} seconds"
449
+ )
450
+ return unless @config.debugging
451
+
452
+ @config.logger.debug("Retry response body: #{response.body}")
453
+ end
454
+
455
+ def max_retry_attempts
456
+ value = fetch_retry_configuration(:max_retries, 0)
457
+ [value.to_i, 0].max
458
+ end
459
+
460
+ def retry_base_interval_seconds
461
+ [fetch_retry_configuration(:base_interval_seconds, 1.0).to_f, 0.0].max
462
+ end
463
+
464
+ def retry_statuses
465
+ Array(fetch_retry_configuration(:retry_statuses, [429, 500, 501, 502, 503])).map(&:to_i)
466
+ end
467
+
468
+ def server_retry_after_seconds(response)
469
+ header_value = response.headers['Retry-After'] if response.respond_to?(:headers) && response.headers.is_a?(Hash)
470
+ header_seconds = parse_retry_after_header(header_value)
471
+ return header_seconds if header_seconds
472
+
473
+ parse_retry_after_from_body(response.body)
474
+ end
475
+
476
+ def parse_retry_after_header(header_value)
477
+ return nil if header_value.nil?
478
+
479
+ integer_value = Integer(header_value, exception: false)
480
+ return integer_value.to_f if integer_value
481
+
482
+ retry_at = Time.httpdate(header_value)
483
+ [retry_at - Time.now, 0.0].max
484
+ rescue ArgumentError
485
+ nil
486
+ end
487
+
488
+ def parse_retry_after_from_body(body)
489
+ return nil if body.nil? || body.empty?
490
+
491
+ parsed = JSON.parse(body)
492
+ retry_after = parsed.dig('details', 'retryAfterSeconds') || parsed.dig(:details, :retryAfterSeconds)
493
+ return nil if retry_after.nil?
494
+
495
+ retry_after.to_f
496
+ rescue JSON::ParserError, TypeError
497
+ nil
498
+ end
499
+
500
+ def fetch_retry_configuration(key, default)
501
+ return default unless @config.retry_configuration.is_a?(Hash)
502
+
503
+ if @config.retry_configuration.key?(key)
504
+ @config.retry_configuration[key]
505
+ else
506
+ @config.retry_configuration.fetch(key.to_s, default)
507
+ end
508
+ end
402
509
  end
403
510
  end
@@ -90,13 +90,13 @@ module Kubernetes
90
90
  Configuration.instance_variable_set(:@in_cluster_config, self)
91
91
  Configuration.prepend(Module.new do
92
92
  # rubocop:disable Metrics/LineLength
93
- def api_key_with_prefix(identifier)
93
+ def api_key_with_prefix(identifier, param_alias = nil)
94
94
  in_cluster_config = self.class.instance_variable_get(:@in_cluster_config)
95
95
  if identifier == 'authorization' && @api_key.key?(identifier) && in_cluster_config.token_expires_at <= Time.now
96
96
  in_cluster_config.load_token
97
97
  @api_key[identifier] = 'Bearer ' + in_cluster_config.token
98
98
  end
99
- super identifier
99
+ super identifier, param_alias
100
100
  end
101
101
  # rubocop:enable Metrics/LineLength
102
102
  end)
@@ -49,6 +49,13 @@ module Kubernetes
49
49
  File.dirname(path)
50
50
  end
51
51
 
52
+ def resolve_path(file_path)
53
+ return file_path unless file_path
54
+ file_path = file_path.to_s
55
+ return file_path if file_path.start_with?('/')
56
+ File.expand_path(file_path, File.expand_path(base_path))
57
+ end
58
+
52
59
  def config
53
60
  @config ||= File.open(path) do |io|
54
61
  ::YAML.safe_load(io.read)
@@ -86,8 +93,8 @@ module Kubernetes
86
93
 
87
94
  def setup_ssl(cluster, user, config)
88
95
  # rubocop:disable DoubleNegation
89
- config.verify_ssl = !!cluster['verify-ssl']
90
- config.verify_ssl_host = !!cluster['verify-ssl']
96
+ config.verify_ssl = !!cluster['verify_ssl']
97
+ config.verify_ssl_host = !!cluster['verify_ssl']
91
98
  # rubocop:enable DoubleNegation
92
99
 
93
100
  config.ssl_ca_cert = cluster['certificate-authority']
@@ -98,6 +105,7 @@ module Kubernetes
98
105
  def find_cluster(name)
99
106
  find_by_name(config['clusters'], 'cluster', name).tap do |cluster|
100
107
  Kubernetes.create_temp_file_and_set(cluster, 'certificate-authority')
108
+ cluster['certificate-authority'] = resolve_path(cluster['certificate-authority'])
101
109
  cluster['verify_ssl'] = !cluster['insecure-skip-tls-verify']
102
110
  end
103
111
  end
@@ -108,6 +116,8 @@ module Kubernetes
108
116
 
109
117
  Kubernetes.create_temp_file_and_set(user, 'client-certificate')
110
118
  Kubernetes.create_temp_file_and_set(user, 'client-key')
119
+ user['client-certificate'] = resolve_path(user['client-certificate'])
120
+ user['client-key'] = resolve_path(user['client-key'])
111
121
  load_token_file(user)
112
122
  setup_auth(user)
113
123
  end
@@ -117,6 +127,7 @@ module Kubernetes
117
127
  # If tokenFile is specified, then set token
118
128
  return unless !user['token'] && user['tokenFile']
119
129
 
130
+ user['tokenFile'] = resolve_path(user['tokenFile'])
120
131
  File.open(user['tokenFile']) do |io|
121
132
  user['token'] = io.read.chomp
122
133
  end
@@ -11,9 +11,12 @@ OpenAPI Generator version: 5.1.0
11
11
  =end
12
12
 
13
13
  require 'logger'
14
+ require 'thread'
14
15
 
15
16
  module Kubernetes
16
17
  class Configuration
18
+ @default_mutex = Mutex.new
19
+
17
20
  # Defines url scheme
18
21
  attr_accessor :scheme
19
22
 
@@ -88,6 +91,11 @@ module Kubernetes
88
91
  # Default to 0 (never times out).
89
92
  attr_accessor :timeout
90
93
 
94
+ # Optional retry configuration for retriable HTTP responses.
95
+ # Example:
96
+ # { max_retries: 4, base_interval_seconds: 1.0, retry_statuses: [429, 500, 501, 502, 503] }
97
+ attr_accessor :retry_configuration
98
+
91
99
  # Set this to false to skip client side validation in the operation.
92
100
  # Default to true.
93
101
  # @return [true, false]
@@ -150,6 +158,7 @@ module Kubernetes
150
158
  @api_key = {}
151
159
  @api_key_prefix = {}
152
160
  @timeout = 0
161
+ @retry_configuration = nil
153
162
  @client_side_validation = true
154
163
  @verify_ssl = true
155
164
  @verify_ssl_host = true
@@ -166,7 +175,17 @@ module Kubernetes
166
175
 
167
176
  # The default Configuration object.
168
177
  def self.default
169
- @@default ||= Configuration.new
178
+ return @@default if defined?(@@default) && @@default
179
+
180
+ @default_mutex.synchronize do
181
+ @@default ||= Configuration.new
182
+ end
183
+ end
184
+
185
+ def self.reset_default
186
+ @default_mutex.synchronize do
187
+ @@default = nil
188
+ end
170
189
  end
171
190
 
172
191
  # Backward-compatible alias used by examples and older integrations.
@@ -260,21 +279,30 @@ module Kubernetes
260
279
  end
261
280
 
262
281
  server = servers[index]
263
- url = server[:url]
282
+ url = server[:url].dup
264
283
 
265
284
  return url unless server.key? :variables
266
285
 
267
286
  # go through variable and assign a value
268
287
  server[:variables].each do |name, variable|
269
- if variables.key?(name)
270
- if (!server[:variables][name].key?(:enum_values) || server[:variables][name][:enum_values].include?(variables[name]))
271
- url.gsub! "{" + name.to_s + "}", variables[name]
288
+ variable_key = if variables.key?(name)
289
+ name
290
+ elsif variables.key?(name.to_s)
291
+ name.to_s
292
+ elsif name.respond_to?(:to_sym) && variables.key?(name.to_sym)
293
+ name.to_sym
294
+ end
295
+
296
+ if variable_key
297
+ variable_value = variables[variable_key]
298
+ if (!variable.key?(:enum_values) || variable[:enum_values].include?(variable_value))
299
+ url.gsub! "{" + name.to_s + "}", variable_value
272
300
  else
273
- fail ArgumentError, "The variable `#{name}` in the server URL has invalid value #{variables[name]}. Must be #{server[:variables][name][:enum_values]}."
301
+ fail ArgumentError, "The variable `#{name}` in the server URL has invalid value #{variable_value}. Must be #{variable[:enum_values]}."
274
302
  end
275
303
  else
276
304
  # use default value
277
- url.gsub! "{" + name.to_s + "}", server[:variables][name][:default_value]
305
+ url.gsub! "{" + name.to_s + "}", variable[:default_value]
278
306
  end
279
307
  end
280
308
 
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+ require "rubygems/specification"
5
+ require "shellwords"
6
+ require "kubernetes/release/changelog"
7
+
8
+ module Kubernetes
9
+ module Release
10
+ module PublishGuard
11
+ module_function
12
+
13
+ def gemspec_files(gemspec_path)
14
+ spec = Gem::Specification.load(gemspec_path)
15
+ raise Changelog::Error, "failed to load gemspec #{gemspec_path}" unless spec
16
+
17
+ spec.files
18
+ rescue Gem::InvalidSpecificationException => e
19
+ raise Changelog::Error, e.message
20
+ end
21
+
22
+ def untracked_package_files(repo_root:, package_root:, package_files:)
23
+ repo_paths = package_files.map do |path|
24
+ package_file_repo_path(repo_root: repo_root, package_root: package_root, package_path: path)
25
+ end.uniq.sort
26
+ return [] if repo_paths.empty?
27
+
28
+ tracked_paths = capture_command("git", "-C", repo_root, "ls-files", "--", *repo_paths).lines.map(&:chomp)
29
+ repo_paths - tracked_paths
30
+ end
31
+
32
+ def untracked_gemspec_files(repo_root:, package_root:, gemspec_path:)
33
+ untracked_package_files(
34
+ repo_root: repo_root,
35
+ package_root: package_root,
36
+ package_files: gemspec_files(gemspec_path)
37
+ )
38
+ end
39
+
40
+ def package_file_repo_path(repo_root:, package_root:, package_path:)
41
+ repo_root = File.expand_path(repo_root)
42
+ repo_prefix = "#{repo_root}#{File::SEPARATOR}"
43
+ full_path = File.expand_path(package_path, package_root)
44
+
45
+ unless full_path.start_with?(repo_prefix)
46
+ raise Changelog::Error, "gem package file #{package_path} resolves outside #{repo_root}"
47
+ end
48
+
49
+ full_path.delete_prefix(repo_prefix)
50
+ end
51
+
52
+ def capture_command(*command)
53
+ output, status = Open3.capture2e(*command)
54
+ return output if status.success?
55
+
56
+ message = "command failed: #{Shellwords.join(command)}"
57
+ details = output.strip
58
+ message = "#{message}\n#{details}" unless details.empty?
59
+ raise Changelog::Error, message
60
+ end
61
+ end
62
+ end
63
+ end
@@ -15,6 +15,7 @@
15
15
  require 'kubernetes/config/incluster_config'
16
16
  require 'kubernetes/config/kube_config'
17
17
  require 'rubygems/version'
18
+ require 'thread'
18
19
 
19
20
  # The Kubernetes module encapsulates the Kubernetes client for Ruby
20
21
  module Kubernetes
@@ -73,18 +74,22 @@ module Kubernetes
73
74
  end
74
75
 
75
76
  @temp_files = {}
77
+ @temp_files_mutex = Mutex.new
76
78
 
77
79
  def create_temp_file_with_base64content(content)
78
- @temp_files[content] ||= Tempfile.open('kube') do |temp|
79
- temp.write(Base64.strict_decode64(content))
80
- temp
80
+ @temp_files_mutex.synchronize do
81
+ @temp_files[content] ||= Tempfile.open('kube') do |temp|
82
+ temp.write(Base64.strict_decode64(content))
83
+ temp
84
+ end
85
+ @temp_files.fetch(content).path
81
86
  end
82
-
83
- @temp_files[content].path
84
87
  end
85
88
 
86
89
  def clear_temp_files
87
- @temp_files = {}
90
+ @temp_files_mutex.synchronize do
91
+ @temp_files = {}
92
+ end
88
93
  end
89
94
 
90
95
  SUPPORTED_KUBERNETES_VERSION_RANGE = (
@@ -11,5 +11,5 @@ OpenAPI Generator version: 5.1.0
11
11
  =end
12
12
 
13
13
  module Kubernetes
14
- VERSION = '1.36.0.2'
14
+ VERSION = '1.36.0.4'
15
15
  end
@@ -13,41 +13,74 @@
13
13
  # limitations under the License.
14
14
 
15
15
  require 'json'
16
+ require 'uri'
16
17
 
17
18
  # The Kubernetes module encapsulates the Kubernetes client for Ruby
18
19
  module Kubernetes
19
20
  # The Watch class provides the ability to watch a specific resource for
20
21
  # updates.
21
22
  class Watch
23
+ MAX_RECONNECT_ATTEMPTS = 3
24
+ RECONNECT_BACKOFF_SECONDS = 1.0
25
+
22
26
  def initialize(client)
23
27
  @client = client
24
28
  end
25
29
 
26
30
  def make_url(path, resource_version)
27
- query = '?watch=true'
28
- query += "&resourceVersion=#{resource_version}" if resource_version
29
- path + query
31
+ uri = URI.parse(path)
32
+ query = URI.decode_www_form(uri.query || '').to_h
33
+ query['watch'] = 'true'
34
+ query['resourceVersion'] = resource_version if resource_version
35
+ query_string = query.map { |k, v| "#{URI.encode_www_form_component(k).gsub('+', '%20')}=#{URI.encode_www_form_component(v).gsub('+', '%20')}" }.join('&')
36
+ "#{uri.path}?#{query_string}"
30
37
  end
31
38
 
32
39
  def connect(path, resource_version = nil, &_block)
33
- opts = { auth_names: ['BearerToken'] }
34
- url = make_url(path, resource_version)
35
- request = @client.build_request('GET', url, opts)
36
- last = ''
37
- request.on_body do |chunk|
38
- last, pieces = split_lines(last, chunk)
39
- pieces.each do |part|
40
- begin
41
- event = JSON.parse(part)
42
- rescue JSON::ParserError => e
43
- warn "Failed to parse watch event: #{e.message}. Raw event: #{part.inspect}"
40
+ current_resource_version = resource_version
41
+ reconnect_attempts = 0
42
+
43
+ loop do
44
+ reconnect_requested = false
45
+ opts = { auth_names: ['BearerToken'] }
46
+ url = make_url(path, current_resource_version)
47
+ request = @client.build_request('GET', url, opts)
48
+ last = ''
49
+
50
+ process_event = lambda do |part|
51
+ return if part.nil? || part.strip.empty?
52
+
53
+ event = parse_event(part)
54
+ return unless event
55
+
56
+ if watch_reset_event?(event)
57
+ current_resource_version = nil
58
+ reconnect_requested = true
44
59
  next
45
60
  end
46
61
 
62
+ current_resource_version = extract_resource_version(event) || current_resource_version
47
63
  yield event
48
64
  end
65
+
66
+ request.on_body do |chunk|
67
+ last, pieces = split_lines(last, chunk)
68
+ pieces.each { |part| process_event.call(part) }
69
+ end
70
+
71
+ request.on_complete do |_response|
72
+ process_event.call(last)
73
+ last = ''
74
+ end
75
+
76
+ response = request.run
77
+ reconnect_reason = reconnect_reason(response, reconnect_requested)
78
+ return response unless reconnect_reason
79
+ raise_terminal_watch_error(response, reconnect_reason) if reconnect_attempts >= MAX_RECONNECT_ATTEMPTS
80
+
81
+ reconnect_attempts += 1
82
+ sleep reconnect_backoff_seconds(reconnect_attempts - 1) if reconnect_reason == :transport
49
83
  end
50
- request.run
51
84
  end
52
85
 
53
86
  def split_lines(last, chunk)
@@ -61,5 +94,51 @@ module Kubernetes
61
94
  last = data[(ix + 1)..data.length]
62
95
  [last, complete.split(/\n/)]
63
96
  end
97
+
98
+ private
99
+
100
+ def parse_event(part)
101
+ JSON.parse(part)
102
+ rescue JSON::ParserError => e
103
+ warn "Failed to parse watch event: #{e.message}. Raw event: #{part.inspect}"
104
+ nil
105
+ end
106
+
107
+ def extract_resource_version(event)
108
+ object = event['object']
109
+ return nil unless object.is_a?(Hash)
110
+
111
+ metadata = object['metadata']
112
+ return metadata['resourceVersion'] if metadata.is_a?(Hash)
113
+
114
+ object['resourceVersion']
115
+ end
116
+
117
+ def watch_reset_event?(event)
118
+ event['type'] == 'ERROR' && event.dig('object', 'code').to_i == 410
119
+ end
120
+
121
+ def reconnect_reason(response, reconnect_requested)
122
+ return :reset if reconnect_requested
123
+ return nil unless response
124
+
125
+ return :transport if response.timed_out? || response.code.to_i.zero?
126
+
127
+ nil
128
+ end
129
+
130
+ def reconnect_backoff_seconds(reconnect_attempt)
131
+ RECONNECT_BACKOFF_SECONDS * (2**reconnect_attempt)
132
+ end
133
+
134
+ def raise_terminal_watch_error(response, reconnect_reason)
135
+ if reconnect_reason == :reset
136
+ raise ApiError.new(code: 410, message: 'Watch resource version expired')
137
+ elsif response&.timed_out?
138
+ raise ApiError.new('Watch connection timed out')
139
+ elsif response && response.code.to_i.zero?
140
+ raise ApiError.new(code: 0, message: response.return_message)
141
+ end
142
+ end
64
143
  end
65
144
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.36.0.2
4
+ version: 1.36.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - doridoridoriand
@@ -903,6 +903,7 @@ files:
903
903
  - lib/kubernetes/models/v2_resource_metric_status.rb
904
904
  - lib/kubernetes/models/version_info.rb
905
905
  - lib/kubernetes/release/changelog.rb
906
+ - lib/kubernetes/release/publish_guard.rb
906
907
  - lib/kubernetes/utils.rb
907
908
  - lib/kubernetes/version.rb
908
909
  - lib/kubernetes/watch.rb