aptible-resource 1.0.2 → 1.1.1
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 +5 -5
- data/.github/CODEOWNERS +1 -0
- data/.travis.yml +2 -3
- data/Gemfile +0 -2
- data/README.md +1 -3
- data/aptible-resource.gemspec +9 -9
- data/lib/aptible/resource/adapter.rb +1 -0
- data/lib/aptible/resource/base.rb +9 -12
- data/lib/aptible/resource/default_retry_coordinator.rb +22 -3
- data/lib/aptible/resource/errors.rb +2 -0
- data/lib/aptible/resource/null_retry_coordinator.rb +2 -3
- data/lib/aptible/resource/version.rb +1 -1
- data/lib/aptible/resource.rb +6 -0
- data/lib/hyper_resource/exceptions.rb +1 -1
- data/lib/hyper_resource/link.rb +2 -2
- data/lib/hyper_resource/modules/http/wrap_errors.rb +1 -7
- data/lib/hyper_resource/modules/http.rb +101 -42
- data/lib/hyper_resource/modules/internal_attributes.rb +0 -2
- data/lib/hyper_resource.rb +2 -9
- data/spec/aptible/resource/base_spec.rb +127 -26
- data/spec/aptible/resource/retry_spec.rb +4 -32
- data/spec/fixtures/api.rb +1 -0
- data/spec/fixtures/mainframe.rb +1 -0
- data/spec/fixtures/token.rb +1 -0
- data/spec/spec_helper.rb +2 -0
- metadata +48 -60
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4eeb9d01868528de4be4cb015abbb22c9710086bf2d880c075997a60475f06ba
|
4
|
+
data.tar.gz: 6b1f04a38239649c91bc77f930c4d862ea7d068c7c4f77c36684699fed726925
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87b33183877986d2b1fc2ae9975a256bd361efb0c95f94a7e8d1cd145c36bebd8e3c185fcff32ed394f46076484c65743861004128a52419a5e7fe7541dd35b0
|
7
|
+
data.tar.gz: 90aaa5a7269f47379ed9e8bf7b23e510a3da41072ad7ad7a16a6f8e8ad9332cc473b367a354f88b5743d671230a317425858f42d63b9da95bb120ac1675d51de
|
data/.github/CODEOWNERS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
* @dawenster
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -49,7 +49,5 @@ This gem depends on a vendored version of [HyperResource](https://github.com/gam
|
|
49
49
|
|
50
50
|
MIT License, see [LICENSE](LICENSE.md) for details.
|
51
51
|
|
52
|
-
Copyright (c)
|
53
|
-
|
54
|
-
[<img src="https://s.gravatar.com/avatar/9b58236204e844e3181e43e05ddb0809?s=60" style="border-radius: 50%;" alt="@sandersonet" />](https://github.com/sandersonet)
|
52
|
+
Copyright (c) 2019 [Aptible](https://www.aptible.com) and contributors.
|
55
53
|
|
data/aptible-resource.gemspec
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
|
5
6
|
require 'English'
|
@@ -20,18 +21,17 @@ Gem::Specification.new do |spec|
|
|
20
21
|
spec.require_paths = ['lib']
|
21
22
|
|
22
23
|
# HyperResource dependencies
|
23
|
-
spec.add_dependency '
|
24
|
-
spec.add_dependency 'faraday', '>= 0.9.2', '< 0.14'
|
25
|
-
spec.add_dependency 'json'
|
26
|
-
|
24
|
+
spec.add_dependency 'activesupport'
|
27
25
|
spec.add_dependency 'fridge'
|
28
|
-
spec.add_dependency 'activesupport', '>= 4.0', '< 6.0'
|
29
26
|
spec.add_dependency 'gem_config', '~> 0.3.1'
|
27
|
+
spec.add_dependency 'httpclient', '~> 2.8'
|
28
|
+
spec.add_dependency 'json'
|
29
|
+
spec.add_dependency 'uri_template', '>= 0.5.2'
|
30
30
|
|
31
|
-
spec.add_development_dependency 'bundler', '~> 1.3'
|
32
31
|
spec.add_development_dependency 'aptible-tasks'
|
33
|
-
spec.add_development_dependency '
|
34
|
-
spec.add_development_dependency 'rspec', '~> 2.0'
|
32
|
+
spec.add_development_dependency 'bundler'
|
35
33
|
spec.add_development_dependency 'pry'
|
34
|
+
spec.add_development_dependency 'rake', '< 11.0'
|
35
|
+
spec.add_development_dependency 'rspec', '~> 2.0'
|
36
36
|
spec.add_development_dependency 'webmock', '~> 2.3.2'
|
37
37
|
end
|
@@ -5,7 +5,7 @@ require 'active_support/core_ext'
|
|
5
5
|
require 'date'
|
6
6
|
|
7
7
|
# Require vendored HyperResource
|
8
|
-
$LOAD_PATH.unshift File.expand_path('
|
8
|
+
$LOAD_PATH.unshift File.expand_path('..', __dir__)
|
9
9
|
require 'hyper_resource'
|
10
10
|
|
11
11
|
require 'aptible/resource/adapter'
|
@@ -15,12 +15,14 @@ require 'aptible/resource/boolean'
|
|
15
15
|
module Aptible
|
16
16
|
module Resource
|
17
17
|
# rubocop:disable ClassLength
|
18
|
+
# rubocop:disable DuplicateMethods
|
18
19
|
class Base < HyperResource
|
19
20
|
attr_accessor :errors
|
20
21
|
attr_reader :token
|
21
22
|
|
22
23
|
def self.get_data_type_from_response(response)
|
23
24
|
return nil unless response && response.body
|
25
|
+
|
24
26
|
adapter.get_data_type_from_object(adapter.deserialize(response.body))
|
25
27
|
end
|
26
28
|
|
@@ -79,6 +81,7 @@ module Aptible
|
|
79
81
|
new(options).find_by_url(url)
|
80
82
|
rescue HyperResource::ClientError => e
|
81
83
|
return nil if e.response.status == 404
|
84
|
+
|
82
85
|
raise e
|
83
86
|
end
|
84
87
|
|
@@ -182,6 +185,7 @@ module Aptible
|
|
182
185
|
|
183
186
|
define_method iterator_method do |&block|
|
184
187
|
next enum_for(iterator_method) if block.nil?
|
188
|
+
|
185
189
|
send(relation).each(&block)
|
186
190
|
end
|
187
191
|
end
|
@@ -224,16 +228,7 @@ module Aptible
|
|
224
228
|
end
|
225
229
|
end
|
226
230
|
|
227
|
-
|
228
|
-
# Default Faraday options. May be overridden by passing
|
229
|
-
# faraday_options to the initializer.
|
230
|
-
{
|
231
|
-
request: {
|
232
|
-
open_timeout: 10
|
233
|
-
}
|
234
|
-
}
|
235
|
-
end
|
236
|
-
|
231
|
+
# rubocop:disable ReturnInVoidContext
|
237
232
|
def initialize(options = {})
|
238
233
|
return super(options) unless options.is_a?(Hash)
|
239
234
|
|
@@ -241,6 +236,7 @@ module Aptible
|
|
241
236
|
super(options)
|
242
237
|
self.token = options[:token] if options[:token]
|
243
238
|
end
|
239
|
+
# rubocop:enable ReturnInVoidContext
|
244
240
|
|
245
241
|
def populate_default_options!(options)
|
246
242
|
options[:root] ||= root_url
|
@@ -305,7 +301,7 @@ module Aptible
|
|
305
301
|
# Already deleted
|
306
302
|
raise unless e.response.status == 404
|
307
303
|
rescue HyperResource::ResponseError
|
308
|
-
# HyperResource
|
304
|
+
# HyperResource chokes on empty response bodies
|
309
305
|
nil
|
310
306
|
end
|
311
307
|
|
@@ -327,5 +323,6 @@ module Aptible
|
|
327
323
|
end
|
328
324
|
end
|
329
325
|
# rubocop:enable ClassLength
|
326
|
+
# rubocop:enable DuplicateMethods
|
330
327
|
end
|
331
328
|
end
|
@@ -5,11 +5,27 @@ module Aptible
|
|
5
5
|
|
6
6
|
IDEMPOTENT_METHODS = [
|
7
7
|
# Idempotent as per RFC
|
8
|
-
|
8
|
+
'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PUT',
|
9
|
+
|
9
10
|
# Idempotent on our APIs
|
10
|
-
|
11
|
+
'PATCH'
|
12
|
+
].freeze
|
13
|
+
|
14
|
+
RETRY_ERRORS = [
|
15
|
+
# Ancestor for Errno::X
|
16
|
+
SystemCallError,
|
17
|
+
|
18
|
+
# Might be caused by e.g. DNS failure
|
19
|
+
SocketError,
|
20
|
+
|
21
|
+
# HTTPClient transfer error
|
22
|
+
HTTPClient::TimeoutError,
|
23
|
+
HTTPClient::KeepAliveDisconnected,
|
24
|
+
HTTPClient::BadResponseError,
|
25
|
+
|
26
|
+
# Bad response
|
27
|
+
HyperResource::ServerError
|
11
28
|
].freeze
|
12
|
-
RETRY_ERRORS = [Faraday::Error, HyperResource::ServerError].freeze
|
13
29
|
|
14
30
|
def initialize(resource)
|
15
31
|
@resource = resource
|
@@ -19,9 +35,12 @@ module Aptible
|
|
19
35
|
def retry?(method, err)
|
20
36
|
# rubocop:disable Style/CaseEquality
|
21
37
|
return false unless RETRY_ERRORS.any? { |c| c === err }
|
38
|
+
|
22
39
|
return false unless IDEMPOTENT_METHODS.include?(method)
|
40
|
+
|
23
41
|
retry_in = retry_schedule.shift
|
24
42
|
return false if retry_in.nil?
|
43
|
+
|
25
44
|
sleep retry_in
|
26
45
|
true
|
27
46
|
# rubocop:enable Style/CaseEquality
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Aptible
|
2
2
|
module Resource
|
3
3
|
class Errors
|
4
|
+
# rubocop:disable DuplicateMethods
|
4
5
|
attr_accessor :status_code, :messages, :full_messages
|
5
6
|
|
6
7
|
def self.from_exception(exception)
|
@@ -23,6 +24,7 @@ module Aptible
|
|
23
24
|
def any?
|
24
25
|
full_messages.any?
|
25
26
|
end
|
27
|
+
# rubocop:enable DuplicateMethods
|
26
28
|
end
|
27
29
|
end
|
28
30
|
end
|
data/lib/aptible/resource.rb
CHANGED
@@ -3,6 +3,7 @@ require 'aptible/resource/base'
|
|
3
3
|
require 'aptible/resource/default_retry_coordinator'
|
4
4
|
require 'aptible/resource/null_retry_coordinator'
|
5
5
|
require 'gem_config'
|
6
|
+
require 'logger'
|
6
7
|
|
7
8
|
module Aptible
|
8
9
|
module Resource
|
@@ -18,6 +19,10 @@ module Aptible
|
|
18
19
|
has :user_agent,
|
19
20
|
classes: [String],
|
20
21
|
default: "aptible-resource #{Aptible::Resource::VERSION}"
|
22
|
+
|
23
|
+
has :logger,
|
24
|
+
classes: [Logger],
|
25
|
+
default: Logger.new(STDERR).tap { |l| l.level = Logger::WARN }
|
21
26
|
end
|
22
27
|
|
23
28
|
class << self
|
@@ -37,6 +42,7 @@ module Aptible
|
|
37
42
|
def retry_coordinator_class
|
38
43
|
override = Thread.current[RETRY_COORDINATOR_OVERRIDE]
|
39
44
|
return override if override
|
45
|
+
|
40
46
|
configuration.retry_coordinator_class
|
41
47
|
end
|
42
48
|
end
|
@@ -10,7 +10,7 @@ class HyperResource
|
|
10
10
|
end
|
11
11
|
|
12
12
|
class ResponseError < Exception
|
13
|
-
## The +
|
13
|
+
## The +HTTPClient::Message+ object which led to this exception.
|
14
14
|
attr_accessor :response
|
15
15
|
|
16
16
|
## The deserialized response body which led to this exception.
|
data/lib/hyper_resource/link.rb
CHANGED
@@ -53,7 +53,7 @@ class HyperResource::Link
|
|
53
53
|
|
54
54
|
## If we were called with a method we don't know, load this resource
|
55
55
|
## and pass the message along. This achieves implicit loading.
|
56
|
-
def method_missing(method, *args)
|
57
|
-
self.get.send(method, *args)
|
56
|
+
def method_missing(method, *args, &block)
|
57
|
+
self.get.send(method, *args, &block)
|
58
58
|
end
|
59
59
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class HyperResource
|
2
2
|
module Modules
|
3
3
|
module HTTP
|
4
|
-
|
4
|
+
module WrapErrors
|
5
5
|
class WrappedError < StandardError
|
6
6
|
attr_reader :method, :err
|
7
7
|
|
@@ -10,12 +10,6 @@ class HyperResource
|
|
10
10
|
@err = err
|
11
11
|
end
|
12
12
|
end
|
13
|
-
|
14
|
-
def call(env)
|
15
|
-
@app.call(env)
|
16
|
-
rescue StandardError => e
|
17
|
-
raise WrappedError.new(env.method, e)
|
18
|
-
end
|
19
13
|
end
|
20
14
|
end
|
21
15
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'httpclient'
|
2
2
|
require 'uri'
|
3
3
|
require 'json'
|
4
4
|
require 'digest/md5'
|
@@ -11,11 +11,42 @@ class HyperResource
|
|
11
11
|
# things over and over again.
|
12
12
|
MAX_COORDINATOR_RETRIES = 16
|
13
13
|
|
14
|
+
CONTENT_TYPE_HEADERS = {
|
15
|
+
'Content-Type' => 'application/json; charset=utf-8'
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
class << self
|
19
|
+
attr_reader :http_client
|
20
|
+
|
21
|
+
def initialize_http_client!
|
22
|
+
@http_client = HTTPClient.new.tap do |c|
|
23
|
+
c.cookie_manager = nil
|
24
|
+
c.connect_timeout = 30
|
25
|
+
c.send_timeout = 45
|
26
|
+
c.receive_timeout = 30
|
27
|
+
c.keep_alive_timeout = 15
|
28
|
+
c.ssl_config.set_default_paths
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# We use this accessor / initialize as opposed to a simple constant
|
34
|
+
# because during specs, Webmock stubs the HTTPClient class, but that's
|
35
|
+
# happens after we initialized the constant (we could work around that
|
36
|
+
# by loading Webmock first, but this is just as simple.
|
37
|
+
initialize_http_client!
|
38
|
+
|
14
39
|
## Loads and returns the resource pointed to by +href+. The returned
|
15
40
|
## resource will be blessed into its "proper" class, if
|
16
41
|
## +self.class.namespace != nil+.
|
17
42
|
def get
|
18
|
-
execute_request
|
43
|
+
execute_request('GET') do |uri, headers|
|
44
|
+
HTTP.http_client.get(
|
45
|
+
uri,
|
46
|
+
follow_redirect: true,
|
47
|
+
header: headers
|
48
|
+
)
|
49
|
+
end
|
19
50
|
end
|
20
51
|
|
21
52
|
## By default, calls +post+ with the given arguments. Override to
|
@@ -28,8 +59,13 @@ class HyperResource
|
|
28
59
|
## the response resource.
|
29
60
|
def post(attrs = nil)
|
30
61
|
attrs ||= attributes
|
31
|
-
|
32
|
-
|
62
|
+
|
63
|
+
execute_request('POST') do |uri, headers|
|
64
|
+
HTTP.http_client.post(
|
65
|
+
uri,
|
66
|
+
body: adapter.serialize(attrs),
|
67
|
+
header: headers.merge(CONTENT_TYPE_HEADERS)
|
68
|
+
)
|
33
69
|
end
|
34
70
|
end
|
35
71
|
|
@@ -44,8 +80,13 @@ class HyperResource
|
|
44
80
|
## instead.
|
45
81
|
def put(attrs = nil)
|
46
82
|
attrs ||= attributes
|
47
|
-
|
48
|
-
|
83
|
+
|
84
|
+
execute_request('PUT') do |uri, headers|
|
85
|
+
HTTP.http_client.put(
|
86
|
+
uri,
|
87
|
+
body: adapter.serialize(attrs),
|
88
|
+
header: headers.merge(CONTENT_TYPE_HEADERS)
|
89
|
+
)
|
49
90
|
end
|
50
91
|
end
|
51
92
|
|
@@ -54,49 +95,62 @@ class HyperResource
|
|
54
95
|
## uses those instead.
|
55
96
|
def patch(attrs = nil)
|
56
97
|
attrs ||= attributes.changed_attributes
|
57
|
-
|
58
|
-
|
98
|
+
|
99
|
+
execute_request('PATCH') do |uri, headers|
|
100
|
+
HTTP.http_client.patch(
|
101
|
+
uri,
|
102
|
+
body: adapter.serialize(attrs),
|
103
|
+
header: headers.merge(CONTENT_TYPE_HEADERS)
|
104
|
+
)
|
59
105
|
end
|
60
106
|
end
|
61
107
|
|
62
108
|
## DELETEs this resource's href, and returns the response resource.
|
63
109
|
def delete
|
64
|
-
execute_request
|
65
|
-
|
66
|
-
|
67
|
-
## Returns a raw Faraday connection to this resource's URL, with proper
|
68
|
-
## headers (including auth).
|
69
|
-
def faraday_connection(url = nil)
|
70
|
-
url ||= URI.join(root, href)
|
71
|
-
|
72
|
-
Faraday.new(faraday_options.merge(url: url)) do |builder|
|
73
|
-
builder.headers.merge!(headers || {})
|
74
|
-
builder.headers['User-Agent'] = Aptible::Resource.configuration
|
75
|
-
.user_agent
|
76
|
-
|
77
|
-
if (ba = auth[:basic])
|
78
|
-
builder.basic_auth(*ba)
|
79
|
-
end
|
80
|
-
|
81
|
-
builder.use WrapErrors # This has to be first!
|
82
|
-
builder.request :url_encoded
|
83
|
-
builder.adapter Faraday.default_adapter
|
110
|
+
execute_request('DELETE') do |uri, headers|
|
111
|
+
HTTP.http_client.delete(uri, header: headers)
|
84
112
|
end
|
85
113
|
end
|
86
114
|
|
87
115
|
private
|
88
116
|
|
89
|
-
def execute_request
|
117
|
+
def execute_request(method)
|
90
118
|
raise 'execute_request needs a block!' unless block_given?
|
91
119
|
retry_coordinator = Aptible::Resource.retry_coordinator_class.new(self)
|
92
120
|
|
121
|
+
uri = URI.join(root, href)
|
122
|
+
|
123
|
+
h = headers || {}
|
124
|
+
h['User-Agent'] = Aptible::Resource.configuration.user_agent
|
125
|
+
|
93
126
|
n_retry = 0
|
94
127
|
|
95
128
|
begin
|
129
|
+
t0 = Time.now
|
130
|
+
|
96
131
|
begin
|
97
|
-
|
98
|
-
|
99
|
-
|
132
|
+
res = yield(uri, h)
|
133
|
+
entity = finish_up(res)
|
134
|
+
rescue StandardError => e
|
135
|
+
Aptible::Resource.configuration.logger.info([
|
136
|
+
method,
|
137
|
+
uri,
|
138
|
+
"(#{n_retry})",
|
139
|
+
"#{(Time.now - t0).round(2)}s",
|
140
|
+
"ERR[#{e.class}: #{e}]"
|
141
|
+
].join(' '))
|
142
|
+
|
143
|
+
raise WrapErrors::WrappedError.new(method, e)
|
144
|
+
else
|
145
|
+
Aptible::Resource.configuration.logger.info([
|
146
|
+
method,
|
147
|
+
uri,
|
148
|
+
"(#{n_retry})",
|
149
|
+
"#{(Time.now - t0).round(2)}s",
|
150
|
+
res.status
|
151
|
+
].join(' '))
|
152
|
+
|
153
|
+
entity
|
100
154
|
end
|
101
155
|
rescue WrapErrors::WrappedError => e
|
102
156
|
n_retry += 1
|
@@ -121,18 +175,23 @@ class HyperResource
|
|
121
175
|
elsif status / 100 == 3
|
122
176
|
raise 'HyperResource does not handle redirects'
|
123
177
|
elsif status / 100 == 4
|
124
|
-
raise HyperResource::ClientError.new(
|
125
|
-
|
126
|
-
|
178
|
+
raise HyperResource::ClientError.new(
|
179
|
+
status.to_s,
|
180
|
+
response: response,
|
181
|
+
body: body
|
182
|
+
)
|
127
183
|
elsif status / 100 == 5
|
128
|
-
raise HyperResource::ServerError.new(
|
129
|
-
|
130
|
-
|
131
|
-
|
184
|
+
raise HyperResource::ServerError.new(
|
185
|
+
status.to_s,
|
186
|
+
response: response,
|
187
|
+
body: body
|
188
|
+
)
|
132
189
|
else ## 1xx? really?
|
133
|
-
raise HyperResource::ResponseError.new(
|
134
|
-
|
135
|
-
|
190
|
+
raise HyperResource::ResponseError.new(
|
191
|
+
"Got status #{status}, wtf?",
|
192
|
+
response: response,
|
193
|
+
body: body
|
194
|
+
)
|
136
195
|
|
137
196
|
end
|
138
197
|
|
@@ -26,7 +26,6 @@ module HyperResource::Modules
|
|
26
26
|
:headers, ## e.g. {'Accept' => 'application/vnd.example+json'}
|
27
27
|
:namespace, ## e.g. 'ExampleAPI', or the class ExampleAPI itself
|
28
28
|
:adapter, ## subclass of HR::Adapter
|
29
|
-
:faraday_options ## e.g. {:request => {:timeout => 30}}
|
30
29
|
]
|
31
30
|
end
|
32
31
|
|
@@ -37,7 +36,6 @@ module HyperResource::Modules
|
|
37
36
|
:headers,
|
38
37
|
:namespace,
|
39
38
|
:adapter,
|
40
|
-
:faraday_options,
|
41
39
|
:token,
|
42
40
|
|
43
41
|
:request,
|
data/lib/hyper_resource.rb
CHANGED
@@ -46,9 +46,6 @@ public
|
|
46
46
|
## [headers] Headers to send along with requests for this resource (as
|
47
47
|
## well as its eventual child resources, if any).
|
48
48
|
##
|
49
|
-
## [faraday_options] Configuration passed to +Faraday::Connection.initialize+,
|
50
|
-
## such as +{request: {timeout: 30}}+.
|
51
|
-
##
|
52
49
|
def initialize(opts={})
|
53
50
|
return init_from_resource(opts) if opts.kind_of?(HyperResource)
|
54
51
|
|
@@ -58,8 +55,6 @@ public
|
|
58
55
|
self.namespace = opts[:namespace] || self.class.namespace
|
59
56
|
self.headers = DEFAULT_HEADERS.merge(self.class.headers || {}).
|
60
57
|
merge(opts[:headers] || {})
|
61
|
-
self.faraday_options = opts[:faraday_options] ||
|
62
|
-
self.class.faraday_options || {}
|
63
58
|
|
64
59
|
## There's a little acrobatics in getting Attributes, Links, and Objects
|
65
60
|
## into the correct subclass.
|
@@ -130,14 +125,14 @@ public
|
|
130
125
|
## in this resource. Returns nil on failure.
|
131
126
|
def [](i)
|
132
127
|
get unless loaded
|
133
|
-
self.objects.first[1][i]
|
128
|
+
self.objects.first[1][i]
|
134
129
|
end
|
135
130
|
|
136
131
|
## Iterates over the objects in the first collection of embedded objects
|
137
132
|
## in this resource.
|
138
133
|
def each(&block)
|
139
134
|
get unless loaded
|
140
|
-
self.objects.first[1].each(&block)
|
135
|
+
self.objects.first[1].each(&block)
|
141
136
|
end
|
142
137
|
|
143
138
|
#### Magic
|
@@ -199,7 +194,6 @@ public
|
|
199
194
|
:auth => self.auth,
|
200
195
|
:headers => self.headers,
|
201
196
|
:namespace => self.namespace,
|
202
|
-
:faraday_options => self.faraday_options,
|
203
197
|
:token => self.token,
|
204
198
|
:href => href)
|
205
199
|
end
|
@@ -253,7 +247,6 @@ public
|
|
253
247
|
self.class.response_class(self.response, self.namespace)
|
254
248
|
end
|
255
249
|
|
256
|
-
|
257
250
|
## Inspects the given Faraday::Response, and returns a string describing
|
258
251
|
## this resource's data type.
|
259
252
|
##
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
# rubocop:disable BlockLength
|
4
|
+
# rubocop:disable InterpolationCheck
|
3
5
|
describe Aptible::Resource::Base do
|
4
6
|
let(:hyperresource_exception) { HyperResource::ResponseError.new('403') }
|
5
7
|
let(:error_response) { double 'Faraday::Response' }
|
@@ -36,6 +38,7 @@ describe Aptible::Resource::Base do
|
|
36
38
|
calls << u
|
37
39
|
page = pages[u]
|
38
40
|
raise "Accessed unexpected URL #{u}" if page.nil?
|
41
|
+
|
39
42
|
page
|
40
43
|
end
|
41
44
|
end
|
@@ -52,16 +55,31 @@ describe Aptible::Resource::Base do
|
|
52
55
|
end
|
53
56
|
|
54
57
|
describe '.find' do
|
55
|
-
it 'should
|
56
|
-
|
57
|
-
|
58
|
-
|
58
|
+
it 'should find' do
|
59
|
+
stub_request(
|
60
|
+
:get, 'https://resource.example.com/mainframes/42'
|
61
|
+
).to_return(body: { id: 42 }.to_json, status: 200)
|
62
|
+
|
63
|
+
m = Api::Mainframe.find(42)
|
64
|
+
expect(m.id).to eq(42)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should find with query params' do
|
68
|
+
stub_request(
|
69
|
+
:get, 'https://resource.example.com/mainframes/42?test=123'
|
70
|
+
).to_return(body: { id: 42 }.to_json, status: 200)
|
71
|
+
|
72
|
+
m = Api::Mainframe.find(42, test: 123)
|
73
|
+
expect(m.id).to eq(42)
|
59
74
|
end
|
60
75
|
|
61
|
-
it 'should
|
62
|
-
|
63
|
-
|
64
|
-
|
76
|
+
it 'should return an instance of the correct class' do
|
77
|
+
stub_request(
|
78
|
+
:get, 'https://resource.example.com/mainframes/42'
|
79
|
+
).to_return(body: { id: 42 }.to_json, status: 200)
|
80
|
+
|
81
|
+
m = Api::Mainframe.find(42)
|
82
|
+
expect(m).to be_a(Api::Mainframe)
|
65
83
|
end
|
66
84
|
end
|
67
85
|
|
@@ -72,7 +90,7 @@ describe Aptible::Resource::Base do
|
|
72
90
|
|
73
91
|
before do
|
74
92
|
collection.stub(:entries) { [mainframe] }
|
75
|
-
collection.stub(:links) {
|
93
|
+
collection.stub(:links) { {} }
|
76
94
|
Api::Mainframe.any_instance.stub(:find_by_url) { collection }
|
77
95
|
end
|
78
96
|
|
@@ -254,7 +272,7 @@ describe Aptible::Resource::Base do
|
|
254
272
|
HyperResource.any_instance.stub(:put) { raise hyperresource_exception }
|
255
273
|
begin
|
256
274
|
subject.update!({})
|
257
|
-
rescue
|
275
|
+
rescue StandardError
|
258
276
|
# Allow errors to be populated and tested
|
259
277
|
nil
|
260
278
|
end
|
@@ -453,7 +471,7 @@ describe Aptible::Resource::Base do
|
|
453
471
|
end
|
454
472
|
|
455
473
|
context 'configuration' do
|
456
|
-
subject { Api.new(root: 'http://
|
474
|
+
subject { Api.new(root: 'http://example.com') }
|
457
475
|
|
458
476
|
def configure_new_coordinator(&block)
|
459
477
|
Aptible::Resource.configure do |config|
|
@@ -468,7 +486,7 @@ describe Aptible::Resource::Base do
|
|
468
486
|
it 'should not retry if the proc returns false' do
|
469
487
|
configure_new_coordinator { define_method(:retry?) { |_, _e| false } }
|
470
488
|
|
471
|
-
stub_request(:get, '
|
489
|
+
stub_request(:get, 'example.com')
|
472
490
|
.to_return(body: { error: 'foo' }.to_json, status: 401).then
|
473
491
|
.to_return(body: { status: 'ok' }.to_json, status: 200)
|
474
492
|
|
@@ -479,7 +497,7 @@ describe Aptible::Resource::Base do
|
|
479
497
|
it 'should retry if the proc returns true' do
|
480
498
|
configure_new_coordinator { define_method(:retry?) { |_, _e| true } }
|
481
499
|
|
482
|
-
stub_request(:get, '
|
500
|
+
stub_request(:get, 'example.com')
|
483
501
|
.to_return(body: { error: 'foo' }.to_json, status: 401).then
|
484
502
|
.to_return(body: { error: 'foo' }.to_json, status: 401).then
|
485
503
|
.to_return(body: { status: 'ok' }.to_json, status: 200)
|
@@ -494,7 +512,7 @@ describe Aptible::Resource::Base do
|
|
494
512
|
define_method(:retry?) { |_, _e| failures += 1 || true }
|
495
513
|
end
|
496
514
|
|
497
|
-
stub_request(:get, '
|
515
|
+
stub_request(:get, 'example.com')
|
498
516
|
.to_return(body: { error: 'foo' }.to_json, status: 401).then
|
499
517
|
.to_return(body: { status: 'ok' }.to_json, status: 200).then
|
500
518
|
.to_return(body: { error: 'foo' }.to_json, status: 401)
|
@@ -505,7 +523,7 @@ describe Aptible::Resource::Base do
|
|
505
523
|
end
|
506
524
|
|
507
525
|
it 'should not retry with the default proc' do
|
508
|
-
stub_request(:get, '
|
526
|
+
stub_request(:get, 'example.com')
|
509
527
|
.to_return(body: { error: 'foo' }.to_json, status: 401).then
|
510
528
|
.to_return(body: { status: 'ok' }.to_json, status: 200)
|
511
529
|
|
@@ -522,7 +540,7 @@ describe Aptible::Resource::Base do
|
|
522
540
|
define_method(:retry?) { |_, e| (exception = e) && false }
|
523
541
|
end
|
524
542
|
|
525
|
-
stub_request(:get, '
|
543
|
+
stub_request(:get, 'example.com')
|
526
544
|
.to_return(body: { error: 'foo' }.to_json, status: 401)
|
527
545
|
|
528
546
|
expect { subject.get.body }
|
@@ -544,11 +562,11 @@ describe Aptible::Resource::Base do
|
|
544
562
|
end
|
545
563
|
end
|
546
564
|
|
547
|
-
stub_request(:get, '
|
565
|
+
stub_request(:get, 'example.com')
|
548
566
|
.with(headers: { 'Authorization' => /foo/ })
|
549
567
|
.to_return(body: { error: 'foo' }.to_json, status: 401)
|
550
568
|
|
551
|
-
stub_request(:get, '
|
569
|
+
stub_request(:get, 'example.com')
|
552
570
|
.with(headers: { 'Authorization' => /bar/ })
|
553
571
|
.to_return(body: { status: 'ok' }.to_json, status: 200)
|
554
572
|
|
@@ -563,7 +581,7 @@ describe Aptible::Resource::Base do
|
|
563
581
|
define_method(:retry?) { |_, _e| n += 1 || true }
|
564
582
|
end
|
565
583
|
|
566
|
-
stub_request(:get, '
|
584
|
+
stub_request(:get, 'example.com')
|
567
585
|
.to_return(body: { error: 'foo' }.to_json, status: 401)
|
568
586
|
|
569
587
|
expect { subject.get.body }
|
@@ -579,7 +597,7 @@ describe Aptible::Resource::Base do
|
|
579
597
|
config.user_agent = 'foo ua'
|
580
598
|
end
|
581
599
|
|
582
|
-
stub_request(:get, '
|
600
|
+
stub_request(:get, 'example.com')
|
583
601
|
.with(headers: { 'User-Agent' => 'foo ua' })
|
584
602
|
.to_return(body: { status: 'ok' }.to_json, status: 200)
|
585
603
|
|
@@ -589,22 +607,22 @@ describe Aptible::Resource::Base do
|
|
589
607
|
end
|
590
608
|
|
591
609
|
context 'token' do
|
592
|
-
subject { Api.new(root: 'http://
|
610
|
+
subject { Api.new(root: 'http://example.com', token: 'bar') }
|
593
611
|
|
594
612
|
before do
|
595
|
-
stub_request(:get, '
|
613
|
+
stub_request(:get, 'example.com/')
|
596
614
|
.with(headers: { 'Authorization' => /Bearer (bar|foo)/ })
|
597
615
|
.to_return(body: {
|
598
|
-
_links: { some: { href: 'http://
|
599
|
-
mainframes: { href: 'http://
|
616
|
+
_links: { some: { href: 'http://example.com/some' },
|
617
|
+
mainframes: { href: 'http://example.com/mainframes' } },
|
600
618
|
_embedded: { best_mainframe: { _type: 'mainframe', status: 'ok' } }
|
601
619
|
}.to_json, status: 200)
|
602
620
|
|
603
|
-
stub_request(:get, '
|
621
|
+
stub_request(:get, 'example.com/some')
|
604
622
|
.with(headers: { 'Authorization' => /Bearer (bar|foo)/ })
|
605
623
|
.to_return(body: { status: 'ok' }.to_json, status: 200)
|
606
624
|
|
607
|
-
stub_request(:get, '
|
625
|
+
stub_request(:get, 'example.com/mainframes')
|
608
626
|
.with(headers: { 'Authorization' => /Bearer (bar|foo)/ })
|
609
627
|
.to_return(body: { _embedded: {
|
610
628
|
mainframes: [{ status: 'ok' }]
|
@@ -646,4 +664,87 @@ describe Aptible::Resource::Base do
|
|
646
664
|
expect(m.token).to eq('bar')
|
647
665
|
end
|
648
666
|
end
|
667
|
+
|
668
|
+
context 'lazy fetching' do
|
669
|
+
subject { Api.new(root: 'http://foo.com') }
|
670
|
+
|
671
|
+
it 'should support enumerable methods' do
|
672
|
+
index = {
|
673
|
+
_links: {
|
674
|
+
some_items: { href: 'http://foo.com/some_items' }
|
675
|
+
}
|
676
|
+
}
|
677
|
+
|
678
|
+
some_items = {
|
679
|
+
_embedded: {
|
680
|
+
some_items: [
|
681
|
+
{ id: 1, handle: 'foo' },
|
682
|
+
{ id: 2, handle: 'bar' },
|
683
|
+
{ id: 3, handle: 'qux' }
|
684
|
+
]
|
685
|
+
}
|
686
|
+
}
|
687
|
+
|
688
|
+
stub_request(:get, 'foo.com')
|
689
|
+
.to_return(body: index.to_json, status: 200)
|
690
|
+
|
691
|
+
stub_request(:get, 'foo.com/some_items')
|
692
|
+
.to_return(body: some_items.to_json, status: 200)
|
693
|
+
|
694
|
+
bar = subject.some_items.find { |m| m.id == 2 }
|
695
|
+
expect(bar.handle).to eq('bar')
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
699
|
+
describe '_type' do
|
700
|
+
subject { Api.new(root: 'http://example.com', token: 'bar') }
|
701
|
+
|
702
|
+
it 'uses the correct class for an expected linked instance' do
|
703
|
+
stub_request(:get, 'example.com/')
|
704
|
+
.to_return(body: {
|
705
|
+
_links: {
|
706
|
+
worst_mainframe: { href: 'http://example.com/mainframes/123' }
|
707
|
+
}
|
708
|
+
}.to_json, status: 200)
|
709
|
+
|
710
|
+
stub_request(:get, 'example.com/mainframes/123')
|
711
|
+
.to_return(body: { _type: 'mainframe', id: 123 }.to_json, status: 200)
|
712
|
+
|
713
|
+
expect(subject.worst_mainframe).to be_a(Api::Mainframe)
|
714
|
+
end
|
715
|
+
|
716
|
+
it 'uses the correct class for an unexpected linked instance' do
|
717
|
+
stub_request(:get, 'example.com/')
|
718
|
+
.to_return(body: {
|
719
|
+
_links: {
|
720
|
+
some: { href: 'http://example.com/mainframes/123' }
|
721
|
+
}
|
722
|
+
}.to_json, status: 200)
|
723
|
+
|
724
|
+
stub_request(:get, 'example.com/mainframes/123')
|
725
|
+
.to_return(body: { _type: 'mainframe', id: 123 }.to_json, status: 200)
|
726
|
+
|
727
|
+
expect(subject.some.get).to be_a(Api::Mainframe)
|
728
|
+
end
|
729
|
+
|
730
|
+
it 'uses the correct class for an expected embedded instance' do
|
731
|
+
stub_request(:get, 'example.com/')
|
732
|
+
.to_return(body: {
|
733
|
+
_embedded: { best_mainframe: { _type: 'mainframe', id: 123 } }
|
734
|
+
}.to_json, status: 200)
|
735
|
+
|
736
|
+
expect(subject.best_mainframe).to be_a(Api::Mainframe)
|
737
|
+
end
|
738
|
+
|
739
|
+
it 'uses the correct class for an unexpected embedded instance' do
|
740
|
+
stub_request(:get, 'example.com/')
|
741
|
+
.to_return(body: {
|
742
|
+
_embedded: { some: { _type: 'mainframe', id: 123 } }
|
743
|
+
}.to_json, status: 200)
|
744
|
+
|
745
|
+
expect(subject.some).to be_a(Api::Mainframe)
|
746
|
+
end
|
747
|
+
end
|
649
748
|
end
|
749
|
+
# rubocop:enable InterpolationCheck
|
750
|
+
# rubocop:enable BlockLength
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
# With webmock (fake connections), to check how we handle timeouts.
|
4
|
+
# rubocop:disable BlockLength
|
4
5
|
describe Aptible::Resource::Base do
|
5
6
|
let(:body) do
|
6
7
|
{ 'hello' => '1', '_links' => { 'self' => { 'href' => href } } }
|
@@ -136,15 +137,6 @@ describe Aptible::Resource::Base do
|
|
136
137
|
expect(subject.get.body).to eq(body)
|
137
138
|
end
|
138
139
|
|
139
|
-
it 'should retry timeout errors (Net::OpenTimeout)' do
|
140
|
-
stub_request(:get, href)
|
141
|
-
.to_raise(Net::OpenTimeout).then
|
142
|
-
.to_raise(Net::OpenTimeout).then
|
143
|
-
.to_return(body: json_body)
|
144
|
-
|
145
|
-
expect(subject.get.body).to eq(body)
|
146
|
-
end
|
147
|
-
|
148
140
|
it 'should retry connection errors' do
|
149
141
|
stub_request(:get, href)
|
150
142
|
.to_raise(Errno::ECONNREFUSED).then
|
@@ -159,30 +151,10 @@ describe Aptible::Resource::Base do
|
|
159
151
|
.to_timeout.then
|
160
152
|
.to_return(body: json_body)
|
161
153
|
|
162
|
-
expect { subject.post }
|
163
|
-
|
164
|
-
end
|
165
|
-
|
166
|
-
context 'without connections' do
|
167
|
-
around do |example|
|
168
|
-
WebMock.allow_net_connect!
|
169
|
-
example.run
|
170
|
-
WebMock.disable_net_connect!
|
171
|
-
end
|
172
|
-
|
173
|
-
it 'default to 10 seconds of timeout and retries 4 times' do
|
174
|
-
# This really relies on how exactly MRI implements Net::HTTP open
|
175
|
-
# timeouts
|
176
|
-
skip 'MRI implementation-specific' if RUBY_PLATFORM == 'java'
|
177
|
-
|
178
|
-
expect(Timeout).to receive(:timeout)
|
179
|
-
.with(10, Net::OpenTimeout)
|
180
|
-
.exactly(4).times
|
181
|
-
.and_raise(Net::OpenTimeout)
|
182
|
-
|
183
|
-
expect { subject.get }.to raise_error(Faraday::ConnectionFailed)
|
184
|
-
expect(sleeps.size).to eq(3)
|
154
|
+
expect { subject.post }
|
155
|
+
.to raise_error(HTTPClient::TimeoutError)
|
185
156
|
end
|
186
157
|
end
|
187
158
|
end
|
188
159
|
end
|
160
|
+
# rubocop:enable BlockLength
|
data/spec/fixtures/api.rb
CHANGED
data/spec/fixtures/mainframe.rb
CHANGED
data/spec/fixtures/token.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -18,6 +18,8 @@ require 'webmock/rspec'
|
|
18
18
|
WebMock.disable_net_connect!
|
19
19
|
|
20
20
|
RSpec.configure do |config|
|
21
|
+
config.before(:suite) { HyperResource::Modules::HTTP.initialize_http_client! }
|
22
|
+
|
21
23
|
config.before { Aptible::Resource.configuration.reset }
|
22
24
|
config.before { WebMock.reset! }
|
23
25
|
|
metadata
CHANGED
@@ -1,127 +1,115 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aptible-resource
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Frank Macreery
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0
|
19
|
+
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0
|
26
|
+
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: fridge
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0
|
34
|
-
- - "<"
|
35
|
-
- !ruby/object:Gem::Version
|
36
|
-
version: '0.14'
|
33
|
+
version: '0'
|
37
34
|
type: :runtime
|
38
35
|
prerelease: false
|
39
36
|
version_requirements: !ruby/object:Gem::Requirement
|
40
37
|
requirements:
|
41
38
|
- - ">="
|
42
39
|
- !ruby/object:Gem::Version
|
43
|
-
version: 0
|
44
|
-
- - "<"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '0.14'
|
40
|
+
version: '0'
|
47
41
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
42
|
+
name: gem_config
|
49
43
|
requirement: !ruby/object:Gem::Requirement
|
50
44
|
requirements:
|
51
|
-
- - "
|
45
|
+
- - "~>"
|
52
46
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
47
|
+
version: 0.3.1
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
51
|
requirements:
|
58
|
-
- - "
|
52
|
+
- - "~>"
|
59
53
|
- !ruby/object:Gem::Version
|
60
|
-
version:
|
54
|
+
version: 0.3.1
|
61
55
|
- !ruby/object:Gem::Dependency
|
62
|
-
name:
|
56
|
+
name: httpclient
|
63
57
|
requirement: !ruby/object:Gem::Requirement
|
64
58
|
requirements:
|
65
|
-
- - "
|
59
|
+
- - "~>"
|
66
60
|
- !ruby/object:Gem::Version
|
67
|
-
version: '
|
61
|
+
version: '2.8'
|
68
62
|
type: :runtime
|
69
63
|
prerelease: false
|
70
64
|
version_requirements: !ruby/object:Gem::Requirement
|
71
65
|
requirements:
|
72
|
-
- - "
|
66
|
+
- - "~>"
|
73
67
|
- !ruby/object:Gem::Version
|
74
|
-
version: '
|
68
|
+
version: '2.8'
|
75
69
|
- !ruby/object:Gem::Dependency
|
76
|
-
name:
|
70
|
+
name: json
|
77
71
|
requirement: !ruby/object:Gem::Requirement
|
78
72
|
requirements:
|
79
73
|
- - ">="
|
80
74
|
- !ruby/object:Gem::Version
|
81
|
-
version: '
|
82
|
-
- - "<"
|
83
|
-
- !ruby/object:Gem::Version
|
84
|
-
version: '6.0'
|
75
|
+
version: '0'
|
85
76
|
type: :runtime
|
86
77
|
prerelease: false
|
87
78
|
version_requirements: !ruby/object:Gem::Requirement
|
88
79
|
requirements:
|
89
80
|
- - ">="
|
90
81
|
- !ruby/object:Gem::Version
|
91
|
-
version: '
|
92
|
-
- - "<"
|
93
|
-
- !ruby/object:Gem::Version
|
94
|
-
version: '6.0'
|
82
|
+
version: '0'
|
95
83
|
- !ruby/object:Gem::Dependency
|
96
|
-
name:
|
84
|
+
name: uri_template
|
97
85
|
requirement: !ruby/object:Gem::Requirement
|
98
86
|
requirements:
|
99
|
-
- - "
|
87
|
+
- - ">="
|
100
88
|
- !ruby/object:Gem::Version
|
101
|
-
version: 0.
|
89
|
+
version: 0.5.2
|
102
90
|
type: :runtime
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
93
|
requirements:
|
106
|
-
- - "
|
94
|
+
- - ">="
|
107
95
|
- !ruby/object:Gem::Version
|
108
|
-
version: 0.
|
96
|
+
version: 0.5.2
|
109
97
|
- !ruby/object:Gem::Dependency
|
110
|
-
name:
|
98
|
+
name: aptible-tasks
|
111
99
|
requirement: !ruby/object:Gem::Requirement
|
112
100
|
requirements:
|
113
|
-
- - "
|
101
|
+
- - ">="
|
114
102
|
- !ruby/object:Gem::Version
|
115
|
-
version: '
|
103
|
+
version: '0'
|
116
104
|
type: :development
|
117
105
|
prerelease: false
|
118
106
|
version_requirements: !ruby/object:Gem::Requirement
|
119
107
|
requirements:
|
120
|
-
- - "
|
108
|
+
- - ">="
|
121
109
|
- !ruby/object:Gem::Version
|
122
|
-
version: '
|
110
|
+
version: '0'
|
123
111
|
- !ruby/object:Gem::Dependency
|
124
|
-
name:
|
112
|
+
name: bundler
|
125
113
|
requirement: !ruby/object:Gem::Requirement
|
126
114
|
requirements:
|
127
115
|
- - ">="
|
@@ -135,7 +123,7 @@ dependencies:
|
|
135
123
|
- !ruby/object:Gem::Version
|
136
124
|
version: '0'
|
137
125
|
- !ruby/object:Gem::Dependency
|
138
|
-
name:
|
126
|
+
name: pry
|
139
127
|
requirement: !ruby/object:Gem::Requirement
|
140
128
|
requirements:
|
141
129
|
- - ">="
|
@@ -149,33 +137,33 @@ dependencies:
|
|
149
137
|
- !ruby/object:Gem::Version
|
150
138
|
version: '0'
|
151
139
|
- !ruby/object:Gem::Dependency
|
152
|
-
name:
|
140
|
+
name: rake
|
153
141
|
requirement: !ruby/object:Gem::Requirement
|
154
142
|
requirements:
|
155
|
-
- - "
|
143
|
+
- - "<"
|
156
144
|
- !ruby/object:Gem::Version
|
157
|
-
version: '
|
145
|
+
version: '11.0'
|
158
146
|
type: :development
|
159
147
|
prerelease: false
|
160
148
|
version_requirements: !ruby/object:Gem::Requirement
|
161
149
|
requirements:
|
162
|
-
- - "
|
150
|
+
- - "<"
|
163
151
|
- !ruby/object:Gem::Version
|
164
|
-
version: '
|
152
|
+
version: '11.0'
|
165
153
|
- !ruby/object:Gem::Dependency
|
166
|
-
name:
|
154
|
+
name: rspec
|
167
155
|
requirement: !ruby/object:Gem::Requirement
|
168
156
|
requirements:
|
169
|
-
- - "
|
157
|
+
- - "~>"
|
170
158
|
- !ruby/object:Gem::Version
|
171
|
-
version: '0'
|
159
|
+
version: '2.0'
|
172
160
|
type: :development
|
173
161
|
prerelease: false
|
174
162
|
version_requirements: !ruby/object:Gem::Requirement
|
175
163
|
requirements:
|
176
|
-
- - "
|
164
|
+
- - "~>"
|
177
165
|
- !ruby/object:Gem::Version
|
178
|
-
version: '0'
|
166
|
+
version: '2.0'
|
179
167
|
- !ruby/object:Gem::Dependency
|
180
168
|
name: webmock
|
181
169
|
requirement: !ruby/object:Gem::Requirement
|
@@ -197,6 +185,7 @@ executables: []
|
|
197
185
|
extensions: []
|
198
186
|
extra_rdoc_files: []
|
199
187
|
files:
|
188
|
+
- ".github/CODEOWNERS"
|
200
189
|
- ".gitignore"
|
201
190
|
- ".rspec"
|
202
191
|
- ".rubocop.yml"
|
@@ -238,7 +227,7 @@ homepage: https://github.com/aptible/aptible-resource
|
|
238
227
|
licenses:
|
239
228
|
- MIT
|
240
229
|
metadata: {}
|
241
|
-
post_install_message:
|
230
|
+
post_install_message:
|
242
231
|
rdoc_options: []
|
243
232
|
require_paths:
|
244
233
|
- lib
|
@@ -253,9 +242,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
253
242
|
- !ruby/object:Gem::Version
|
254
243
|
version: '0'
|
255
244
|
requirements: []
|
256
|
-
|
257
|
-
|
258
|
-
signing_key:
|
245
|
+
rubygems_version: 3.0.3.1
|
246
|
+
signing_key:
|
259
247
|
specification_version: 4
|
260
248
|
summary: Foundation classes for Aptible resource server gems
|
261
249
|
test_files:
|