artifactory_api 0.1.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 +7 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +37 -0
- data/README.md +6 -0
- data/Rakefile +43 -0
- data/lib/artifactory_api.rb +8 -0
- data/lib/artifactory_api/artifacts.rb +35 -0
- data/lib/artifactory_api/builds.rb +57 -0
- data/lib/artifactory_api/client.rb +242 -0
- data/lib/artifactory_api/exceptions.rb +70 -0
- data/lib/artifactory_api/version.rb +14 -0
- data/spec/builds_spec.rb +81 -0
- data/spec/client_spec.rb +83 -0
- data/spec/spec_helper.rb +12 -0
- metadata +101 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 292f834fe01f7e90f6e0b8e2f0d67afab066f9fc
|
|
4
|
+
data.tar.gz: 492a47063e8101ad28a9218d234f198c1446dbb8
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 2ada15a767456c235450b4e2b1109e6cbbe2d2173d64361dd2f598b2f9d28c45d2d0407bc8c7376021c4d43361400f638dfb10e3b049e641faee16e84c344e88
|
|
7
|
+
data.tar.gz: 65e54220c99d42e288141a5ba3722a85e6875e2269efa9120bb3ce9ac95e991150c1c795e4fbc05a4a617ba4dd259f08c4e6ce7e5aaabcc412d9b207d9f9d7cf
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: ../artifactory_api
|
|
3
|
+
specs:
|
|
4
|
+
artifactory_api (0.1.4)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: http://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
builder (3.2.2)
|
|
10
|
+
diff-lcs (1.2.5)
|
|
11
|
+
rake (10.1.1)
|
|
12
|
+
rspec (3.2.0)
|
|
13
|
+
rspec-core (~> 3.2.0)
|
|
14
|
+
rspec-expectations (~> 3.2.0)
|
|
15
|
+
rspec-mocks (~> 3.2.0)
|
|
16
|
+
rspec-core (3.2.0)
|
|
17
|
+
rspec-support (~> 3.2.0)
|
|
18
|
+
rspec-expectations (3.2.0)
|
|
19
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
20
|
+
rspec-support (~> 3.2.0)
|
|
21
|
+
rspec-mocks (3.2.0)
|
|
22
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
23
|
+
rspec-support (~> 3.2.0)
|
|
24
|
+
rspec-support (3.2.1)
|
|
25
|
+
rubygems-tasks (0.2.4)
|
|
26
|
+
|
|
27
|
+
PLATFORMS
|
|
28
|
+
java
|
|
29
|
+
ruby
|
|
30
|
+
|
|
31
|
+
DEPENDENCIES
|
|
32
|
+
artifactory_api!
|
|
33
|
+
builder
|
|
34
|
+
bundler (~> 1.8.0)
|
|
35
|
+
rake (~> 10.1.0)
|
|
36
|
+
rspec
|
|
37
|
+
rubygems-tasks (~> 0.2)
|
data/README.md
ADDED
data/Rakefile
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
# encoding: utf-8
|
|
4
|
+
|
|
5
|
+
require 'rubygems'
|
|
6
|
+
|
|
7
|
+
begin
|
|
8
|
+
require 'bundler'
|
|
9
|
+
rescue LoadError => e
|
|
10
|
+
warn e.message
|
|
11
|
+
warn "Run `gem install bundler` to install Bundler."
|
|
12
|
+
exit -1
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
begin
|
|
16
|
+
Bundler.setup(:development)
|
|
17
|
+
rescue Bundler::BundlerError => e
|
|
18
|
+
warn e.message
|
|
19
|
+
warn "Run `bundle install` to install missing gems."
|
|
20
|
+
exit e.status_code
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
require 'rake'
|
|
24
|
+
|
|
25
|
+
require 'rubygems/tasks'
|
|
26
|
+
Gem::Tasks.new
|
|
27
|
+
|
|
28
|
+
# require 'cucumber/rake/task'
|
|
29
|
+
#
|
|
30
|
+
# Cucumber::Rake::Task.new do |t|
|
|
31
|
+
# t.cucumber_opts = %w[--format pretty]
|
|
32
|
+
# end
|
|
33
|
+
|
|
34
|
+
task :default => [:test]
|
|
35
|
+
task :spec => :test
|
|
36
|
+
|
|
37
|
+
require 'rspec/core'
|
|
38
|
+
require 'rspec/core/rake_task'
|
|
39
|
+
|
|
40
|
+
RSpec::Core::RakeTask.new(:test) do |spec|
|
|
41
|
+
spec.pattern = FileList['spec/**/*.rb']
|
|
42
|
+
end
|
|
43
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module ArtifactoryApi
|
|
2
|
+
class Client
|
|
3
|
+
class Artifacts
|
|
4
|
+
def initialize(client)
|
|
5
|
+
@client = client
|
|
6
|
+
@logger = @client.logger
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def to_s
|
|
10
|
+
"#<ArtifactoryApi::Clients::Builds>"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def deploy_artifact repo, path, file
|
|
14
|
+
url = "/#{repo}#{path}"
|
|
15
|
+
@client.api_put_request url, file
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def retrieve_artifact repo, path
|
|
19
|
+
url = "/#{repo}#{path}"
|
|
20
|
+
response = @client.api_get_request url, raw_response=true
|
|
21
|
+
response.body
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def artifact_info repo, path
|
|
25
|
+
url = "/api/storage/#{repo}#{path}"
|
|
26
|
+
@client.api_get_request url
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def copy_artifact from_repo, from_path, to_repo, to_path
|
|
30
|
+
url = "/api/copy/#{from_repo}#{from_path}?to=/#{to_repo}#{to_path}"
|
|
31
|
+
@client.api_post_request url
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
|
|
2
|
+
module ArtifactoryApi
|
|
3
|
+
class Client
|
|
4
|
+
class Builds
|
|
5
|
+
def initialize(client)
|
|
6
|
+
@client = client
|
|
7
|
+
@logger = @client.logger
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_s
|
|
11
|
+
"#<ArtifactoryApi::Client::Builds"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
#Returns an array of hashes, containing a "name" key and a "last_built" key
|
|
15
|
+
#The api returns build names with a starting slash, this will remove them.
|
|
16
|
+
def list_all
|
|
17
|
+
response_json = @client.api_get_request("/api/build")
|
|
18
|
+
|
|
19
|
+
return nil unless response_json
|
|
20
|
+
|
|
21
|
+
response_json["builds"].map do |build|
|
|
22
|
+
{
|
|
23
|
+
:name => build["uri"].sub(/^\//,''),
|
|
24
|
+
:uri => build["uri"],
|
|
25
|
+
:lastStarted => build["lastStarted"]
|
|
26
|
+
}
|
|
27
|
+
end.sort{ |x,y| x[:name] <=> y[:name]}
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def get_runs_for_build build
|
|
32
|
+
response_json = @client.api_get_request("/api/build/#{build}")
|
|
33
|
+
return nil unless response_json
|
|
34
|
+
|
|
35
|
+
response_json["buildsNumbers"].map do |build|
|
|
36
|
+
{
|
|
37
|
+
:number => build["uri"].sub(/^\//,''),
|
|
38
|
+
:uri => build["uri"],
|
|
39
|
+
:started => build["started"]
|
|
40
|
+
}
|
|
41
|
+
end.sort{|x,y| x[:number].to_i <=> y[:number].to_i}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def get_run_info build,run
|
|
45
|
+
response_json = @client.api_get_request("/api/build/#{build}/#{run}")
|
|
46
|
+
return nil unless response_json
|
|
47
|
+
result = response_json["buildInfo"]
|
|
48
|
+
result[:number] = result["number"]
|
|
49
|
+
result[:name] = result["name"]
|
|
50
|
+
result
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def diffs_for_build_run build, to_run, from_run
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
require 'base64'
|
|
3
|
+
require 'uri'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'net/http'
|
|
6
|
+
require 'net/https'
|
|
7
|
+
|
|
8
|
+
module ArtifactoryApi
|
|
9
|
+
class Client
|
|
10
|
+
attr_accessor :logger
|
|
11
|
+
|
|
12
|
+
DEFAULT_SERVER_PORT = 80
|
|
13
|
+
|
|
14
|
+
VALID_PARAMS = [
|
|
15
|
+
"server_url",
|
|
16
|
+
"server_ip",
|
|
17
|
+
"server_port",
|
|
18
|
+
"artifactory_path",
|
|
19
|
+
"username",
|
|
20
|
+
"password",
|
|
21
|
+
"password_base64",
|
|
22
|
+
"log_location",
|
|
23
|
+
"log_level",
|
|
24
|
+
"ssl",
|
|
25
|
+
"follow_redirects"
|
|
26
|
+
].freeze
|
|
27
|
+
|
|
28
|
+
def initialize(args)
|
|
29
|
+
args.each do |key, value|
|
|
30
|
+
if value && VALID_PARAMS.include?(key.to_s)
|
|
31
|
+
instance_variable_set("@#{key}", value)
|
|
32
|
+
end
|
|
33
|
+
end if args.is_a? Hash
|
|
34
|
+
|
|
35
|
+
# Server IP or Server URL must be specified
|
|
36
|
+
unless @server_ip || @server_url
|
|
37
|
+
raise ArgumentError, "Server IP or Server URL is required to connect" +
|
|
38
|
+
" to Artifactory"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Username/password are optional as some artifactory servers do not require
|
|
42
|
+
# authentication
|
|
43
|
+
if @username && !(@password || @password_base64)
|
|
44
|
+
raise ArgumentError, "If username is provided, password is required"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Get info from the server_url, if we got one
|
|
48
|
+
if @server_url
|
|
49
|
+
server_uri = URI.parse(@server_url)
|
|
50
|
+
@server_ip = server_uri.host
|
|
51
|
+
@server_port = server_uri.port
|
|
52
|
+
@ssl = server_uri.scheme == "https"
|
|
53
|
+
@artifactory_path = server_uri.path
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
@artifactory_path ||= ""
|
|
57
|
+
@artifactory_path.gsub!(/\/$/, "") # remove trailing slash if there is one
|
|
58
|
+
|
|
59
|
+
@server_port = DEFAULT_SERVER_PORT unless @server_port
|
|
60
|
+
@ssl ||= false
|
|
61
|
+
|
|
62
|
+
# Setting log options
|
|
63
|
+
@log_location = STDOUT unless @log_location
|
|
64
|
+
@log_level = Logger::INFO unless @log_level
|
|
65
|
+
@logger = Logger.new(@log_location)
|
|
66
|
+
@logger.level = @log_level
|
|
67
|
+
|
|
68
|
+
# Base64 decode inserts a newline character at the end. As a workaround
|
|
69
|
+
# added chomp to remove newline characters. I hope nobody uses newline
|
|
70
|
+
# characters at the end of their passwords :)
|
|
71
|
+
@password = Base64.decode64(@password_base64).chomp if @password_base64
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def builds
|
|
76
|
+
ArtifactoryApi::Client::Builds.new(self)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def artifacts
|
|
80
|
+
ArtifactoryApi::Client::Artifacts.new(self)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Returns a string representing the class name
|
|
84
|
+
#
|
|
85
|
+
# @return [String] string representation of class name
|
|
86
|
+
#
|
|
87
|
+
def to_s
|
|
88
|
+
"#<ArtifactoryApi::Client>"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Connects to the Artifactory server, sends the specified request and returns
|
|
92
|
+
# the response.
|
|
93
|
+
#
|
|
94
|
+
# @param [Net::HTTPRequest] request The request object to send
|
|
95
|
+
# @param [Boolean] follow_redirect whether to follow redirects or not
|
|
96
|
+
#
|
|
97
|
+
# @return [Net::HTTPResponse] Response from Jenkins
|
|
98
|
+
#
|
|
99
|
+
def make_http_request(request, follow_redirect = @follow_redirects)
|
|
100
|
+
request.basic_auth @username, @password if @username
|
|
101
|
+
|
|
102
|
+
http = Net::HTTP.new(@server_ip, @server_port)
|
|
103
|
+
|
|
104
|
+
if @ssl
|
|
105
|
+
http.use_ssl = true
|
|
106
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
response = http.request(request)
|
|
110
|
+
case response
|
|
111
|
+
when Net::HTTPRedirection then
|
|
112
|
+
# If we got a redirect request, follow it (if flag set), but don't
|
|
113
|
+
# go any deeper (only one redirect supported - don't want to follow
|
|
114
|
+
# our tail)
|
|
115
|
+
if follow_redirect
|
|
116
|
+
redir_uri = URI.parse(response['location'])
|
|
117
|
+
response = make_http_request(
|
|
118
|
+
Net::HTTP::Get.new(redir_uri.path, false)
|
|
119
|
+
)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
return response
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
protected :make_http_request
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# Sends a GET request to the Artifactory server with the specified URL
|
|
129
|
+
#
|
|
130
|
+
# @param [String] url_prefix The prefix to use in the URL
|
|
131
|
+
# @param [Boolean] raw_response Return complete Response object instead of
|
|
132
|
+
# JSON body of response
|
|
133
|
+
#
|
|
134
|
+
# @return [String, JSON] JSON response from Jenkins
|
|
135
|
+
#
|
|
136
|
+
def api_get_request(url_prefix, raw_response = false)
|
|
137
|
+
url_prefix = "#{@artifactory_path}#{url_prefix}"
|
|
138
|
+
to_get = URI.escape(url_prefix)
|
|
139
|
+
request = Net::HTTP::Get.new(to_get)
|
|
140
|
+
@logger.info "GET #{to_get}"
|
|
141
|
+
exec_request(request, raw_response)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Sends a PUT request to the Artifactory server with the specified URL
|
|
145
|
+
def api_put_request(url_prefix, data, raw_response = false)
|
|
146
|
+
url_prefix = "#{@artifactory_path}#{url_prefix}"
|
|
147
|
+
to_put = URI.escape(url_prefix)
|
|
148
|
+
request = Net::HTTP::Put.new(to_put)
|
|
149
|
+
request.body = data
|
|
150
|
+
@logger.info "PUT #{to_put}"
|
|
151
|
+
exec_request(request, raw_response, data)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Sends a POST request to the Artifactory server with the specified URL
|
|
155
|
+
def api_post_request(url_prefix, raw_response = false, data=nil)
|
|
156
|
+
url_prefix = "#{@artifactory_path}#{url_prefix}"
|
|
157
|
+
to_post = URI.escape(url_prefix)
|
|
158
|
+
request = Net::HTTP::Post.new(to_post)
|
|
159
|
+
@logger.info "POST #{to_post}"
|
|
160
|
+
exec_request(request, raw_response, data)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
#
|
|
164
|
+
# @param [Net::HTTP::Get Put or Post] request
|
|
165
|
+
# @param [Boolean] raw_response Return complete Response object instead of
|
|
166
|
+
# JSON body of response
|
|
167
|
+
# @param [String] data String to be sent as body of the request
|
|
168
|
+
|
|
169
|
+
# @return [String, JSON] Response returned whether loaded JSON or raw
|
|
170
|
+
def exec_request(request, raw_response=false, data=nil)
|
|
171
|
+
request.body = data if !data.nil?
|
|
172
|
+
response = make_http_request(request)
|
|
173
|
+
if raw_response
|
|
174
|
+
handle_exception(response, "raw")
|
|
175
|
+
else
|
|
176
|
+
handle_exception(response, "body", send_json=true)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
private
|
|
181
|
+
|
|
182
|
+
# Private method that handles the exception and raises with proper error
|
|
183
|
+
# message with the type of exception and returns the required values if no
|
|
184
|
+
# exceptions are raised.
|
|
185
|
+
#
|
|
186
|
+
# @param [Net::HTTP::Response] response Response from Artifactory
|
|
187
|
+
# @param [String] to_send What should be returned as a response. Allowed
|
|
188
|
+
# values: "code", "body", and "raw".
|
|
189
|
+
# @param [Boolean] send_json Boolean value used to determine whether to
|
|
190
|
+
# load the JSON or send the response as is.
|
|
191
|
+
#
|
|
192
|
+
# @return [String, JSON] Response returned whether loaded JSON or raw
|
|
193
|
+
# string
|
|
194
|
+
#
|
|
195
|
+
# @raise [Exceptions::Unauthorized] When invalid credentials are
|
|
196
|
+
# provided to connect to Artifactory
|
|
197
|
+
# @raise [Exceptions::NotFound] When the requested page on Artifactory is not
|
|
198
|
+
# found
|
|
199
|
+
# @raise [Exceptions::InternalServerError] When Artifactory returns a 500
|
|
200
|
+
# Internal Server Error
|
|
201
|
+
# @raise [Exceptions::ApiException] Any other exception returned from
|
|
202
|
+
# Artifactory that are not categorized in the API Client.
|
|
203
|
+
#
|
|
204
|
+
def handle_exception(response, to_send = "code", send_json = false)
|
|
205
|
+
msg = "ArtifactoryAPI HTTP Code: #{response.code}, Response Body: #{response.body}"
|
|
206
|
+
@logger.debug msg
|
|
207
|
+
case response.code.to_i
|
|
208
|
+
when 200, 201, 302
|
|
209
|
+
if to_send == "body" && send_json
|
|
210
|
+
return JSON.parse(response.body)
|
|
211
|
+
elsif to_send == "body"
|
|
212
|
+
return response.body
|
|
213
|
+
elsif to_send == "code"
|
|
214
|
+
return response.code
|
|
215
|
+
elsif to_send == "raw"
|
|
216
|
+
return response
|
|
217
|
+
end
|
|
218
|
+
when 400
|
|
219
|
+
matched = response.body.match(/<p>(.*)<br\s*\/>/)
|
|
220
|
+
api_message = matched[1] unless matched.nil?
|
|
221
|
+
@logger.info "API message: #{api_message}"
|
|
222
|
+
raise Exceptions::ApiException.new(api_message)
|
|
223
|
+
when 401
|
|
224
|
+
raise Exceptions::Unauthorized.new
|
|
225
|
+
when 403
|
|
226
|
+
raise Exceptions::Forbidden.new
|
|
227
|
+
when 404
|
|
228
|
+
raise Exceptions::NotFound.new
|
|
229
|
+
when 500
|
|
230
|
+
raise Exceptions::InternalServerError.new
|
|
231
|
+
when 503
|
|
232
|
+
raise Exceptions::ServiceUnavailable.new
|
|
233
|
+
else
|
|
234
|
+
raise Exceptions::ApiException.new(
|
|
235
|
+
"Error code #{response.code}"
|
|
236
|
+
)
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
require 'logger'
|
|
4
|
+
|
|
5
|
+
module ArtifactoryApi
|
|
6
|
+
# This module contains classes that define exceptions for various catories.
|
|
7
|
+
#
|
|
8
|
+
module Exceptions
|
|
9
|
+
# This is the base class for Exceptions that is inherited from
|
|
10
|
+
# RuntimeError.
|
|
11
|
+
#
|
|
12
|
+
class ApiException < RuntimeError
|
|
13
|
+
def initialize( message = "")
|
|
14
|
+
super(message)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# This exception class handles cases where invalid credentials are provided
|
|
19
|
+
# to connect to Artifactory.
|
|
20
|
+
#
|
|
21
|
+
class Unauthorized < ApiException
|
|
22
|
+
def initialize( message = "")
|
|
23
|
+
msg = "Invalid credentials are provided. #{message}"
|
|
24
|
+
super(msg)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# This exception class handles cases where invalid credentials are provided
|
|
29
|
+
# to connect to Artifactory.
|
|
30
|
+
#
|
|
31
|
+
class Forbidden < ApiException
|
|
32
|
+
def initialize( message = "")
|
|
33
|
+
msg = "Forbiddent exception #{message}"
|
|
34
|
+
super(msg)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# This exception class handles cases where a requested page is not found on
|
|
39
|
+
# the Artifactory API.
|
|
40
|
+
#
|
|
41
|
+
class NotFound < ApiException
|
|
42
|
+
def initialize( message = "")
|
|
43
|
+
msg = "Requested component is not found on Artifactory" \
|
|
44
|
+
if message.empty?
|
|
45
|
+
super(msg)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# This exception class handles cases where the Artifactory API returns with a
|
|
50
|
+
# 500 Internel Server Error.
|
|
51
|
+
#
|
|
52
|
+
class InternalServerError < ApiException
|
|
53
|
+
def initialize( message = "")
|
|
54
|
+
msg = "Internel Server Error. #{message}"
|
|
55
|
+
super(msg)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# This exception class handles cases where Artifactory is getting restarted
|
|
60
|
+
# or reloaded where the response code returned is 503
|
|
61
|
+
#
|
|
62
|
+
class ServiceUnavailable < ApiException
|
|
63
|
+
def initialize( message = "")
|
|
64
|
+
msg = "Artifactory is unavailable #{message}"
|
|
65
|
+
super(msg)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module ArtifactoryApi
|
|
2
|
+
class Client
|
|
3
|
+
# Major version of the gem
|
|
4
|
+
MAJOR = 0
|
|
5
|
+
# Minor version of the gem
|
|
6
|
+
MINOR = 1
|
|
7
|
+
# Tiny version of the gem used for patches
|
|
8
|
+
TINY = 4
|
|
9
|
+
# Used for pre-releases
|
|
10
|
+
PRE = 'pre2'
|
|
11
|
+
# Version String of Jenkins API Client.
|
|
12
|
+
VERSION = [MAJOR, MINOR, TINY, PRE].compact.join('.')
|
|
13
|
+
end
|
|
14
|
+
end
|
data/spec/builds_spec.rb
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require_relative "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe ArtifactoryApi::Client::Builds do
|
|
4
|
+
|
|
5
|
+
before(:each) do
|
|
6
|
+
#Setup mocks
|
|
7
|
+
logger = Logger.new("test_log.log")
|
|
8
|
+
@client = double("client")
|
|
9
|
+
@client.stub(:logger) {logger}
|
|
10
|
+
@builds = ArtifactoryApi::Client::Builds.new(@client)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should call the all builds endpoint" do
|
|
14
|
+
#@client.should_receive(:api_get_request) {"/api/builds"}
|
|
15
|
+
@client.should_receive(:api_get_request).with("/api/build").and_return(nil)
|
|
16
|
+
builds = ArtifactoryApi::Client::Builds.new(@client)
|
|
17
|
+
builds.list_all
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should return the builds map" do
|
|
21
|
+
the_response = { "builds" => [{"uri" => "/Build1",
|
|
22
|
+
"lastStarted" => "2013-06-03T13:41:18.147+0000"}],
|
|
23
|
+
"uri" => "http://artifactory/api/build"}
|
|
24
|
+
|
|
25
|
+
@client.should_receive(:api_get_request).with("/api/build").and_return(the_response)
|
|
26
|
+
|
|
27
|
+
build_list = @builds.list_all
|
|
28
|
+
expect(build_list.length).to eq(1)
|
|
29
|
+
expect(build_list[0][:lastStarted]).to eq("2013-06-03T13:41:18.147+0000")
|
|
30
|
+
expect(build_list[0][:name]).to eq("Build1")
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should return all runs given a build" do
|
|
35
|
+
the_response = {"buildsNumbers" => [{"uri" => "/149","started" => "2013-03-14T16:07:43.636+0000"}],
|
|
36
|
+
"uri" => "https://artifactory-1.ampaxs.net/api/build/Server"}
|
|
37
|
+
@client.should_receive(:api_get_request).with("/api/build/MyBuild").and_return(the_response)
|
|
38
|
+
|
|
39
|
+
runs = @builds.get_runs_for_build "MyBuild"
|
|
40
|
+
|
|
41
|
+
expect(runs.length).to eq(1)
|
|
42
|
+
expect(runs[0][:number]).to eq("149")
|
|
43
|
+
expect(runs[0][:started]).to eq("2013-03-14T16:07:43.636+0000")
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "should sort runs by the run number" do
|
|
48
|
+
the_response = {"buildsNumbers" => [
|
|
49
|
+
{"uri" => "/149","started" => "2013-03-14T16:07:43.636+0000"},
|
|
50
|
+
{"uri" => "/2464","started" => "2013-03-14T16:07:43.636+0000"},
|
|
51
|
+
{"uri" => "/379","started" => "2013-06-10T19:38:05.857+0000"},
|
|
52
|
+
{"uri" => "/222","started" => "2013-04-25T19:39:26.464+0000"}],
|
|
53
|
+
"uri" => "https://artifactory-1.ampaxs.net/api/build/Server"}
|
|
54
|
+
|
|
55
|
+
@client.should_receive(:api_get_request).with("/api/build/MyBuild").and_return(the_response)
|
|
56
|
+
|
|
57
|
+
runs = @builds.get_runs_for_build "MyBuild"
|
|
58
|
+
|
|
59
|
+
expect(runs.length).to eq(4)
|
|
60
|
+
expect(runs[0][:number]).to eq("149")
|
|
61
|
+
expect(runs[1][:number]).to eq("222")
|
|
62
|
+
expect(runs[2][:number]).to eq("379")
|
|
63
|
+
expect(runs[3][:number]).to eq("2464")
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
it "should return info for a run, given a build and run" do
|
|
69
|
+
|
|
70
|
+
the_response = {"buildInfo" => {"version" => "1.0.1", "name" => "MyBuild", "number" => "430"},
|
|
71
|
+
"uri" => "https://artifactory-1.ampaxs.net/api/build/Server/430"}
|
|
72
|
+
|
|
73
|
+
@client.should_receive(:api_get_request).with("/api/build/MyBuild/430").and_return(the_response)
|
|
74
|
+
|
|
75
|
+
run_info = @builds.get_run_info "MyBuild","430"
|
|
76
|
+
|
|
77
|
+
expect(run_info[:number]).to eq("430")
|
|
78
|
+
expect(run_info[:name]).to eq("MyBuild")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
data/spec/client_spec.rb
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require_relative "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe ArtifactoryApi::Client do
|
|
4
|
+
|
|
5
|
+
describe "initialization" do
|
|
6
|
+
it "should initialize when server ip, port, and user/password is provided" do
|
|
7
|
+
expect(
|
|
8
|
+
lambda do
|
|
9
|
+
ArtifactoryApi::Client.new(
|
|
10
|
+
:server_ip => '127.0.0.1',
|
|
11
|
+
:server_port => 8080,
|
|
12
|
+
:username => 'username',
|
|
13
|
+
:password => 'password'
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
).not_to raise_error
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should initialize when username/password not specified" do
|
|
20
|
+
expect(
|
|
21
|
+
lambda do
|
|
22
|
+
ArtifactoryApi::Client.new(
|
|
23
|
+
:server_ip => '127.0.0.1',
|
|
24
|
+
:server_port => 8080
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
).not_to raise_error
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should initializes with server_url" do
|
|
31
|
+
expect(
|
|
32
|
+
lambda do
|
|
33
|
+
ArtifactoryApi::Client.new(
|
|
34
|
+
:server_url => 'http://localhost',
|
|
35
|
+
:username => 'username',
|
|
36
|
+
:password => 'password'
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
).not_to raise_error
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should fail to initialize when a username is provided but not a password" do
|
|
43
|
+
expect(
|
|
44
|
+
lambda do
|
|
45
|
+
ArtifactoryApi::Client.new(
|
|
46
|
+
:server_url => 'http://localhost',
|
|
47
|
+
:username => 'user_id'
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
).to raise_error
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "should fail to initialize when you don't provide any server data" do
|
|
54
|
+
expect(
|
|
55
|
+
lambda do
|
|
56
|
+
ArtifactoryApi::Client.new(
|
|
57
|
+
:username => "user", :password => "password")
|
|
58
|
+
end
|
|
59
|
+
).to raise_error
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context "With valid credentials given" do
|
|
64
|
+
before do
|
|
65
|
+
@client = ArtifactoryApi::Client.new(
|
|
66
|
+
:server_ip => '127.0.0.1',
|
|
67
|
+
:server_port => 8080,
|
|
68
|
+
:username => 'username',
|
|
69
|
+
:password => 'password',
|
|
70
|
+
:log_location => '/dev/null'
|
|
71
|
+
)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "should return a Build object when you ask for it" do
|
|
75
|
+
expect(@client.builds.class).to eq(ArtifactoryApi::Client::Builds)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "should return a Artifacts object when you ask for it" do
|
|
79
|
+
expect(@client.artifacts.class).to eq(ArtifactoryApi::Client::Artifacts)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require File.expand_path('../../lib/artifactory_api', __FILE__)
|
|
2
|
+
require 'logger'
|
|
3
|
+
|
|
4
|
+
RSpec.configure do |config|
|
|
5
|
+
config.mock_with :rspec
|
|
6
|
+
config.color_enabled = true
|
|
7
|
+
config.order = :random
|
|
8
|
+
config.expect_with :rspec do |expectations|
|
|
9
|
+
expectations.syntax = :expect
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
metadata
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: artifactory_api
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.4
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Rick Carragher
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2013-08-21 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ~>
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.0'
|
|
20
|
+
requirement: !ruby/object:Gem::Requirement
|
|
21
|
+
requirements:
|
|
22
|
+
- - ~>
|
|
23
|
+
- !ruby/object:Gem::Version
|
|
24
|
+
version: '1.0'
|
|
25
|
+
prerelease: false
|
|
26
|
+
type: :development
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ~>
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '10'
|
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ~>
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '10'
|
|
39
|
+
prerelease: false
|
|
40
|
+
type: :development
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rubygems-tasks
|
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ~>
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0.2'
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ~>
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '0.2'
|
|
53
|
+
prerelease: false
|
|
54
|
+
type: :development
|
|
55
|
+
description: A client to the artifactory rest api
|
|
56
|
+
email: rcarragher@gmail.com
|
|
57
|
+
executables: []
|
|
58
|
+
extensions: []
|
|
59
|
+
extra_rdoc_files: []
|
|
60
|
+
files:
|
|
61
|
+
- Gemfile
|
|
62
|
+
- Gemfile.lock
|
|
63
|
+
- README.md
|
|
64
|
+
- Rakefile
|
|
65
|
+
- lib/artifactory_api.rb
|
|
66
|
+
- lib/artifactory_api/artifacts.rb
|
|
67
|
+
- lib/artifactory_api/builds.rb
|
|
68
|
+
- lib/artifactory_api/client.rb
|
|
69
|
+
- lib/artifactory_api/exceptions.rb
|
|
70
|
+
- lib/artifactory_api/version.rb
|
|
71
|
+
- spec/builds_spec.rb
|
|
72
|
+
- spec/client_spec.rb
|
|
73
|
+
- spec/spec_helper.rb
|
|
74
|
+
homepage: http://rubygems.org/gems/artifactory_api
|
|
75
|
+
licenses:
|
|
76
|
+
- Apachev2
|
|
77
|
+
metadata: {}
|
|
78
|
+
post_install_message:
|
|
79
|
+
rdoc_options: []
|
|
80
|
+
require_paths:
|
|
81
|
+
- lib
|
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
83
|
+
requirements:
|
|
84
|
+
- - '>='
|
|
85
|
+
- !ruby/object:Gem::Version
|
|
86
|
+
version: '0'
|
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
|
+
requirements:
|
|
89
|
+
- - '>='
|
|
90
|
+
- !ruby/object:Gem::Version
|
|
91
|
+
version: '0'
|
|
92
|
+
requirements: []
|
|
93
|
+
rubyforge_project:
|
|
94
|
+
rubygems_version: 2.4.5
|
|
95
|
+
signing_key:
|
|
96
|
+
specification_version: 4
|
|
97
|
+
summary: artfifactory_api consumes the artifactory rest api to do useful stuff
|
|
98
|
+
test_files:
|
|
99
|
+
- spec/builds_spec.rb
|
|
100
|
+
- spec/client_spec.rb
|
|
101
|
+
- spec/spec_helper.rb
|