jenkins_api_client 0.12.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -34,6 +34,7 @@ module JenkinsApi
34
34
  #
35
35
  def initialize(client)
36
36
  @client = client
37
+ @logger = @client.logger
37
38
  end
38
39
 
39
40
  # Returns a string representation of BuildQueue class.
@@ -45,6 +46,7 @@ module JenkinsApi
45
46
  # Gives the number of jobs currently in the build queue
46
47
  #
47
48
  def size
49
+ @logger.info "Obtaining the number of tasks in build queue"
48
50
  response_json = @client.api_get_request("/queue")
49
51
  response_json["items"].size
50
52
  end
@@ -52,6 +54,7 @@ module JenkinsApi
52
54
  # Lists all tasks currently in the build queue
53
55
  #
54
56
  def list
57
+ @logger.info "Obtaining the tasks currently in the build queue"
55
58
  response_json = @client.api_get_request("/queue")
56
59
  tasks = []
57
60
  response_json["items"].each do |item|
@@ -67,6 +70,8 @@ module JenkinsApi
67
70
  # @return [Fixnum] age in seconds
68
71
  #
69
72
  def get_age(task_name)
73
+ @logger.info "Obtaining the age of task '#{task_name}' from the" +
74
+ " build queue"
70
75
  age = nil
71
76
  details = get_details(task_name)
72
77
  unless details.empty?
@@ -82,6 +87,8 @@ module JenkinsApi
82
87
  # @return [Hash] Queue details of the specified task/job
83
88
  #
84
89
  def get_details(task_name)
90
+ @logger.info "Obtaining the details of task '#{task_name}' from the" +
91
+ " build queue"
85
92
  response_json = @client.api_get_request("/queue")
86
93
  details = {}
87
94
  response_json["items"].each do |item|
@@ -90,6 +97,17 @@ module JenkinsApi
90
97
  details
91
98
  end
92
99
 
100
+ # Obtain the item in the queue provided the ID of the task
101
+ #
102
+ # @param task_id [String] the ID of the task
103
+ #
104
+ # @return [Hash] the details of the item in the queue
105
+ #
106
+ def get_item_by_id(task_id)
107
+ @logger.info "Obtaining the details of task with ID '#{task_id}'"
108
+ @client.api_get_request("/queue/item/#{task_id}")
109
+ end
110
+
93
111
  # Obtains the causes from the build queue for the specified task
94
112
  #
95
113
  # @param [String] task_name
@@ -97,6 +115,8 @@ module JenkinsApi
97
115
  # @return [Array] causes for the task to be in queue
98
116
  #
99
117
  def get_causes(task_name)
118
+ @logger.info "Obtaining the causes of task '#{task_name}' from the" +
119
+ " build queue"
100
120
  causes = nil
101
121
  details = get_details(task_name)
102
122
  unless details.empty?
@@ -115,6 +135,8 @@ module JenkinsApi
115
135
  # @return [String] reason for being in queue, nil if no task found
116
136
  #
117
137
  def get_reason(task_name)
138
+ @logger.info "Obtaining the reason of task '#{task_name}' from the" +
139
+ " build queue"
118
140
  reason = nil
119
141
  details = get_details(task_name)
120
142
  unless details.empty?
@@ -131,6 +153,8 @@ module JenkinsApi
131
153
  # tasks with no ETA info.
132
154
  #
133
155
  def get_eta(task_name)
156
+ @logger.info "Obtaining the ETA for the task '#{task_name}' from the" +
157
+ " build queue"
134
158
  eta = nil
135
159
  details = get_details(task_name)
136
160
  unless details.empty?
@@ -153,6 +177,8 @@ module JenkinsApi
153
177
  # @return [String] ID of the task, nil of no task is found
154
178
  #
155
179
  def get_id(task_name)
180
+ @logger.info "Obtaining the ID of task '#{task_name}' from the" +
181
+ " build queue"
156
182
  id = nil
157
183
  details = get_details(task_name)
158
184
  unless details.empty?
@@ -168,6 +194,8 @@ module JenkinsApi
168
194
  # @return [String] params, nil if the no task is found
169
195
  #
170
196
  def get_params(task_name)
197
+ @logger.info "Obtaining the build parameters of task '#{task_name}'" +
198
+ " from the build queue"
171
199
  params = nil
172
200
  details = get_details(task_name)
173
201
  unless details.empty?
@@ -183,6 +211,8 @@ module JenkinsApi
183
211
  # @return [TrueClass|FalseClass] buildable or not
184
212
  #
185
213
  def is_buildable?(task_name)
214
+ @logger.info "Checking if task '#{task_name}' from the build queue" +
215
+ " is buildable"
186
216
  buildable = nil
187
217
  details = get_details(task_name)
188
218
  unless details.empty?
@@ -198,6 +228,8 @@ module JenkinsApi
198
228
  # @return [TrueClass|FalseClass] blocked or not
199
229
  #
200
230
  def is_blocked?(task_name)
231
+ @logger.info "Checking if task '#{task_name}' from the build queue" +
232
+ " is blocked"
201
233
  blocked = nil
202
234
  details = get_details(task_name)
203
235
  unless details.empty?
@@ -213,6 +245,8 @@ module JenkinsApi
213
245
  # @return [TrueClass|FalseClass] stuck or not
214
246
  #
215
247
  def is_stuck?(task_name)
248
+ @logger.info "Checking if task '#{task_name}' from the build queue" +
249
+ " is stuck"
216
250
  stuck = nil
217
251
  details = get_details(task_name)
218
252
  unless details.empty?
@@ -89,20 +89,15 @@ module JenkinsApi
89
89
  desc "console JOB", "Print the progressive console output of a job"
90
90
  method_option :sleep, :aliases => "-z",
91
91
  :desc => "Time to wait between querying the API for console output"
92
- # CLI command to obtain console output for a job
92
+ # CLI command to obtain console output for a job. Make sure the log
93
+ # location is set to something other than STDOUT. By default it is set to
94
+ # STDOUT. If the log messages are printed on the same console, the
95
+ # console output will get garbled.
93
96
  #
94
97
  # @param [String] job Name of the job
95
98
  #
96
99
  def console(job)
97
100
  @client = Helper.setup(parent_options)
98
- # If debug is enabled, disable it. It shouldn't interfere
99
- # with console output.
100
- debug_changed = false
101
- if @client.debug == true
102
- @client.debug = false
103
- debug_changed = true
104
- end
105
-
106
101
  # Print progressive console output
107
102
  response = @client.job.get_console_output(job)
108
103
  puts response['output'] unless response['more']
@@ -114,8 +109,6 @@ module JenkinsApi
114
109
  end
115
110
  # Print the last few lines
116
111
  puts response['output'] unless response['output'].chomp.empty?
117
- # Change the debug back if we changed it now
118
- @client.toggle_debug if debug_changed
119
112
  end
120
113
 
121
114
  desc "restrict JOB", "Restricts a job to a specific node"
@@ -26,7 +26,9 @@ require 'net/http'
26
26
  require 'net/https'
27
27
  require 'nokogiri'
28
28
  require 'base64'
29
- require "mixlib/shellout"
29
+ require 'mixlib/shellout'
30
+ require 'uri'
31
+ require 'logger'
30
32
 
31
33
  # The main module that contains the Client class and all subclasses that
32
34
  # communicate with the Jenkins's Remote Access API.
@@ -37,7 +39,7 @@ module JenkinsApi
37
39
  # for various operations.
38
40
  #
39
41
  class Client
40
- attr_accessor :debug, :timeout
42
+ attr_accessor :timeout, :logger
41
43
  # Default port to be used to connect to Jenkins
42
44
  DEFAULT_SERVER_PORT = 8080
43
45
  # Default timeout in seconds to be used while performing operations
@@ -53,27 +55,54 @@ module JenkinsApi
53
55
  "username",
54
56
  "password",
55
57
  "password_base64",
56
- "debug",
58
+ "log_location",
59
+ "log_level",
57
60
  "timeout",
58
61
  "ssl",
59
- "follow_redirects"
62
+ "follow_redirects",
63
+ "identity_file"
60
64
  ].freeze
61
65
 
62
66
  # Initialize a Client object with Jenkins CI server credentials
63
67
  #
64
- # @param [Hash] args
65
- # * the +:server_ip+ param is the IP address of the Jenkins CI server
66
- # * the +:server_port+ param is the port on which the Jenkins listens
67
- # * the +:server_url+ param is the full URL address of the Jenkins CI server (http/https)
68
- # * the +:username+ param is the username used for connecting to the server (optional)
69
- # * the +:password+ param is the password for connecting to the CI server (optional)
70
- # * the +:proxy_ip+ param is the proxy IP address
71
- # * the +:proxy_port+ param is the proxy port
72
- # * the +:jenkins_path+ param is the optional context path for Jenkins
73
- # * the +:ssl+ param indicates if Jenkins is accessible over HTTPS
74
- # (defaults to false)
75
- # * the +:follow_redirects+ param will cause the client to follow a redirect
76
- # (jenkins can return a 30x when starting a build)
68
+ # @param args [Hash] Arguments to connect to Jenkins server
69
+ #
70
+ # @option args [String] :server_ip
71
+ # the IP address of the Jenkins CI server
72
+ # @option args [String] :server_port
73
+ # the port on which the Jenkins listens
74
+ # @option args [String] :server_url
75
+ # the full URL address of the Jenkins CI server (http/https)
76
+ # @option args [String] :username
77
+ # the username used for connecting to the server (optional)
78
+ # @option args [String] :password
79
+ # the password for connecting to the CI server (optional)
80
+ # @option args [String] :password_base64
81
+ # the password with base64 encoded format for connecting to the CI
82
+ # server (optional)
83
+ # @option args [String] :identity_file
84
+ # the priviate key file for Jenkins CLI authentication,
85
+ # it is used only for executing CLI commands.
86
+ # also remember to upload the public key to http://#{server_ip}:#{server_port}/user/#{my_username}/configure
87
+ # @option args [String] :proxy_ip
88
+ # the proxy IP address
89
+ # @option args [String] :proxy_port
90
+ # the proxy port
91
+ # @option args [String] :jenkins_path
92
+ # the optional context path for Jenkins
93
+ # @option args [Boolean] :ssl
94
+ # indicates if Jenkins is accessible over HTTPS (defaults to false)
95
+ # @option args [Boolean] :follow_redirects
96
+ # This argument causes the client to follow a redirect (jenkins can
97
+ # return a 30x when starting a build)
98
+ # @option args [Fixnum] :timeout
99
+ # This argument sets the timeout for the jenkins system to become ready
100
+ # @option args [String] :log_location
101
+ # The location for the log file (Defaults to STDOUT)
102
+ # @option args [Fixnum] :log_level
103
+ # The level for messages to be logged. Should be one of:
104
+ # Logger::DEBUG (0), Logger::INFO (1), Logger::WARN (2), Logger::ERROR
105
+ # (2), Logger::FATAL (3) (Defaults to Logger::INFO)
77
106
  #
78
107
  # @return [JenkinsApi::Client] a client object to Jenkins API
79
108
  #
@@ -85,10 +114,15 @@ module JenkinsApi
85
114
  instance_variable_set("@#{key}", value)
86
115
  end
87
116
  end if args.is_a? Hash
117
+
118
+ # Server IP or Server URL must be specifiec
88
119
  unless @server_ip || @server_url
89
- raise ArgumentError, "Server IP or Server URL is required to connect to Jenkins"
120
+ raise ArgumentError, "Server IP or Server URL is required to connect" +
121
+ " to Jenkins"
90
122
  end
91
- # Username/password are optional as some jenkins servers do not require auth
123
+
124
+ # Username/password are optional as some jenkins servers do not require
125
+ # authentication
92
126
  if @username && !(@password || @password_base64)
93
127
  raise ArgumentError, "If username is provided, password is required"
94
128
  end
@@ -96,23 +130,44 @@ module JenkinsApi
96
130
  raise ArgumentError, "Proxy IP and port must both be specified or" +
97
131
  " both left nil"
98
132
  end
99
- @server_uri = URI.parse(@server_url) if @server_url
133
+
134
+ # Get info from the server_url, if we got one
135
+ if @server_url
136
+ server_uri = URI.parse(@server_url)
137
+ @server_ip = server_uri.host
138
+ @server_port = server_uri.port
139
+ @ssl = server_uri.scheme == "https"
140
+ @jenkins_path = server_uri.path
141
+ end
142
+
143
+ @jenkins_path ||= ""
144
+ @jenkins_path.gsub!(/\/$/,"") # remove trailing slash if there is one
100
145
  @server_port = DEFAULT_SERVER_PORT unless @server_port
101
146
  @timeout = DEFAULT_TIMEOUT unless @timeout
102
147
  @ssl ||= false
103
- @ssl = @server_uri.scheme == "https" if @server_uri
104
- @debug = false unless @debug
148
+
149
+ # Setting log options
150
+ @log_location = STDOUT unless @log_location
151
+ @log_level = Logger::INFO unless @log_level
152
+ @logger = Logger.new(@log_location)
153
+ @logger.level = @log_level
154
+
105
155
 
106
156
  # Base64 decode inserts a newline character at the end. As a workaround
107
157
  # added chomp to remove newline characters. I hope nobody uses newline
108
158
  # characters at the end of their passwords :)
109
159
  @password = Base64.decode64(@password_base64).chomp if @password_base64
110
- end
111
160
 
112
- # This method toggles the debug parameter in run time
113
- #
114
- def toggle_debug
115
- @debug = @debug == false ? true : false
161
+ # No connections are made to the Jenkins server during initialize to
162
+ # allow the unit tests to behave normally as mocking is simpler this way.
163
+ # If this variable is nil, the first POST request will query the API and
164
+ # populate this variable.
165
+ @crumbs_enabled = nil
166
+ # The crumbs hash. Store it so that we don't have to obtain the crumb for
167
+ # every POST request. It appears that the crumb doesn't change often.
168
+ @crumb = {}
169
+ # This is the number of times to refetch the crumb if it ever expires.
170
+ @crumb_max_retries = 3
116
171
  end
117
172
 
118
173
  # Creates an instance to the Job class by passing a reference to self
@@ -163,6 +218,21 @@ module JenkinsApi
163
218
  "#<JenkinsApi::Client>"
164
219
  end
165
220
 
221
+ # Overrides the inspect method to get rid of the credentials being shown in
222
+ # the in interactive IRB sessions and also when the `inspect` method is
223
+ # called. Just print the important variables.
224
+ #
225
+ def inspect
226
+ "#<JenkinsApi::Client:0x#{(self.__id__ * 2).to_s(16)}" +
227
+ " @ssl=#{@ssl.inspect}," +
228
+ " @log_location=#{@log_location.inspect}," +
229
+ " @log_level=#{@log_level.inspect}," +
230
+ " @crumbs_enabled=#{@crumbs_enabled.inspect}," +
231
+ " @follow_redirects=#{@follow_redirects.inspect}," +
232
+ " @jenkins_path=#{@jenkins_path.inspect}," +
233
+ " @timeout=#{@timeout.inspect}>"
234
+ end
235
+
166
236
  # Connects to the Jenkins server, sends the specified request and returns
167
237
  # the response.
168
238
  #
@@ -174,18 +244,10 @@ module JenkinsApi
174
244
  def make_http_request(request, follow_redirect = @follow_redirects)
175
245
  request.basic_auth @username, @password if @username
176
246
 
177
- if @server_uri
178
- host = @server_uri.host
179
- port = @server_uri.port
180
- else
181
- host = @server_ip
182
- port = @server_port
183
- end
184
-
185
247
  if @proxy_ip
186
- http = Net::HTTP::Proxy(@proxy_ip, @proxy_port).new(host, port)
248
+ http = Net::HTTP::Proxy(@proxy_ip, @proxy_port).new(@server_ip, @server_port)
187
249
  else
188
- http = Net::HTTP.new(host, port)
250
+ http = Net::HTTP.new(@server_ip, @server_port)
189
251
  end
190
252
 
191
253
  if @ssl
@@ -216,6 +278,7 @@ module JenkinsApi
216
278
  # @return [Net::HTTP::Response] Response from Jenkins for "/"
217
279
  #
218
280
  def get_root
281
+ @logger.info "GET /"
219
282
  request = Net::HTTP::Get.new("/")
220
283
  make_http_request(request)
221
284
  end
@@ -241,10 +304,10 @@ module JenkinsApi
241
304
  end
242
305
  to_get = URI.escape(to_get)
243
306
  request = Net::HTTP::Get.new(to_get)
244
- puts "[INFO] GET #{to_get}" if @debug
307
+ @logger.info "GET #{to_get}"
245
308
  response = make_http_request(request)
246
309
  if raw_response
247
- response
310
+ handle_exception(response, "raw")
248
311
  else
249
312
  handle_exception(response, "body", url_suffix =~ /json/)
250
313
  end
@@ -257,16 +320,37 @@ module JenkinsApi
257
320
  #
258
321
  # @return [String] Response code form Jenkins Response
259
322
  #
260
- def api_post_request(url_prefix, form_data = {})
261
- # Added form_data default {} instead of nil to help with proxies
262
- # that barf with empty post
263
- url_prefix = URI.escape("#{@jenkins_path}#{url_prefix}")
264
- request = Net::HTTP::Post.new("#{url_prefix}")
265
- puts "[INFO] POST #{url_prefix}" if @debug
266
- request.content_type = 'application/json'
267
- request.set_form_data(form_data)
268
- response = make_http_request(request)
269
- handle_exception(response)
323
+ def api_post_request(url_prefix, form_data = {}, raw_response = false)
324
+ retries = @crumb_max_retries
325
+ begin
326
+ # Identify whether to use crumbs if this is the first POST request.
327
+ @crumbs_enabled = use_crumbs? if @crumbs_enabled.nil?
328
+ @crumb = get_crumb if @crumbs_enabled && @crumb.empty?
329
+
330
+ # Added form_data default {} instead of nil to help with proxies
331
+ # that barf with empty post
332
+ url_prefix = URI.escape("#{@jenkins_path}#{url_prefix}")
333
+ request = Net::HTTP::Post.new("#{url_prefix}")
334
+ @logger.info "POST #{url_prefix}"
335
+ request.content_type = 'application/json'
336
+ if @crumbs_enabled
337
+ request[@crumb["crumbRequestField"]] = @crumb["crumb"]
338
+ end
339
+ request.set_form_data(form_data)
340
+ response = make_http_request(request)
341
+ if raw_response
342
+ handle_exception(response, "raw")
343
+ else
344
+ handle_exception(response)
345
+ end
346
+ rescue Exceptions::ForbiddenException
347
+ @logger.info "Crumb expired. Refetching from the server. Trying" +
348
+ " #{@crumb_max_retries - retries + 1} out of #{@crumb_max_retries}" +
349
+ " times..."
350
+ @crumb = get_crumb
351
+ retries -= 1
352
+ retries > 0 ? retry : raise
353
+ end
270
354
  end
271
355
 
272
356
  # Obtains the configuration of a component from the Jenkins CI server
@@ -278,7 +362,7 @@ module JenkinsApi
278
362
  def get_config(url_prefix)
279
363
  url_prefix = URI.escape("#{@jenkins_path}#{url_prefix}")
280
364
  request = Net::HTTP::Get.new("#{url_prefix}/config.xml")
281
- puts "[INFO] GET #{url_prefix}/config.xml" if @debug
365
+ @logger.info "GET #{url_prefix}/config.xml"
282
366
  response = make_http_request(request)
283
367
  handle_exception(response, "body")
284
368
  end
@@ -291,18 +375,54 @@ module JenkinsApi
291
375
  # @return [String] Response code returned from Jenkins
292
376
  #
293
377
  def post_config(url_prefix, xml)
294
- url_prefix = URI.escape("#{@jenkins_path}#{url_prefix}")
295
- request = Net::HTTP::Post.new("#{url_prefix}")
296
- puts "[INFO] POST #{url_prefix}" if @debug
297
- request.body = xml
298
- request.content_type = 'application/xml'
299
- response = make_http_request(request)
300
- handle_exception(response)
378
+ retries = @crumb_max_retries
379
+ begin
380
+ # Identify whether to use crumbs if this is the first POST request.
381
+ @crumbs_enabled = use_crumbs? if @crumbs_enabled.nil?
382
+ @crumb = get_crumb if @crumbs_enabled && @crumb.empty?
383
+
384
+ url_prefix = URI.escape("#{@jenkins_path}#{url_prefix}")
385
+ request = Net::HTTP::Post.new("#{url_prefix}")
386
+ @logger.info "POST #{url_prefix}"
387
+ request.body = xml
388
+ request.content_type = 'application/xml'
389
+ if @crumbs_enabled
390
+ request[@crumb["crumbRequestField"]] = @crumb["crumb"]
391
+ end
392
+ response = make_http_request(request)
393
+ handle_exception(response)
394
+ rescue Exceptions::ForbiddenException
395
+ @logger.info "Crumb expired. Refetching from the server. Trying" +
396
+ " #{@crumb_max_retries - retries + 1} out of #{@crumb_max_retries}" +
397
+ " times..."
398
+ @crumb = get_crumb
399
+ retries -= 1
400
+ retries > 0 ? retry : raise
401
+ end
402
+ end
403
+
404
+ # Checks if Jenkins uses crumbs (i.e) the XSS disable option is checked in
405
+ # Jenkins' security settings
406
+ #
407
+ # @return [Boolean] whether Jenkins uses crumbs or not
408
+ #
409
+ def use_crumbs?
410
+ response = api_get_request("")
411
+ response["useCrumbs"]
301
412
  end
302
413
 
303
- # Obtain the version of Jenkins CI server
414
+ # Checks if Jenkins uses security
415
+ #
416
+ # @return [Boolean] whether Jenkins uses security or not
304
417
  #
305
- # @return [String] Version of Jenkins
418
+ def use_security?
419
+ response = api_get_request("")
420
+ response["useSecurity"]
421
+ end
422
+
423
+ # Obtains the jenkins version from the API
424
+ #
425
+ # @return Jenkins version
306
426
  #
307
427
  def get_jenkins_version
308
428
  response = get_root
@@ -340,10 +460,11 @@ module JenkinsApi
340
460
  def exec_cli(command, args = [])
341
461
  base_dir = File.dirname(__FILE__)
342
462
  server_url = "http://#{@server_ip}:#{@server_port}/#{@jenkins_path}"
343
- cmd = "java -jar #{base_dir}/../../java_deps/jenkins-cli.jar" +
344
- " -s #{server_url} #{command}" +
345
- " --username #{@username} --password #{@password} " +
346
- args.join(' ')
463
+ cmd = "java -jar #{base_dir}/../../java_deps/jenkins-cli.jar -s #{server_url}"
464
+ cmd << " -i #{@identity_file}" if @identity_file && !@identity_file.empty?
465
+ cmd << " #{command}"
466
+ cmd << " --username #{@username} --password #{@password} " if @identity_file.nil? || @identity_file.empty?
467
+ cmd << args.join(' ')
347
468
  java_cmd = Mixlib::ShellOut.new(cmd)
348
469
 
349
470
  # Run the command
@@ -354,37 +475,62 @@ module JenkinsApi
354
475
  # The stderr has a stack trace of the Java program. We'll already have
355
476
  # a stack trace for Ruby. So just display a descriptive message for the
356
477
  # error thrown by the CLI.
357
- raise Exceptions::CLIException.new(java_cmd.stderr.split("\n").first)
478
+ raise Exceptions::CLIException.new(
479
+ @logger,
480
+ java_cmd.stderr.split("\n").first
481
+ )
358
482
  end
359
483
  end
360
484
 
361
485
  private
362
486
 
487
+ # Obtains the crumb from Jenkins' crumb issuer
488
+ #
489
+ # @return [Hash<String, String>] the crumb response from Jenkins' crumb
490
+ # issuer
491
+ #
492
+ # @raise Exceptions::CrumbNotFoundException if the crumb is not provided
493
+ # (i.e) XSS disable option is not checked in Jenkins' security setting
494
+ #
495
+ def get_crumb
496
+ begin
497
+ @logger.debug "Obtaining crumb from the jenkins server"
498
+ api_get_request("/crumbIssuer")
499
+ rescue Exceptions::NotFoundException
500
+ raise Exceptions::CrumbNotFoundException.new(
501
+ @logger,
502
+ "CSRF protection is not enabled on the server at the moment." +
503
+ " Perhaps the client was initialized when the CSRF setting was" +
504
+ " enabled. Please re-initialize the client."
505
+ )
506
+ end
507
+ end
508
+
363
509
  # Private method that handles the exception and raises with proper error
364
510
  # message with the type of exception and returns the required values if no
365
511
  # exceptions are raised.
366
512
  #
367
513
  # @param [Net::HTTP::Response] response Response from Jenkins
368
514
  # @param [String] to_send What should be returned as a response. Allowed
369
- # values: "code" and "body".
515
+ # values: "code", "body", and "raw".
370
516
  # @param [Boolean] send_json Boolean value used to determine whether to
371
517
  # load the JSON or send the response as is.
372
518
  #
373
519
  # @return [String, JSON] Response returned whether loaded JSON or raw
374
520
  # string
375
521
  #
376
- # @raise [Exceptions::UnauthorizedException] When invalid credentials are
522
+ # @raise [Exceptions::Unauthorized] When invalid credentials are
377
523
  # provided to connect to Jenkins
378
- # @raise [Exceptions::NotFoundException] When the requested page on Jenkins
379
- # is found
380
- # @raise [Exceptions::InternelServerErrorException] When Jenkins returns a
381
- # 500 Internel Server Error
524
+ # @raise [Exceptions::NotFound] When the requested page on Jenkins is not
525
+ # found
526
+ # @raise [Exceptions::InternalServerError] When Jenkins returns a 500
527
+ # Internal Server Error
382
528
  # @raise [Exceptions::ApiException] Any other exception returned from
383
529
  # Jenkins that are not categorized in the API Client.
384
530
  #
385
531
  def handle_exception(response, to_send = "code", send_json = false)
386
532
  msg = "HTTP Code: #{response.code}, Response Body: #{response.body}"
387
- puts msg if @debug
533
+ @logger.debug msg
388
534
  case response.code.to_i
389
535
  # As of Jenkins version 1.519, the job builds return a 201 status code
390
536
  # with a Location HTTP header with the pointing the URL of the item in
@@ -396,24 +542,40 @@ module JenkinsApi
396
542
  return response.body
397
543
  elsif to_send == "code"
398
544
  return response.code
545
+ elsif to_send == "raw"
546
+ return response
399
547
  end
400
548
  when 400
401
- case response.body
549
+ matched = response.body.match(/<p>(.*)<\/p>/)
550
+ api_message = matched[1] unless matched.nil?
551
+ @logger.debug "API message: #{api_message}"
552
+ case api_message
402
553
  when /A job already exists with the name/
403
- raise Exceptions::JobAlreadyExistsWithName.new
554
+ raise Exceptions::JobAlreadyExists.new(@logger, api_message)
555
+ when /A view already exists with the name/
556
+ raise Exceptions::ViewAlreadyExists.new(@logger, api_message)
557
+ when /Slave called .* already exists/
558
+ raise Exceptions::NodeAlreadyExists.new(@logger, api_message)
404
559
  when /Nothing is submitted/
405
- raise Exceptions::NothingSubmitted.new
560
+ raise Exceptions::NothingSubmitted.new(@logger, api_message)
406
561
  else
407
- raise Exceptions::ApiException.new("Error code 400")
562
+ raise Exceptions::ApiException.new(@logger, api_message)
408
563
  end
409
564
  when 401
410
- raise Exceptions::UnautherizedException.new
565
+ raise Exceptions::Unauthorized.new @logger
566
+ when 403
567
+ raise Exceptions::Forbidden.new @logger
411
568
  when 404
412
- raise Exceptions::NotFoundException.new
569
+ raise Exceptions::NotFound.new @logger
413
570
  when 500
414
- raise Exceptions::InternelServerErrorException.new
571
+ raise Exceptions::InternalServerError.new @logger
572
+ when 503
573
+ raise Exceptions::ServiceUnavailable.new @logger
415
574
  else
416
- raise Exceptions::ApiException.new("Error code #{response.code}")
575
+ raise Exceptions::ApiException.new(
576
+ @logger,
577
+ "Error code #{response.code}"
578
+ )
417
579
  end
418
580
  end
419
581