artifactory 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +11 -7
- data/CHANGELOG.md +18 -0
- data/README.md +25 -4
- data/Rakefile +5 -2
- data/artifactory.gemspec +0 -3
- data/lib/artifactory.rb +2 -4
- data/lib/artifactory/client.rb +210 -85
- data/lib/artifactory/configurable.rb +6 -1
- data/lib/artifactory/defaults.rb +52 -3
- data/lib/artifactory/errors.rb +21 -14
- data/lib/artifactory/resources/artifact.rb +132 -58
- data/lib/artifactory/resources/base.rb +120 -6
- data/lib/artifactory/resources/build.rb +2 -1
- data/lib/artifactory/resources/group.rb +5 -72
- data/lib/artifactory/resources/layout.rb +106 -0
- data/lib/artifactory/resources/repository.rb +62 -114
- data/lib/artifactory/resources/system.rb +5 -1
- data/lib/artifactory/resources/user.rb +5 -79
- data/lib/artifactory/util.rb +8 -2
- data/lib/artifactory/version.rb +1 -1
- data/spec/integration/resources/layout_spec.rb +22 -0
- data/spec/integration/resources/repository_spec.rb +7 -0
- data/spec/integration/resources/system_spec.rb +4 -4
- data/spec/support/api_server/repository_endpoints.rb +5 -0
- data/spec/support/api_server/system_endpoints.rb +18 -0
- data/spec/unit/client_spec.rb +17 -98
- data/spec/unit/resources/artifact_spec.rb +99 -13
- data/spec/unit/resources/build_spec.rb +1 -1
- data/spec/unit/resources/group_spec.rb +1 -1
- data/spec/unit/resources/layout_spec.rb +61 -0
- data/spec/unit/resources/repository_spec.rb +31 -47
- data/spec/unit/resources/system_spec.rb +4 -2
- data/spec/unit/resources/user_spec.rb +1 -1
- metadata +16 -40
- data/locales/en.yml +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f140751bb7b38da3e211b0c3fbd7332bb60754f3
|
4
|
+
data.tar.gz: cf32023c6d7ade23e0237828d4a2f25f6c4ed8aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bbc1d3688eee73f034dd8f39c62ad086555aea4345636f2654f428b5d1f89e4b92ee02fbc554187cb42057eaa6d02eb694a82f60afac33cd00987fc033406363
|
7
|
+
data.tar.gz: 139a0c2ac153c5440dae9d6893b081ad7730139f621ce36c393af81cb89d0a116bd6ff85d9395dd2a43017baa0bf2fbc03c811bc01edf41894298ceab4203d4d
|
data/.travis.yml
CHANGED
@@ -1,20 +1,24 @@
|
|
1
|
-
# Test on modern rubies
|
2
1
|
rvm:
|
3
2
|
- 1.9.3
|
4
3
|
- 2.0.0
|
5
|
-
- 2.1
|
4
|
+
- 2.1
|
6
5
|
|
7
|
-
# Setup parallel downloaders
|
8
6
|
bundler_args: --jobs 7
|
9
7
|
|
10
|
-
# Only test master (PRs are still tested)
|
11
8
|
branches:
|
12
9
|
only:
|
13
10
|
- master
|
14
11
|
|
15
|
-
|
12
|
+
script: bundle exec rake travis:ci
|
13
|
+
|
16
14
|
notifications:
|
17
15
|
hipchat:
|
16
|
+
on_change: true
|
17
|
+
on_failure: true
|
18
|
+
on_success: false
|
19
|
+
on_pull_requests: false
|
18
20
|
rooms:
|
19
|
-
|
20
|
-
- secure: fQEeBZSIV9mKpM5XeKxmvcgUb19skv3+qW6TiyvuPReB4B/mc5vf3AABWhbdnnHzjsKnq2iQtcppXVG0eJwuRM5D1werMO91zwSRNBU/ClOLHaYBp5l4tVkuHzAd3eo/Z67vxE0BAV9lGWeWv7r3y/BLgJ265nQMyfgZSyz1i44=
|
21
|
+
# Build Statuses
|
22
|
+
- secure: fQEeBZSIV9mKpM5XeKxmvcgUb19skv3+qW6TiyvuPReB4B/mc5vf3AABWhbdnnHzjsKnq2iQtcppXVG0eJwuRM5D1werMO91zwSRNBU/ClOLHaYBp5l4tVkuHzAd3eo/Z67vxE0BAV9lGWeWv7r3y/BLgJ265nQMyfgZSyz1i44=
|
23
|
+
# Release Engineering
|
24
|
+
- secure: eUtMt0CeB2bbIcTeQA3rUJsTtBkq/Ng5AnM59NOCzutcPTnNDeM4kNQEfgJ5QEZZkx08IXyiPJ14gEQUaV0bF0s0FLyzFxjlX9p2jem99FmEA404KJ7axoUiGGxgATbq9V7tUOrp1zG+a8xVQTahZASKadPlC9TSRgKqjUL+Dvg=
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,24 @@ Artifactory Client CHANGELOG
|
|
3
3
|
This file is used to document the changes between releases of the Artifactory
|
4
4
|
Ruby client.
|
5
5
|
|
6
|
+
v1.2.0 (2014-06-02)
|
7
|
+
-------------------
|
8
|
+
- Change the airty of Repository#find to align with other resources
|
9
|
+
- Add the ability to save/create repositories
|
10
|
+
- Remove i18n
|
11
|
+
- Make proxy configuration more verbose
|
12
|
+
- Remove HTTPClient in favor of raw Net::HTTP
|
13
|
+
- Add custom SSL configuration options
|
14
|
+
- Make Configurable#proxy_port a string because #ocd
|
15
|
+
- Allow file uploads
|
16
|
+
- Return an Artifact object after uploading
|
17
|
+
- Allow repositories to be deleted
|
18
|
+
- Add required attribute for repository layout
|
19
|
+
- Move upload method from Repository to Artifact
|
20
|
+
- Implement Repository.upload via Artifact.upload
|
21
|
+
- Move to_matrix_properties method to base class
|
22
|
+
- Add the ability to list/find repository layouts from xml configuration
|
23
|
+
- Specify content-type for updating config
|
6
24
|
|
7
25
|
v1.1.0 (2014-02-11)
|
8
26
|
-------------------
|
data/README.md
CHANGED
@@ -6,6 +6,8 @@ A Ruby client and interface to the Artifactory API. **The majority of API endpoi
|
|
6
6
|
|
7
7
|
The Artifactory gem offers a convienent interface for managing various parts of the Artifactory API. It is not a complete API implementation, and should still be considered a work in progress.
|
8
8
|
|
9
|
+
This project is managed by the CHEF Release Engineering team. For more information on the Release Engineering team's contribution, triage, and release process, please consult the [CHEF Release Engineering OSS Management Guide](https://docs.google.com/a/opscode.com/document/d/1oJB0vZb_3bl7_ZU2YMDBkMFdL-EWplW1BJv_FXTUOzg/edit).
|
10
|
+
|
9
11
|
|
10
12
|
Quick start
|
11
13
|
-----------
|
@@ -54,9 +56,20 @@ Artifactory.configure do |config|
|
|
54
56
|
config.username = 'admin'
|
55
57
|
config.password = 'password'
|
56
58
|
|
59
|
+
# Speaking of SSL, you can specify the path to a pem file with your custom
|
60
|
+
# certificates and the gem will wire it all up for you (NOTE: it must be a
|
61
|
+
# valid PEM file).
|
62
|
+
config.ssl_pem_file = '/path/to/my.pem'
|
63
|
+
|
64
|
+
# Or if you are feelying frisky, you can always disable SSL verification
|
65
|
+
config.ssl_verify = false
|
66
|
+
|
57
67
|
# You can specify any proxy information, including any authentication
|
58
68
|
# information in the URL.
|
59
|
-
config.
|
69
|
+
config.proxy_username = 'user'
|
70
|
+
config.proxy_password = 'password'
|
71
|
+
config.proxy_address = 'my.proxy.server'
|
72
|
+
config.proxy_port = '8080'
|
60
73
|
end
|
61
74
|
```
|
62
75
|
|
@@ -73,6 +86,7 @@ Or, if you want to be really Unixy, these parameters are all configurable via en
|
|
73
86
|
export ARTIFACTORY_ENDPOINT=http://my.storage.server/artifactory
|
74
87
|
export ARTIFACTORY_USERNAME=admin
|
75
88
|
export ARTIFACTORY_PASSWORD=password
|
89
|
+
export ARTIFACTORY_SSL_PEM_FILE=/path/to/my.pem
|
76
90
|
```
|
77
91
|
|
78
92
|
You can also create a full `Client` object with hash parameters:
|
@@ -82,10 +96,13 @@ client = Artifactory::Client.new(endpoint: '...', username: '...')
|
|
82
96
|
```
|
83
97
|
|
84
98
|
### Making requests
|
85
|
-
The Artifactory gem attempts to make the Artifactory API as object-oriented and Ruby-like as possible. All of the methods and API calls are heavily documented with examples inline using YARD. In order to keep the examples versioned with the code, the README only lists a few examples for using the Artifactory gem. Please see the inline documentation for the full API documentation.
|
99
|
+
The Artifactory gem attempts to make the Artifactory API as object-oriented and Ruby-like as possible. All of the methods and API calls are heavily documented with examples inline using YARD. In order to keep the examples versioned with the code, the README only lists a few examples for using the Artifactory gem. Please see the inline documentation for the full API documentation. The tests in the 'spec' directory are an additional source of examples.
|
86
100
|
|
87
101
|
#### Artifacts
|
88
102
|
```ruby
|
103
|
+
# Upload an artifact to a repository whose key is 'repo_key'
|
104
|
+
artifact.upload('/local/path/to/file', 'repo_key', param_1: 'foo')
|
105
|
+
|
89
106
|
# Search for an artifact by name
|
90
107
|
artifact = Artifact.search(name: 'package.deb').first
|
91
108
|
artifact #=> "#<Artifactory::Resource::Artifact md5: 'ABCD1234'>"
|
@@ -123,6 +140,10 @@ repo #=> #<Artifactory::Resource::Repository ...>
|
|
123
140
|
# Get information about the repository
|
124
141
|
repo.description => "The default storage mechanism for..."
|
125
142
|
|
143
|
+
# Change the repository
|
144
|
+
repo.description = "This is a new description"
|
145
|
+
repo.save
|
146
|
+
|
126
147
|
# Upload an artifact to the repo
|
127
148
|
repo.upload('/local/path/to/file', param_1: 'foo', param_2: 'bar')
|
128
149
|
|
@@ -155,8 +176,8 @@ client.get('/some/special/path', param_1: 'foo', param_2: 'bar')
|
|
155
176
|
|
156
177
|
For more information on the methods available, please see the [`Artifactory::Client` class](https://github.com/opscode/artifactory-client/blob/master/lib/artifactory/client.rb).
|
157
178
|
|
158
|
-
###
|
159
|
-
If you plan to use the Artifactory gem in a library, you should be aware that _certain_ pathways for accessing resources
|
179
|
+
### Threadsafety
|
180
|
+
If you plan to use the Artifactory gem in a library, you should be aware that _certain_ pathways for accessing resources are **not** threadsafe. In order to deliver a "Rails-like" experience, accessing a resource without a client object uses a global shared state. Other threads may modify this state, and therefore we do **not** recommend using the Rails-like approach if you are concerned about threadsafety. The following code snippet may better explain the differences:
|
160
181
|
|
161
182
|
```ruby
|
162
183
|
# In our current thread...
|
data/Rakefile
CHANGED
data/artifactory.gemspec
CHANGED
@@ -20,9 +20,6 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
21
|
spec.require_paths = ['lib']
|
22
22
|
|
23
|
-
spec.add_dependency 'httpclient', '~> 2.3'
|
24
|
-
spec.add_dependency 'i18n', '~> 0.5'
|
25
|
-
|
26
23
|
spec.add_development_dependency 'bundler'
|
27
24
|
spec.add_development_dependency 'rake'
|
28
25
|
end
|
data/lib/artifactory.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'pathname'
|
1
2
|
require 'artifactory/version'
|
2
3
|
|
3
4
|
module Artifactory
|
@@ -17,6 +18,7 @@ module Artifactory
|
|
17
18
|
autoload :Base, 'artifactory/resources/base'
|
18
19
|
autoload :Build, 'artifactory/resources/build'
|
19
20
|
autoload :Group, 'artifactory/resources/group'
|
21
|
+
autoload :Layout, 'artifactory/resources/layout'
|
20
22
|
autoload :Plugin, 'artifactory/resources/plugin'
|
21
23
|
autoload :Repository, 'artifactory/resources/repository'
|
22
24
|
autoload :System, 'artifactory/resources/system'
|
@@ -70,9 +72,5 @@ module Artifactory
|
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|
73
|
-
require 'i18n'
|
74
|
-
I18n.enforce_available_locales = false
|
75
|
-
I18n.load_path << Dir[Artifactory.root.join('locales', '*.yml').to_s]
|
76
|
-
|
77
75
|
# Load the initial default values
|
78
76
|
Artifactory.setup
|
data/lib/artifactory/client.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
require 'httpclient'
|
2
1
|
require 'json'
|
3
|
-
require '
|
2
|
+
require 'net/http'
|
4
3
|
require 'uri'
|
5
4
|
|
6
5
|
module Artifactory
|
@@ -33,6 +32,7 @@ module Artifactory
|
|
33
32
|
include Artifactory::Configurable
|
34
33
|
|
35
34
|
proxy Resource::Artifact
|
35
|
+
proxy Resource::Layout
|
36
36
|
proxy Resource::Repository
|
37
37
|
proxy Resource::User
|
38
38
|
proxy Resource::System
|
@@ -68,137 +68,245 @@ module Artifactory
|
|
68
68
|
#
|
69
69
|
# Make a HTTP GET request
|
70
70
|
#
|
71
|
-
# @param
|
72
|
-
#
|
71
|
+
# @param path (see Client#request)
|
72
|
+
# @param [Hash] params
|
73
|
+
# the list of query params
|
74
|
+
# @param headers (see Client#request)
|
75
|
+
#
|
76
|
+
# @raise (see Client#request)
|
77
|
+
# @return (see Client#request)
|
73
78
|
#
|
74
|
-
def get(path,
|
75
|
-
request(:get, path,
|
79
|
+
def get(path, params = {}, headers = {})
|
80
|
+
request(:get, path, params, headers)
|
76
81
|
end
|
77
82
|
|
78
83
|
#
|
79
84
|
# Make a HTTP POST request
|
80
85
|
#
|
81
|
-
# @param
|
82
|
-
#
|
86
|
+
# @param path (see Client#request)
|
87
|
+
# @param [String, #read] data
|
88
|
+
# the body to use for the request
|
89
|
+
# @param headers (see Client#request)
|
90
|
+
#
|
91
|
+
# @raise (see Client#request)
|
92
|
+
# @return (see Client#request)
|
83
93
|
#
|
84
|
-
def post(path,
|
85
|
-
request(:post, path,
|
94
|
+
def post(path, data, headers = {})
|
95
|
+
request(:post, path, data, headers)
|
86
96
|
end
|
87
97
|
|
88
98
|
#
|
89
99
|
# Make a HTTP PUT request
|
90
100
|
#
|
91
|
-
# @param
|
92
|
-
#
|
101
|
+
# @param path (see Client#request)
|
102
|
+
# @param data (see Client#post)
|
103
|
+
# @param headers (see Client#request)
|
104
|
+
#
|
105
|
+
# @raise (see Client#request)
|
106
|
+
# @return (see Client#request)
|
93
107
|
#
|
94
|
-
def put(path,
|
95
|
-
request(:put, path,
|
108
|
+
def put(path, data, headers = {})
|
109
|
+
request(:put, path, data, headers)
|
96
110
|
end
|
97
111
|
|
98
112
|
#
|
99
113
|
# Make a HTTP PATCH request
|
100
114
|
#
|
101
|
-
# @param
|
102
|
-
#
|
115
|
+
# @param path (see Client#request)
|
116
|
+
# @param data (see Client#post)
|
117
|
+
# @param headers (see Client#request)
|
118
|
+
#
|
119
|
+
# @raise (see Client#request)
|
120
|
+
# @return (see Client#request)
|
103
121
|
#
|
104
|
-
def patch(path,
|
105
|
-
request(:patch, path,
|
122
|
+
def patch(path, data, headers = {})
|
123
|
+
request(:patch, path, data, headers)
|
106
124
|
end
|
107
125
|
|
108
126
|
#
|
109
127
|
# Make a HTTP DELETE request
|
110
128
|
#
|
111
|
-
# @param
|
112
|
-
#
|
129
|
+
# @param path (see Client#request)
|
130
|
+
# @param params (see Client#get)
|
131
|
+
# @param headers (see Client#request)
|
132
|
+
#
|
133
|
+
# @raise (see Client#request)
|
134
|
+
# @return (see Client#request)
|
113
135
|
#
|
114
|
-
def delete(path,
|
115
|
-
request(:delete, path,
|
136
|
+
def delete(path, params = {}, headers = {})
|
137
|
+
request(:delete, path, params, headers)
|
116
138
|
end
|
117
139
|
|
118
140
|
#
|
119
|
-
# Make
|
120
|
-
#
|
121
|
-
#
|
122
|
-
# the path to head, relative to {Defaults.endpoint}
|
141
|
+
# Make an HTTP request with the given verb, data, params, and headers. If
|
142
|
+
# the response has a return type of JSON, the JSON is automatically parsed
|
143
|
+
# and returned as a hash; otherwise it is returned as a string.
|
123
144
|
#
|
124
|
-
|
125
|
-
|
126
|
-
end
|
127
|
-
|
145
|
+
# @raise [Error::HTTPError]
|
146
|
+
# if the request is not an HTTP 200 OK
|
128
147
|
#
|
129
|
-
#
|
148
|
+
# @param [Symbol] verb
|
149
|
+
# the lowercase symbol of the HTTP verb (e.g. :get, :delete)
|
150
|
+
# @param [String] path
|
151
|
+
# the absolute or relative path from {Defaults.endpoint} to make the
|
152
|
+
# request against
|
153
|
+
# @param [#read, Hash, nil] data
|
154
|
+
# the data to use (varies based on the +verb+)
|
155
|
+
# @param [Hash] headers
|
156
|
+
# the list of headers to use
|
130
157
|
#
|
131
|
-
# @return [
|
158
|
+
# @return [String, Hash]
|
159
|
+
# the response body
|
132
160
|
#
|
133
|
-
def
|
134
|
-
|
135
|
-
|
161
|
+
def request(verb, path, data = {}, headers = {})
|
162
|
+
# Build the URI and request object from the given information
|
163
|
+
uri = build_uri(verb, path, data)
|
164
|
+
request = class_for_request(verb).new(uri.request_uri)
|
136
165
|
|
137
|
-
|
166
|
+
# Add headers
|
167
|
+
default_headers.merge(headers).each do |key, value|
|
168
|
+
request.add_field(key, value)
|
169
|
+
end
|
138
170
|
|
139
|
-
|
140
|
-
|
141
|
-
|
171
|
+
# Add basic authentication
|
172
|
+
if username && password
|
173
|
+
request.basic_auth(username, password)
|
174
|
+
end
|
142
175
|
|
143
|
-
|
144
|
-
|
176
|
+
# Setup PATCH/POST/PUT
|
177
|
+
if [:patch, :post, :put].include?(verb)
|
178
|
+
if data.respond_to?(:read)
|
179
|
+
request.body_stream = data
|
180
|
+
elsif data.is_a?(Hash)
|
181
|
+
request.form_data = data
|
182
|
+
else
|
183
|
+
request.body = data
|
145
184
|
end
|
185
|
+
end
|
146
186
|
|
147
|
-
|
148
|
-
|
149
|
-
|
187
|
+
# Create the HTTP connection object - since the proxy information defaults
|
188
|
+
# to +nil+, we can just pass it to the initializer method instead of doing
|
189
|
+
# crazy strange conditionals.
|
190
|
+
connection = Net::HTTP.new(uri.host, uri.port,
|
191
|
+
proxy_address, proxy_port, proxy_username, proxy_password)
|
192
|
+
|
193
|
+
# Apply SSL, if applicable
|
194
|
+
if uri.scheme == 'https'
|
195
|
+
require 'net/https' unless defined?(Net::HTTPS)
|
196
|
+
|
197
|
+
# Turn on SSL
|
198
|
+
connection.use_ssl = true
|
199
|
+
|
200
|
+
# Custom pem files, no problem!
|
201
|
+
if ssl_pem_file
|
202
|
+
pem = File.read(ssl_pem_file)
|
203
|
+
connection.cert = OpenSSL::X509::Certificate.new(pem)
|
204
|
+
connection.key = OpenSSL::PKey::RSA.new(pem)
|
205
|
+
connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
150
206
|
end
|
151
207
|
|
152
|
-
|
208
|
+
# Naughty, naughty, naughty! Don't blame when when someone hops in
|
209
|
+
# and executes a MITM attack!
|
210
|
+
unless ssl_verify
|
211
|
+
connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
212
|
+
end
|
153
213
|
end
|
214
|
+
|
215
|
+
# Create a connection using the block form, which will ensure the socket
|
216
|
+
# is properly closed in the event of an error.
|
217
|
+
connection.start do |http|
|
218
|
+
response = http.request(request)
|
219
|
+
|
220
|
+
case response
|
221
|
+
when Net::HTTPRedirection
|
222
|
+
redirect = URI.parse(response['location'])
|
223
|
+
request(verb, redirect, params, headers)
|
224
|
+
when Net::HTTPSuccess
|
225
|
+
success(response)
|
226
|
+
else
|
227
|
+
error(response)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
rescue SocketError, Errno::ECONNREFUSED, EOFError
|
231
|
+
raise Error::ConnectionError.new(endpoint)
|
232
|
+
end
|
233
|
+
|
234
|
+
#
|
235
|
+
# The list of default headers (such as Keep-Alive and User-Agent) for the
|
236
|
+
# client object.
|
237
|
+
#
|
238
|
+
# @return [Hash]
|
239
|
+
#
|
240
|
+
def default_headers
|
241
|
+
{
|
242
|
+
'Connection' => 'keep-alive',
|
243
|
+
'Keep-Alive' => '30',
|
244
|
+
'User-Agent' => user_agent,
|
245
|
+
}
|
154
246
|
end
|
155
247
|
|
156
248
|
#
|
157
|
-
#
|
249
|
+
# Construct a URL from the given verb and path. If the request is a GET or
|
250
|
+
# DELETE request, the params are assumed to be query params are are
|
251
|
+
# converted as such using {Client#to_query_string}.
|
158
252
|
#
|
159
|
-
#
|
160
|
-
#
|
253
|
+
# If the path is relative, it is merged with the {Defaults.endpoint}
|
254
|
+
# attribute. If the path is absolute, it is converted to a URI object and
|
255
|
+
# returned.
|
256
|
+
#
|
257
|
+
# @param [Symbol] verb
|
258
|
+
# the lowercase HTTP verb (e.g. :+get+)
|
161
259
|
# @param [String] path
|
162
|
-
# the absolute or relative
|
260
|
+
# the absolute or relative HTTP path (url) to get
|
261
|
+
# @param [Hash] params
|
262
|
+
# the list of params to build the URI with (for GET and DELETE requests)
|
163
263
|
#
|
164
|
-
# @return [
|
264
|
+
# @return [URI]
|
165
265
|
#
|
166
|
-
def
|
167
|
-
|
266
|
+
def build_uri(verb, path, params = {})
|
267
|
+
# Add any query string parameters
|
268
|
+
if [:delete, :get].include?(verb)
|
269
|
+
path = [path, to_query_string(params)].compact.join('?')
|
270
|
+
end
|
271
|
+
|
272
|
+
# Parse the URI
|
273
|
+
uri = URI.parse(path)
|
168
274
|
|
169
275
|
# Don't merge absolute URLs
|
170
|
-
unless
|
171
|
-
url = URI.parse(File.join(endpoint, path)).to_s
|
172
|
-
end
|
276
|
+
uri = URI.parse(File.join(endpoint, path)) unless uri.absolute?
|
173
277
|
|
174
|
-
#
|
175
|
-
|
176
|
-
|
177
|
-
# Make the actual request
|
178
|
-
response = agent.send(verb, url, *args, &block)
|
179
|
-
|
180
|
-
case response.status.to_i
|
181
|
-
when 200..399
|
182
|
-
parse_response(response)
|
183
|
-
when 400
|
184
|
-
raise Error::BadRequest.new(url: url, body: response.body)
|
185
|
-
when 401
|
186
|
-
raise Error::Unauthorized.new(url: url)
|
187
|
-
when 403
|
188
|
-
raise Error::Forbidden.new(url: url)
|
189
|
-
when 404
|
190
|
-
raise Error::NotFound.new(url: url)
|
191
|
-
when 405
|
192
|
-
raise Error::MethodNotAllowed.new(url: url)
|
193
|
-
else
|
194
|
-
raise Error::ConnectionError.new(url: url, body: response.body)
|
195
|
-
end
|
196
|
-
rescue SocketError, Errno::ECONNREFUSED, EOFError
|
197
|
-
raise Error::ConnectionError.new(url: url, body: <<-EOH.gsub(/^ {8}/, ''))
|
198
|
-
The server is not currently accepting connections.
|
199
|
-
EOH
|
278
|
+
# Return the URI object
|
279
|
+
uri
|
200
280
|
end
|
201
281
|
|
282
|
+
#
|
283
|
+
# Helper method to get the corresponding {Net::HTTP} class from the given
|
284
|
+
# HTTP verb.
|
285
|
+
#
|
286
|
+
# @param [#to_s] verb
|
287
|
+
# the HTTP verb to create a class from
|
288
|
+
#
|
289
|
+
# @return [Class]
|
290
|
+
#
|
291
|
+
def class_for_request(verb)
|
292
|
+
Net::HTTP.const_get(verb.to_s.capitalize)
|
293
|
+
end
|
294
|
+
|
295
|
+
#
|
296
|
+
# Convert the given hash to a list of query string parameters. Each key and
|
297
|
+
# value in the hash is URI-escaped for safety.
|
298
|
+
#
|
299
|
+
# @param [Hash] hash
|
300
|
+
# the hash to create the query string from
|
301
|
+
#
|
302
|
+
# @return [String, nil]
|
303
|
+
# the query string as a string, or +nil+ if there are no params
|
304
|
+
#
|
305
|
+
def to_query_string(hash)
|
306
|
+
hash.map do |key, value|
|
307
|
+
"#{URI.escape(key.to_s)}=#{URI.escape(value.to_s)}"
|
308
|
+
end.join('&')[/.+/]
|
309
|
+
end
|
202
310
|
|
203
311
|
#
|
204
312
|
# Parse the response object and manipulate the result based on the given
|
@@ -211,14 +319,31 @@ module Artifactory
|
|
211
319
|
# @return [String, Hash]
|
212
320
|
# the parsed response, as an object
|
213
321
|
#
|
214
|
-
def
|
215
|
-
content_type
|
216
|
-
|
217
|
-
if content_type && content_type.include?('json')
|
322
|
+
def success(response)
|
323
|
+
if (response.content_type || '').include?('json')
|
218
324
|
JSON.parse(response.body)
|
219
325
|
else
|
220
326
|
response.body
|
221
327
|
end
|
222
328
|
end
|
329
|
+
|
330
|
+
#
|
331
|
+
# Raise a response error, extracting as much information from the server's
|
332
|
+
# response as possible.
|
333
|
+
#
|
334
|
+
# @raise [Error::HTTPError]
|
335
|
+
#
|
336
|
+
# @param [HTTP::Message] response
|
337
|
+
# the response object from the request
|
338
|
+
#
|
339
|
+
def error(response)
|
340
|
+
error = JSON.parse(response.body)['errors'].first
|
341
|
+
raise Error::HTTPError.new(error)
|
342
|
+
rescue JSON::ParserError
|
343
|
+
raise Error::HTTPError.new(
|
344
|
+
'status' => response.code,
|
345
|
+
'message' => response.body,
|
346
|
+
)
|
347
|
+
end
|
223
348
|
end
|
224
349
|
end
|