apipie-bindings 0.0.10 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +18 -3
- data/README.md +1 -1
- data/doc/release_notes.md +6 -0
- data/lib/apipie_bindings.rb +1 -0
- data/lib/apipie_bindings/api.rb +46 -14
- data/lib/apipie_bindings/credentials.rb +22 -0
- data/lib/apipie_bindings/exceptions.rb +4 -0
- data/lib/apipie_bindings/version.rb +1 -1
- data/test/unit/action_test.rb +4 -2
- data/test/unit/api_test.rb +48 -5
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c09e522a914498b0cc1edbefcbcfc9a31bdde5e
|
4
|
+
data.tar.gz: 64e1e5df75c1c34e48bacfbee89b918a82d4d67b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87f289b0d316e15d468abdf01bad936c9692dd9834ac0fc8e847225f26c54400778b1c8134cf800b1dad6c4e2cb66861ca44e935d537c7d3b641e2074ac9a434
|
7
|
+
data.tar.gz: ceeeab2bf484187e116bdcf72c3f32a148e282ec3234ed59c38211b85d0a55631ebb73648067a5923c0e97db23abe86a2c8b5657aa27e9b735c3dbd7c2643a71
|
data/LICENSE
CHANGED
@@ -1,5 +1,20 @@
|
|
1
|
-
|
1
|
+
Copyright 2014 Martin Bačovský and contributors
|
2
2
|
|
3
|
-
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
4
10
|
|
5
|
-
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
data/doc/release_notes.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
Release notes
|
2
2
|
=============
|
3
3
|
|
4
|
+
### 0.0.11 (2014-11-09)
|
5
|
+
* Added lazy loading of credentials ([#7408](http://projects.theforeman.org/issues/7408))
|
6
|
+
* Separate caches for different API versions ([#18](http://github.com/Apipie/apipie-bindings/issues/18))
|
7
|
+
* Change license to MIT
|
8
|
+
* List missing parameter names in validation exception message
|
9
|
+
|
4
10
|
### 0.0.10 (2014-09-18)
|
5
11
|
* apipie-bindings should enforce required params, BZ 1116803 ([#6820](http://projects.theforeman.org/issues/6820))
|
6
12
|
|
data/lib/apipie_bindings.rb
CHANGED
data/lib/apipie_bindings/api.rb
CHANGED
@@ -21,6 +21,10 @@ module ApipieBindings
|
|
21
21
|
# * *:consumer_key* (String) OAuth key
|
22
22
|
# * *:consumer_secret* (String) OAuth secret
|
23
23
|
# * *:options* (Hash) options passed to OAuth
|
24
|
+
# @option config [AbstractCredentials] :credentials object implementing {AbstractCredentials}
|
25
|
+
# interface e.g. {https://github.com/theforeman/hammer-cli-foreman/blob/master/lib/hammer_cli_foreman/credentials.rb HammerCLIForeman::BasicCredentials}
|
26
|
+
# This is prefered way to pass credentials. Credentials acquired form :credentials object take
|
27
|
+
# precedence over explicite params
|
24
28
|
# @option config [Hash] :headers additional headers to send with the requests
|
25
29
|
# @option config [String] :api_version ('1') version of the API
|
26
30
|
# @option config [String] :language prefered locale for the API description
|
@@ -30,6 +34,9 @@ module ApipieBindings
|
|
30
34
|
# to cache the JSON description of the API
|
31
35
|
# @option config [String] :apidoc_cache_name ('default.json') name of te cache file.
|
32
36
|
# If there is cache in the :apidoc_cache_dir, it is used.
|
37
|
+
# @option config [String] :apidoc_authenticated (true) whether or not does the call to
|
38
|
+
# obtain API description use authentication. It is useful to avoid unnecessary prompts
|
39
|
+
# for credentials
|
33
40
|
# @option config [Hash] :fake_responses ({}) responses to return if used in dry run mode
|
34
41
|
# @option config [Bool] :dry_run (false) dry run mode allows to test your scripts
|
35
42
|
# and not touch the API. The results are taken form exemples in the API description
|
@@ -56,8 +63,9 @@ module ApipieBindings
|
|
56
63
|
@api_version = config[:api_version] || 1
|
57
64
|
@language = config[:language]
|
58
65
|
apidoc_cache_base_dir = config[:apidoc_cache_base_dir] || File.join(File.expand_path('~/.cache'), 'apipie_bindings')
|
59
|
-
@apidoc_cache_dir = config[:apidoc_cache_dir] || File.join(apidoc_cache_base_dir, @uri.tr(':/', '_'))
|
66
|
+
@apidoc_cache_dir = config[:apidoc_cache_dir] || File.join(apidoc_cache_base_dir, @uri.tr(':/', '_'), "v#{@api_version}")
|
60
67
|
@apidoc_cache_name = config[:apidoc_cache_name] || set_default_name
|
68
|
+
@apidoc_authenticated = (config[:apidoc_authenticated].nil? ? true : config[:apidoc_authenticated])
|
61
69
|
@dry_run = config[:dry_run] || false
|
62
70
|
@aggressive_cache_checking = config[:aggressive_cache_checking] || false
|
63
71
|
@fake_responses = config[:fake_responses] || {}
|
@@ -79,15 +87,13 @@ module ApipieBindings
|
|
79
87
|
|
80
88
|
log.debug "Global headers: #{headers.ai}"
|
81
89
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
:oauth => config[:oauth],
|
90
|
+
@credentials = config[:credentials] if config[:credentials] && config[:credentials].respond_to?(:to_params)
|
91
|
+
|
92
|
+
@resource_config = {
|
86
93
|
:timeout => config[:timeout],
|
87
94
|
:headers => headers
|
88
95
|
}.merge(options)
|
89
96
|
|
90
|
-
@client = RestClient::Resource.new(config[:uri], resource_config)
|
91
97
|
@config = config
|
92
98
|
end
|
93
99
|
|
@@ -141,6 +147,7 @@ module ApipieBindings
|
|
141
147
|
# @param [Hash] headers extra headers to be sent with the request
|
142
148
|
# @param [Hash] options options to influence the how the call is processed
|
143
149
|
# * *:response* (Symbol) *:raw* - skip parsing JSON in response
|
150
|
+
# * *:with_authentication* (Bool) *true* - use rest client with/without auth configuration
|
144
151
|
# @example show user data
|
145
152
|
# call(:users, :show, :id => 1)
|
146
153
|
def call(resource_name, action_name, params={}, headers={}, options={})
|
@@ -166,6 +173,7 @@ module ApipieBindings
|
|
166
173
|
# @param [Hash] options options to influence the how the call is processed
|
167
174
|
# * *:response* (Symbol) *:raw* - skip parsing JSON in response
|
168
175
|
# * *:reduce_response_log* (Bool) - do not show response content in the log.
|
176
|
+
# * *:with_authentication* (Bool) *true* - use rest client with/without auth configuration
|
169
177
|
# @example show user data
|
170
178
|
# http_call('get', '/api/users/1')
|
171
179
|
def http_call(http_method, path, params={}, headers={}, options={})
|
@@ -196,7 +204,10 @@ module ApipieBindings
|
|
196
204
|
response = RestClient::Response.create(ex.response, net_http_resp, args)
|
197
205
|
else
|
198
206
|
begin
|
199
|
-
|
207
|
+
apidoc_without_auth = (path =~ /\/apidoc\//) && !@apidoc_authenticated
|
208
|
+
authenticate = options[:with_authentication].nil? ? !apidoc_without_auth : options[:with_authentication]
|
209
|
+
client = authenticate ? authenticated_client : unauthenticated_client
|
210
|
+
response = call_client(client, path, args)
|
200
211
|
update_cache(response.headers[:apipie_checksum])
|
201
212
|
rescue => e
|
202
213
|
log.debug e.message + "\n" +
|
@@ -227,19 +238,13 @@ module ApipieBindings
|
|
227
238
|
|
228
239
|
def check_cache
|
229
240
|
begin
|
230
|
-
response = http_call('get', "/apidoc/apipie_checksum", {}, {:accept => "application/json"})
|
241
|
+
response = http_call('get', "/apidoc/apipie_checksum", {}, { :accept => "application/json" })
|
231
242
|
response['checksum']
|
232
243
|
rescue
|
233
244
|
nil
|
234
245
|
end
|
235
246
|
end
|
236
247
|
|
237
|
-
def log
|
238
|
-
@logger
|
239
|
-
end
|
240
|
-
|
241
|
-
private
|
242
|
-
|
243
248
|
def retrieve_apidoc
|
244
249
|
FileUtils.mkdir_p(@apidoc_cache_dir) unless File.exists?(@apidoc_cache_dir)
|
245
250
|
if language
|
@@ -264,6 +269,33 @@ module ApipieBindings
|
|
264
269
|
load_apidoc
|
265
270
|
end
|
266
271
|
|
272
|
+
def log
|
273
|
+
@logger
|
274
|
+
end
|
275
|
+
|
276
|
+
private
|
277
|
+
|
278
|
+
def call_client(client, path, args)
|
279
|
+
client[path].send(*args)
|
280
|
+
end
|
281
|
+
|
282
|
+
def authenticated_client
|
283
|
+
unless @client_with_auth
|
284
|
+
resource_config = @resource_config.merge({
|
285
|
+
:user => @config[:username],
|
286
|
+
:password => @config[:password],
|
287
|
+
:oauth => @config[:oauth],
|
288
|
+
})
|
289
|
+
resource_config.merge!(@credentials.to_params) if @credentials
|
290
|
+
@client_with_auth = RestClient::Resource.new(@config[:uri], resource_config)
|
291
|
+
end
|
292
|
+
@client_with_auth
|
293
|
+
end
|
294
|
+
|
295
|
+
def unauthenticated_client
|
296
|
+
@client_without_auth ||= RestClient::Resource.new(@config[:uri], @resource_config)
|
297
|
+
end
|
298
|
+
|
267
299
|
def retrieve_apidoc_call(path, options={})
|
268
300
|
begin
|
269
301
|
http_call('get', path, {},
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ApipieBindings
|
2
|
+
|
3
|
+
# AbstractCredentials class can hold your logic to get
|
4
|
+
# users credentials. It defines interface that can be used
|
5
|
+
# by ApipieBindings when the credentials are needed to create connection
|
6
|
+
class AbstractCredentials
|
7
|
+
|
8
|
+
# Convert credentials to hash usable for merging to RestClient configuration
|
9
|
+
# @return [Hash]
|
10
|
+
def to_params
|
11
|
+
{}
|
12
|
+
end
|
13
|
+
|
14
|
+
# Check that credentials storage is empty
|
15
|
+
def empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
# Clear credentials storage
|
19
|
+
def clear
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/test/unit/action_test.rb
CHANGED
@@ -42,14 +42,16 @@ describe ApipieBindings::Action do
|
|
42
42
|
|
43
43
|
|
44
44
|
it "should validate incorrect params" do
|
45
|
-
proc do
|
45
|
+
e = proc do
|
46
46
|
resource.action(:create).validate!({ :architecture => { :foo => "foo" } })
|
47
47
|
end.must_raise(ApipieBindings::MissingArgumentsError)
|
48
|
+
e.message.must_match /: name$/
|
48
49
|
|
49
|
-
proc do
|
50
|
+
e = proc do
|
50
51
|
# completely different sub-hash; should still fail
|
51
52
|
resource.action(:create).validate!({ :organization => { :name => "acme" } })
|
52
53
|
end.must_raise(ApipieBindings::MissingArgumentsError)
|
54
|
+
e.message.must_match /: name$/
|
53
55
|
end
|
54
56
|
|
55
57
|
it "should accept correct params" do
|
data/test/unit/api_test.rb
CHANGED
@@ -17,9 +17,6 @@ describe ApipieBindings::API do
|
|
17
17
|
api.resources.map(&:name).must_equal [:architectures]
|
18
18
|
end
|
19
19
|
|
20
|
-
# it "should have apidoc_cache_file available" do
|
21
|
-
# end
|
22
|
-
|
23
20
|
it "should call the method" do
|
24
21
|
params = { :a => 1 }
|
25
22
|
headers = { :content_type => 'application/json' }
|
@@ -143,8 +140,54 @@ describe ApipieBindings::API do
|
|
143
140
|
|
144
141
|
it "should obey :apidoc_cache_base_dir to generate apidoc_cache_dir" do
|
145
142
|
Dir.mktmpdir do |dir|
|
146
|
-
api = ApipieBindings::API.new({:uri => 'http://example.com', :apidoc_cache_base_dir => dir})
|
147
|
-
api.apidoc_cache_file.must_equal File.join(dir, 'http___example.com', 'default.json')
|
143
|
+
api = ApipieBindings::API.new({:uri => 'http://example.com', :apidoc_cache_base_dir => dir, :api_version => 2})
|
144
|
+
api.apidoc_cache_file.must_equal File.join(dir, 'http___example.com', 'v2', 'default.json')
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context "credentials" do
|
150
|
+
|
151
|
+
let(:fake_empty_response) {
|
152
|
+
data = ApipieBindings::Example.new('', '', '', 200, '[]')
|
153
|
+
net_http_resp = Net::HTTPResponse.new(1.0, data.status, "")
|
154
|
+
RestClient::Response.create(data.response, net_http_resp, {})
|
155
|
+
}
|
156
|
+
|
157
|
+
it "should call credentials to_param when :credentials are set and doing authenticated call" do
|
158
|
+
Dir.mktmpdir do |dir|
|
159
|
+
credentials = ApipieBindings::AbstractCredentials.new
|
160
|
+
api = ApipieBindings::API.new({
|
161
|
+
:uri => 'http://example.com', :apidoc_cache_base_dir => dir, :api_version => 2,
|
162
|
+
:credentials => credentials})
|
163
|
+
credentials.expects(:to_params).returns({:password => 'xxx'})
|
164
|
+
api.stubs(:call_client).returns(fake_empty_response)
|
165
|
+
|
166
|
+
api.http_call(:get, '/path')
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should not require credentials for loading apidoc when :apidoc_authenticated => false" do
|
171
|
+
Dir.mktmpdir do |dir|
|
172
|
+
api = ApipieBindings::API.new({
|
173
|
+
:uri => 'http://example.com', :apidoc_cache_base_dir => dir, :api_version => 2,
|
174
|
+
:apidoc_authenticated => false })
|
175
|
+
api.expects(:unauthenticated_client)
|
176
|
+
api.stubs(:call_client).returns(fake_empty_response)
|
177
|
+
|
178
|
+
api.retrieve_apidoc
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should not require credentials for loading checksum when :apidoc_authenticated => false" do
|
183
|
+
Dir.mktmpdir do |dir|
|
184
|
+
api = ApipieBindings::API.new({
|
185
|
+
:uri => 'http://example.com', :apidoc_cache_base_dir => dir, :api_version => 2,
|
186
|
+
:apidoc_authenticated => false })
|
187
|
+
api.expects(:unauthenticated_client)
|
188
|
+
api.stubs(:call_client).returns(fake_empty_response)
|
189
|
+
|
190
|
+
api.check_cache
|
148
191
|
end
|
149
192
|
end
|
150
193
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apipie-bindings
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Bačovský
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-09
|
11
|
+
date: 2014-11-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -206,6 +206,7 @@ files:
|
|
206
206
|
- lib/apipie_bindings.rb
|
207
207
|
- lib/apipie_bindings/action.rb
|
208
208
|
- lib/apipie_bindings/api.rb
|
209
|
+
- lib/apipie_bindings/credentials.rb
|
209
210
|
- lib/apipie_bindings/example.rb
|
210
211
|
- lib/apipie_bindings/exceptions.rb
|
211
212
|
- lib/apipie_bindings/indifferent_hash.rb
|
@@ -229,7 +230,7 @@ files:
|
|
229
230
|
- test/unit/test_helper.rb
|
230
231
|
homepage: http://github.com/Apipie/apipie-bindings
|
231
232
|
licenses:
|
232
|
-
-
|
233
|
+
- MIT
|
233
234
|
metadata: {}
|
234
235
|
post_install_message:
|
235
236
|
rdoc_options: []
|
@@ -263,4 +264,3 @@ test_files:
|
|
263
264
|
- test/unit/resource_test.rb
|
264
265
|
- test/unit/route_test.rb
|
265
266
|
- test/unit/test_helper.rb
|
266
|
-
has_rdoc: yard
|