jenkins_api_client 0.12.1 → 0.13.0

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.
@@ -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