jenkins_api_client 0.7.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,6 +4,18 @@ CHANGELOG
4
4
  upcoming
5
5
  --------
6
6
 
7
+ v0.8.0 [14-FEB-2013]
8
+ ---------------------
9
+ * Added capability to send timer trigger while creating a job
10
+ * Added rename feature for jobs
11
+ * Added support for sending skype notification in job creation and on existing jobs
12
+ * Added support for sending Jenkins root URL configuration. Credit: @kevinhcross
13
+ * Added `delete_all!` methods for Job, View, and Node.
14
+ * `get_eta` in BuildQueue will return "N/A" if the ETA is not given by Jenkins
15
+ * Creating view accepts params Hash and more configuration through the API
16
+ * Spaces are allowed in Job, Node, and View names. Credit: @kevinhcross
17
+ * Support has been added to build a job with parameters. Credit: @tjhanley
18
+
7
19
  v0.7.3 [05-FEB-2013]
8
20
  ---------------------
9
21
  * Fixed #27 with a bug in create_view including extra character in the end of the name
@@ -86,7 +98,7 @@ v0.1.0 [26-OCT-2012]
86
98
  v0.0.2 [16-OCT-2012]
87
99
  ---------------------
88
100
  * Added documentation
89
- * Added some more smal features to Job class
101
+ * Added some more small features to Job class
90
102
 
91
103
  v0.0.1 [15-OCT-2012]
92
104
  ---------------------
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  Jenkins API Client
2
2
  ==================
3
+ [![Gem Version](https://badge.fury.io/rb/jenkins_api_client.png)](http://rubygems.org/gems/jenkins_api_client)
3
4
  [![Build Status](https://travis-ci.org/arangamani/jenkins_api_client.png?branch=master)](https://travis-ci.org/arangamani/jenkins_api_client)
4
5
  [![Dependency Status](https://gemnasium.com/arangamani/jenkins_api_client.png)](https://gemnasium.com/arangamani/jenkins_api_client)
5
- [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/arangamani/jenkins_api_client)
6
+ [![Code Climate](https://codeclimate.com/github/arangamani/jenkins_api_client.png)](https://codeclimate.com/github/arangamani/jenkins_api_client)
6
7
 
7
8
  Copyright © 2012-2013, Kannan Manickam [![endorse](http://api.coderwall.com/arangamani/endorsecount.png)](http://coderwall.com/arangamani)
8
9
 
@@ -77,7 +78,8 @@ The following example passes the YAML file contents. An example yaml file is loc
77
78
  <tt>config/login.yml.example</tt>.
78
79
 
79
80
  ```ruby
80
- @client = JenkinsApi::Client.new(YAML.Load_file(File.expand_path('~/.jenkins_api_client/login.yml', __FILE__)))
81
+ @client = JenkinsApi::Client.new(YAML.Load_file(File.expand_path(
82
+ "~/.jenkins_api_client/login.yml", __FILE__)))
81
83
  # The following call lists all jobs
82
84
  puts @client.job.list_all
83
85
  ```
@@ -95,7 +97,8 @@ require 'jenkins_api_client'
95
97
  jobs_to_filter = "^test_job.*"
96
98
 
97
99
  # Create an instance to jenkins_api_client
98
- @client = JenkinsApi::Client.new(YAML.load_file(File.expand_path('~/.jenkins_api_client/login.yml', __FILE__)))
100
+ @client = JenkinsApi::Client.new(YAML.load_file(File.expand_path(
101
+ "~/.jenkins_api_client/login.yml", __FILE__)))
99
102
 
100
103
  # Get a filtered list of jobs from the server
101
104
  jobs = @client.job.list(jobs_to_filter)
@@ -106,7 +109,8 @@ jobs = @client.job.list(jobs_to_filter)
106
109
  initial_jobs = @client.job.chain(jobs, 'success', ["all"])
107
110
 
108
111
  # Now that we have the initial job(s) we can build them
109
- # The build function returns a code from the API which should be 302 if the build was successful
112
+ # The build function returns a code from the API which should be 302 if
113
+ # the build was successful
110
114
  code = @client.job.build(initial_jobs[0])
111
115
  raise "Could not build the job specified" unless code == 302
112
116
  ```
@@ -137,10 +141,10 @@ with 'failure' as the threshold, and also chain three jobs in parallel.
137
141
  ```ruby
138
142
  initial_jobs = @client.job.chain(jobs, 'failure', ["failure", "unstable"], 3)
139
143
  # We will receive three jobs as a result and we can build them all
140
- initial_jobs.each { |job|
144
+ initial_jobs.each do |job|
141
145
  code = @client.job.build(job)
142
146
  raise "Unable to build job: #{job}" unless code == 302
143
- }
147
+ end
144
148
  ```
145
149
 
146
150
  ### Using with command line
@@ -169,6 +173,8 @@ If you would like to contribute to this project, just do the following:
169
173
  5. Once changes are done or no changes are required, pull request will be merged.
170
174
  6. The next release will have your changes in it.
171
175
 
176
+ Please take a look at the issues page if you want to get started.
177
+
172
178
  FEATURE REQUEST:
173
179
  ----------------
174
180
 
@@ -12,6 +12,10 @@
12
12
 
13
13
  :server_port: 8080
14
14
 
15
+ # If there is a web server routing your Jenkins requests you might need this
16
+
17
+ :jenkins_path: ""
18
+
15
19
  # The username and password to authenticate to the server
16
20
 
17
21
  :username: my_username
@@ -120,15 +120,21 @@ module JenkinsApi
120
120
  #
121
121
  # @param[String] task_name name of the task
122
122
  #
123
- # @return [String] ETA for the task, nil if no task found or ETA is
124
- # not available
123
+ # @return [String] ETA for the task, nil if no task found and N/A for
124
+ # tasks with no ETA info.
125
125
  #
126
126
  def get_eta(task_name)
127
127
  eta = nil
128
128
  details = get_details(task_name)
129
129
  unless details.empty?
130
130
  matched = details["why"].match(/.*\(ETA:(.*)\)/)
131
- eta = matched[1].strip unless matched.nil?
131
+ if matched.nil?
132
+ # Task is found, but ETA information is not available
133
+ eta = "N/A"
134
+ else
135
+ # ETA information is available
136
+ eta = matched[1].strip
137
+ end
132
138
  end
133
139
  eta
134
140
  end
@@ -32,7 +32,7 @@ module JenkinsApi
32
32
  class Client
33
33
  attr_accessor :debug
34
34
  DEFAULT_SERVER_PORT = 8080
35
- VALID_PARAMS = %w(server_ip server_port username password debug)
35
+ VALID_PARAMS = %w(server_ip server_port jenkins_path username password debug)
36
36
 
37
37
  # Initialize a Client object with Jenkins CI server credentials
38
38
  #
@@ -115,10 +115,17 @@ module JenkinsApi
115
115
  # @param [String] url_prefix
116
116
  #
117
117
  def api_get_request(url_prefix, tree = nil, url_suffix ="/api/json")
118
+ url_prefix = "#{@jenkins_path}#{url_prefix}"
118
119
  http = Net::HTTP.start(@server_ip, @server_port)
119
- request = Net::HTTP::Get.new("#{url_prefix}#{url_suffix}")
120
- puts "[INFO] GET #{url_prefix}#{url_suffix}" if @debug
121
- request = Net::HTTP::Get.new("#{url_prefix}#{url_suffix}?#{tree}") if tree
120
+ to_get = ""
121
+ if tree
122
+ to_get = "#{url_prefix}#{url_suffix}?#{tree}"
123
+ else
124
+ to_get = "#{url_prefix}#{url_suffix}"
125
+ end
126
+ to_get = URI.escape(to_get)
127
+ request = Net::HTTP::Get.new(to_get)
128
+ puts "[INFO] GET #{to_get}" if @debug
122
129
  request.basic_auth @username, @password
123
130
  response = http.request(request)
124
131
  msg = "HTTP Code: #{response.code}, Response Body: #{response.body}"
@@ -146,6 +153,7 @@ module JenkinsApi
146
153
  # @param [Hash] form_data form data to send with POST request
147
154
  #
148
155
  def api_post_request(url_prefix, form_data = nil)
156
+ url_prefix = URI.escape("#{@jenkins_path}#{url_prefix}")
149
157
  http = Net::HTTP.start(@server_ip, @server_port)
150
158
  request = Net::HTTP::Post.new("#{url_prefix}")
151
159
  puts "[INFO] PUT #{url_prefix}" if @debug
@@ -156,7 +164,7 @@ module JenkinsApi
156
164
  msg = "HTTP Code: #{response.code}, Response Body: #{response.body}"
157
165
  case response.code.to_i
158
166
  when 200, 302
159
- return response.code
167
+ return response.body
160
168
  when 404
161
169
  raise Exceptions::NotFoundException.new(msg)
162
170
  when 500
@@ -171,6 +179,7 @@ module JenkinsApi
171
179
  # @param [String] url_prefix
172
180
  #
173
181
  def get_config(url_prefix)
182
+ url_prefix = URI.escape(url_prefix)
174
183
  http = Net::HTTP.start(@server_ip, @server_port)
175
184
  request = Net::HTTP::Get.new("#{url_prefix}/config.xml")
176
185
  puts "[INFO] GET #{url_prefix}/config.xml" if @debug
@@ -185,6 +194,7 @@ module JenkinsApi
185
194
  # @param [String] xml
186
195
  #
187
196
  def post_config(url_prefix, xml)
197
+ url_prefix = URI.escape(url_prefix)
188
198
  http = Net::HTTP.start(@server_ip, @server_port)
189
199
  request = Net::HTTP::Post.new("#{url_prefix}")
190
200
  puts "[INFO] PUT #{url_prefix}" if @debug
@@ -192,7 +202,7 @@ module JenkinsApi
192
202
  request.body = xml
193
203
  request.content_type = 'application/xml'
194
204
  response = http.request(request)
195
- response.code
205
+ response.body
196
206
  end
197
207
 
198
208
  end
@@ -61,10 +61,38 @@ module JenkinsApi
61
61
  # * +:scm_branch+ branch to use in scm. Uses master by default
62
62
  # * +:scm_tag+ tag to download from scm. Only for CVS.
63
63
  # * +:scm_use_head_if_tag_not_found+ Only for CVS.
64
+ # * +:timer+ timer for running builds periodically.
64
65
  # * +:shell_command+ command to execute in the shell
66
+ # * +:notification_email+ email for sending notification
67
+ # * +:skype_targets+ skype targets for sending notifications to. Use *
68
+ # to specify group chats. Use space to separate multiple targets.
69
+ # Example: testuser *testgroup.
70
+ # * +:skype_strategy+ skype strategy to be used for sending
71
+ # notifications. Valid values: all, failure, failure_and_fixed,
72
+ # change. Default: change.
73
+ # * +:skype_notify_on_build_start+ Default: false
74
+ # * +:skype_notify_suspects+ Default: false
75
+ # * +:skype_notify_culprits+ Default: false
76
+ # * +:skype_notify_fixers+ Default: false
77
+ # * +:skype_notify_upstream_committers+ Default: false
78
+ # * +:skype_message+ what should be sent as notification message. Valid:
79
+ # just_summary, summary_and_scm_changes,
80
+ # summary_and_build_parameters, summary_scm_changes_and_failed_tests.
81
+ # Default: summary_and_scm_changes
65
82
  # * +:child_projects+ projects to add as downstream projects
66
83
  # * +:child_threshold+ threshold for child projects.
67
- # success, failure, or unstable. Default: failure.
84
+ # success, failure, or unstable. Default: failure.
85
+ #
86
+ # @example Create a Freestype Project
87
+ # create_freestyle(
88
+ # :name => "test_freestyle_job",
89
+ # :keep_dependencies => true,
90
+ # :concurrent_build => true,
91
+ # :scm_provider => "git",
92
+ # :scm_url => "git://github.com./arangamani/jenkins_api_client.git",
93
+ # :scm_branch => "master",
94
+ # :shell_command => "bundle install\n rake func_tests"
95
+ # )
68
96
  #
69
97
  def create_freestyle(params)
70
98
  # Supported SCM providers
@@ -211,7 +239,15 @@ module JenkinsApi
211
239
  "#{params[:block_build_when_downstream_building]}")
212
240
  xml.blockBuildWhenUpstreamBuilding(
213
241
  "#{params[:block_build_when_upstream_building]}")
214
- xml.triggers.vector
242
+ if params[:timer]
243
+ xml.triggers.vector {
244
+ xml.send("hudson.triggers.TimerTrigger") {
245
+ xml.spec params[:timer]
246
+ }
247
+ }
248
+ else
249
+ xml.triggers.vector
250
+ end
215
251
  xml.concurrentBuild "#{params[:concurrent_build]}"
216
252
  # Shell command stuff
217
253
  xml.builders {
@@ -244,6 +280,7 @@ module JenkinsApi
244
280
  "#{params[:notification_email_send_to_individuals]}")
245
281
  }
246
282
  end
283
+ skype_notification(params, xml) if params[:skype_targets]
247
284
  }
248
285
  xml.buildWrappers
249
286
  }
@@ -251,6 +288,58 @@ module JenkinsApi
251
288
  create(params[:name], builder.to_xml)
252
289
  end
253
290
 
291
+ # Adding skype notificaiton to a job
292
+ #
293
+ # @param [Hash] params parameters for adding skype notification
294
+ # * +:name+ name of the job to add skype notification
295
+ # * +:skype_targets+ skype targets for sending notifications to. Use *
296
+ # to specify group chats. Use space to separate multiple targets.
297
+ # Example: testuser, *testgroup.
298
+ # * +:skype_strategy+ skype strategy to be used for sending
299
+ # notifications. Valid values: all, failure, failure_and_fixed,
300
+ # change. Default: change.
301
+ # * +:skype_notify_on_build_start+ Default: false
302
+ # * +:skype_notify_suspects+ Default: false
303
+ # * +:skype_notify_culprits+ Default: false
304
+ # * +:skype_notify_fixers+ Default: false
305
+ # * +:skype_notify_upstream_committers+ Default: false
306
+ # * +:skype_message+ what should be sent as notification message. Valid:
307
+ # just_summary, summary_and_scm_changes, summary_and_build_parameters,
308
+ # summary_scm_changes_and_failed_tests.
309
+ # Default: summary_and_scm_changes
310
+ #
311
+ def add_skype_notification(params)
312
+ raise "No job name specified" unless params[:name]
313
+ raise "No Skype target specified" unless params[:skype_targets]
314
+ xml = get_config(params[:name])
315
+ n_xml = Nokogiri::XML(xml)
316
+ puts n_xml.xpath("//hudson.plugins.skype.im.transport.SkypePublisher")
317
+ if n_xml.xpath("//hudson.plugins.skype.im.transport.SkypePublisher").empty?
318
+ p_xml = Nokogiri::XML::Builder.new(:encoding => "UTF-8") { |xml|
319
+ skype_notification(params, xml)
320
+ }
321
+ skype_xml = Nokogiri::XML(p_xml.to_xml).xpath(
322
+ "//hudson.plugins.skype.im.transport.SkypePublisher"
323
+ ).first
324
+ n_xml.xpath("//publishers").first.add_child(skype_xml)
325
+ post_config(params[:name], n_xml.to_xml)
326
+ end
327
+ end
328
+
329
+ # Rename a job given the old name and new name
330
+ #
331
+ # @param [String] old_job Name of the old job
332
+ # @param [String] new_job Name of the new job.
333
+ #
334
+ def rename(old_job, new_job)
335
+ # Obtain the configuration of the old job
336
+ xml = get_config(old_job)
337
+ # Create the new job with the configuration obtained
338
+ create(new_job, xml)
339
+ # Delete the old job
340
+ delete(old_job)
341
+ end
342
+
254
343
  # Delete a job given the name
255
344
  #
256
345
  # @param [String] job_name
@@ -259,6 +348,15 @@ module JenkinsApi
259
348
  @client.api_post_request("/job/#{job_name}/doDelete")
260
349
  end
261
350
 
351
+ # Deletes all jobs from Jenkins
352
+ #
353
+ # @note This method will remove all jobs from Jenkins. Please use with
354
+ # caution.
355
+ #
356
+ def delete_all!
357
+ list_all.each { |job| delete(job) }
358
+ end
359
+
262
360
  # Stops a running build of a job
263
361
  # This method will stop the current/most recent build if no build number
264
362
  # is specified. The build will be stopped only if it was
@@ -293,7 +391,7 @@ module JenkinsApi
293
391
  # Get progressive console output from Jenkins server for a job
294
392
  #
295
393
  # @param [String] job_name Name of the Jenkins job
296
- # @param [Number] build_number Specific build number to obtain the
394
+ # @param [Number] build_num Specific build number to obtain the
297
395
  # console output from. Default is the recent build
298
396
  # @param [Number] start start offset to get only a portion of the text
299
397
  # @param [String] mode Mode of text output. 'text' or 'html'
@@ -476,13 +574,19 @@ module JenkinsApi
476
574
  end
477
575
 
478
576
  # Build a job given the name of the job
577
+ # You can optionally pass in a list of params for Jenkins to use for parameterized builds
479
578
  #
480
579
  # @param [String] job_name
580
+ # @param [Hash] params
481
581
  #
482
582
  # @return [String] response_code return code from HTTP POST
483
583
  #
484
- def build(job_name)
485
- @client.api_post_request("/job/#{job_name}/build")
584
+ def build(job_name, params={})
585
+ if params.empty?
586
+ @client.api_post_request("/job/#{job_name}/build")
587
+ else
588
+ @client.api_post_request("/job/#{job_name}/buildWithParameters", params)
589
+ end
486
590
  end
487
591
 
488
592
  # Obtain the configuration stored in config.xml of a specific job
@@ -893,6 +997,78 @@ module JenkinsApi
893
997
  filtered_job_names[0..parallel-1]
894
998
  end
895
999
 
1000
+ private
1001
+
1002
+ # Method for creating portion of xml that builds Skype notification
1003
+ # Use this option only when you have the Skype plugin installed and
1004
+ # everything is set up properly
1005
+ #
1006
+ # @param [Hash] params Parameters for adding skype notificaiton. For the
1007
+ # options in this params Hash refer to create_freestyle
1008
+ # @param [XML] xml Main xml to attach the skype portion.
1009
+ #
1010
+ def skype_notification(params, xml)
1011
+ params[:skype_strategy] = case params[:skype_strategy]
1012
+ when "all"
1013
+ "ALL"
1014
+ when "failure"
1015
+ "ANY_FAILURE"
1016
+ when "failure_and_fixed"
1017
+ "FAILURE_AND_FIXED"
1018
+ when "change"
1019
+ "STATECHANGE_ONLY"
1020
+ else
1021
+ "STATECHANGE_ONLY"
1022
+ end
1023
+
1024
+ params[:skype_notify_on_build_start] = false if params[:skype_notify_on_build_start].nil?
1025
+ params[:skype_notify_suspects] = false if params[:skype_notify_suspects].nil?
1026
+ params[:skype_notify_culprits] = false if params[:skype_notify_culprits].nil?
1027
+ params[:skype_notify_fixers] = false if params[:skype_notify_fixers].nil?
1028
+ params[:skype_notify_upstream_committers] = false if params[:skype_notify_upstream_committers].nil?
1029
+
1030
+ targets = params[:skype_targets].split(/\s+/)
1031
+ xml.send("hudson.plugins.skype.im.transport.SkypePublisher") {
1032
+ xml.targets {
1033
+ targets.each { |target|
1034
+ if target =~ /^\*/
1035
+ # Group Chat
1036
+ xml.send("hudson.plugins.im.GroupChatIMMessageTarget") {
1037
+ # Skipe the first * character
1038
+ xml.value target[1..-1]
1039
+ xml.notificationOnly false
1040
+ }
1041
+ else
1042
+ # Individual message
1043
+ xml.send("hudson.plugins.im.DefaultIMMessageTarget") {
1044
+ xml.value target
1045
+ }
1046
+ end
1047
+ }
1048
+ }
1049
+ xml.strategy "#{params[:skype_strategy]}"
1050
+ xml.notifyOnBuildStart params[:skype_notify_on_build_start]
1051
+ xml.notifySuspects params[:skype_notify_suspects]
1052
+ xml.notifyCulprits params[:skype_notify_culprits]
1053
+ xml.notifyFixers params[:skype_notify_fixers]
1054
+ xml.notifyUpstreamCommitters params[:skype_notify_upstream_committers]
1055
+ notification_class = case params[:skype_message]
1056
+ when "just_summary"
1057
+ "hudson.plugins.im.build_notify.SummaryOnlyBuildToChatNotifier"
1058
+ when "summary_and_scm_changes"
1059
+ "hudson.plugins.im.build_notify.DefaultBuildToChatNotifier"
1060
+ when "summary_and_build_parameters"
1061
+ "hudson.plugins.im.build_notify.BuildParametersBuildToChatNotifier"
1062
+ when "summary_scm_changes_and_failed_tests"
1063
+ "hudson.plugins.im.build_notify.PrintFailingTestsBuildToChatNotifier"
1064
+ else
1065
+ "hudson.plugins.im.build_notify.DefaultBuildToChatNotifier"
1066
+ end
1067
+ xml.buildToChatNotifier(:class => notification_class)
1068
+ xml.matrixMultiplier "ONLY_CONFIGURATIONS"
1069
+ }
1070
+ end
1071
+
896
1072
  end
897
1073
  end
898
1074
  end
@@ -108,6 +108,15 @@ module JenkinsApi
108
108
  # * +:slave_port+ Slave port
109
109
  # * +:private_key_file+ Private key file of master
110
110
  #
111
+ # @example Create a Dump Slave
112
+ # create_dump_slave(
113
+ # :name => "slave1",
114
+ # :slave_host => "10.10.10.10",
115
+ # :private_key_file => "/root/.ssh/id_rsa",
116
+ # :executors => 10,
117
+ # :labels => "slave, ruby"
118
+ # )
119
+ #
111
120
  def create_dump_slave(params)
112
121
 
113
122
  if list.include?(params[:name])
@@ -164,7 +173,7 @@ module JenkinsApi
164
173
 
165
174
  # Deletes the specified node
166
175
  #
167
- # @params [String] node_name Name of the node to delete
176
+ # @param [String] node_name Name of the node to delete
168
177
  #
169
178
  def delete(node_name)
170
179
  if list.include?(node_name)
@@ -174,6 +183,16 @@ module JenkinsApi
174
183
  end
175
184
  end
176
185
 
186
+ # Deletes all slaves from Jenkins. The master will be the only node alive
187
+ # after the exection of this call.
188
+ #
189
+ # @note This method will remove all slaves from Jenkins. Please use with
190
+ # caution.
191
+ #
192
+ def delete_all!
193
+ list.each { |node| delete(node) unless node == "master" }
194
+ end
195
+
177
196
  # This method lists all nodes
178
197
  #
179
198
  # @param [String] filter a regex to filter node names
@@ -249,7 +268,7 @@ module JenkinsApi
249
268
  #
250
269
  def get_config(node_name)
251
270
  node_name = "(master)" if node_name == "master"
252
- @client.get_config("/computer/#{node_name}/config.xml")
271
+ @client.get_config("/computer/#{node_name}")
253
272
  end
254
273
 
255
274
  # Posts the given config.xml to the Jenkins node
@@ -23,8 +23,8 @@
23
23
  module JenkinsApi
24
24
  class Client
25
25
  MAJOR = 0
26
- MINOR = 7
27
- TINY = 3
26
+ MINOR = 8
27
+ TINY = 0
28
28
  PRE = nil
29
29
  VERSION = [MAJOR, MINOR, TINY, PRE].compact.join('.')
30
30
  end
@@ -38,15 +38,103 @@ module JenkinsApi
38
38
  "#<JenkinsApi::Client::View>"
39
39
  end
40
40
 
41
- # Create a new view
42
- #
43
- # @param [String] view_name
44
- #
45
- def create(view_name)
46
- post_msg = "/createView?name=#{view_name}&"
47
- post_msg << "mode=hudson.model.ListView&json={\"name\":\"#{view_name}"
48
- post_msg << "\",\"mode\":\"hudson.model.ListView\"}"
49
- @client.api_post_request(post_msg)
41
+ # Creates a new empty view of the given type
42
+ #
43
+ # @param [String] view_name Name of the view to be created
44
+ # @param [String] type Type of view to be created. Valid options:
45
+ # listview, myview. Default: listview
46
+ #
47
+ def create(view_name, type = "listview")
48
+ mode = case type
49
+ when "listview"
50
+ "hudson.model.ListView"
51
+ when "myview"
52
+ "hudson.model.MyView"
53
+ end
54
+ initial_post_params = {
55
+ "name" => view_name,
56
+ "mode" => mode,
57
+ "json" => {
58
+ "name" => view_name,
59
+ "mode" => mode
60
+ }
61
+ }
62
+ @client.api_post_request("/createView", initial_post_params)
63
+ end
64
+
65
+ # Creates a listview by accepting the given parameters hash
66
+ #
67
+ # @param [Hash] params options to create the new view
68
+ # @option params [String] :name Name of the view
69
+ # @option params [String] :description Description of the view
70
+ # @option params [String] :status_filter Filter jobs based on the status.
71
+ # Valid options: all_selected_jobs, enabled_jobs_only,
72
+ # disabled_jobs_only. Default: all_selected_jobs
73
+ # @option params [TrueClass|FalseClass] :filter_queue true or false
74
+ # @option params [TrueClass|FalseClass] :filter_executors true or false
75
+ # @option params [String] :regex Regular expression to filter jobs that
76
+ # are to be added to the view
77
+ #
78
+ def create_list_view(params)
79
+ create(params[:name], "listview")
80
+ status_filter = case params[:status_filter]
81
+ when "all_selected_jobs"
82
+ ""
83
+ when "enabled_jobs_only"
84
+ "1"
85
+ when "disabled_jobs_only"
86
+ "2"
87
+ else
88
+ ""
89
+ end
90
+ post_params = {
91
+ "name" => params[:name],
92
+ "mode" => "hudson.model.ListView",
93
+ "description" => params[:description],
94
+ "statusFilter" => status_filter,
95
+ "json" => {
96
+ "name" => params[:name],
97
+ "description" => params[:description],
98
+ "mode" => "hudson.model.ListView",
99
+ "statusFilter" => "",
100
+ "columns" => [
101
+ {
102
+ "stapler-class" => "hudson.views.StatusColumn",
103
+ "kind"=> "hudson.views.StatusColumn"
104
+ },
105
+ {
106
+ "stapler-class" => "hudson.views.WeatherColumn",
107
+ "kind" => "hudson.views.WeatherColumn"
108
+ },
109
+ {
110
+ "stapler-class" => "hudson.views.JobColumn",
111
+ "kind" => "hudson.views.JobColumn"
112
+ },
113
+ {
114
+ "stapler-class" => "hudson.views.LastSuccessColumn",
115
+ "kind" => "hudson.views.LastSuccessColumn"
116
+ },
117
+ {
118
+ "stapler-class" => "hudson.views.LastFailureColumn",
119
+ "kind" => "hudson.views.LastFailureColumn"
120
+ },
121
+ {
122
+ "stapler-class" => "hudson.views.LastDurationColumn",
123
+ "kind" => "hudson.views.LastDurationColumn"
124
+ },
125
+ {
126
+ "stapler-class" => "hudson.views.BuildButtonColumn",
127
+ "kind" => "hudson.views.BuildButtonColumn"
128
+ }
129
+ ]
130
+ }.to_json
131
+ }
132
+ post_params.merge!("filterQueue" => "on") if params[:filter_queue]
133
+ post_params.merge!("filterExecutors" => "on") if params[:filter_executors]
134
+ post_params.merge!("useincluderegex" => "on",
135
+ "includeRegex" => params[:regex]) if params[:regex]
136
+ @client.api_post_request("/view/#{params[:name]}/configSubmit",
137
+ post_params)
50
138
  end
51
139
 
52
140
  # Delete a view
@@ -57,6 +145,15 @@ module JenkinsApi
57
145
  @client.api_post_request("/view/#{view_name}/doDelete")
58
146
  end
59
147
 
148
+ # Deletes all views (except the All view) in Jenkins.
149
+ #
150
+ # @note This method deletes all views (except the All view) available
151
+ # in Jenkins. Please use with caution.
152
+ #
153
+ def delete_all!
154
+ list.each { |view| delete(view) unless view == "All"}
155
+ end
156
+
60
157
  # This method lists all views
61
158
  #
62
159
  # @param [String] filter a regex to filter view names
@@ -58,66 +58,75 @@ describe JenkinsApi::Client::Job do
58
58
  end
59
59
 
60
60
  describe "#create_freestyle" do
61
+
62
+ def test_and_validate(name, params)
63
+ @client.job.create_freestyle(params).to_i.should == 200
64
+ @client.job.list(name).include?(name).should be_true
65
+ @client.job.delete(name).to_i.should == 302
66
+ @client.job.list(name).include?(name).should be_false
67
+ end
68
+
61
69
  it "Should be able to create a simple freestyle job" do
70
+ name = "test_job_name_using_params"
62
71
  params = {
63
- :name => "test_job_name_using_params"
72
+ :name => name
64
73
  }
65
- @client.job.create_freestyle(params).to_i.should == 200
66
- @client.job.delete("test_job_name_using_params").to_i.should == 302
74
+ test_and_validate(name, params)
67
75
  end
68
76
  it "Should be able to create a freestyle job with shell command" do
77
+ name = "test_job_using_params_shell"
69
78
  params = {
70
- :name => "test_job_using_params_shell",
79
+ :name => name,
71
80
  :shell_command => "echo this is a free style project"
72
81
  }
73
- @client.job.create_freestyle(params).to_i.should == 200
74
- @client.job.delete("test_job_using_params_shell").to_i.should == 302
82
+ test_and_validate(name, params)
75
83
  end
76
84
  it "Should accept Git SCM provider" do
85
+ name = "test_job_with_git_scm"
77
86
  params = {
78
- :name => "test_job_with_git_scm",
87
+ :name => name,
79
88
  :scm_provider => "git",
80
89
  :scm_url => "git://github.com./arangamani/jenkins_api_client.git",
81
90
  :scm_branch => "master"
82
91
  }
83
- @client.job.create_freestyle(params).to_i.should == 200
84
- @client.job.delete("test_job_with_git_scm").to_i.should == 302
92
+ test_and_validate(name, params)
85
93
  end
86
94
  it "Should accept subversion SCM provider" do
95
+ name = "test_job_with_subversion_scm"
87
96
  params = {
88
- :name => "test_job_with_subversion_scm",
97
+ :name => name,
89
98
  :scm_provider => "subversion",
90
99
  :scm_url => "http://svn.freebsd.org/base/",
91
100
  :scm_branch => "master"
92
101
  }
93
- @client.job.create_freestyle(params).to_i.should == 200
94
- @client.job.delete("test_job_with_subversion_scm").to_i.should == 302
102
+ test_and_validate(name, params)
95
103
  end
96
104
  it "Should accept CVS SCM provider with branch" do
105
+ name = "test_job_with_cvs_scm_branch"
97
106
  params = {
98
- :name => "test_job_with_cvs_scm_branch",
107
+ :name => name,
99
108
  :scm_provider => "cvs",
100
109
  :scm_url => "http://cvs.NetBSD.org",
101
110
  :scm_module => "src",
102
111
  :scm_branch => "MAIN"
103
112
  }
104
- @client.job.create_freestyle(params).to_i.should == 200
105
- @client.job.delete("test_job_with_cvs_scm_branch").to_i.should == 302
113
+ test_and_validate(name, params)
106
114
  end
107
115
  it "Should accept CVS SCM provider with tag" do
116
+ name = "test_job_with_cvs_scm_tag"
108
117
  params = {
109
- :name => "test_job_with_cvs_scm_tag",
118
+ :name => name,
110
119
  :scm_provider => "cvs",
111
120
  :scm_url => "http://cvs.NetBSD.org",
112
121
  :scm_module => "src",
113
122
  :scm_tag => "MAIN"
114
123
  }
115
- @client.job.create_freestyle(params).to_i.should == 200
116
- @client.job.delete("test_job_with_cvs_scm_tag").to_i.should == 302
124
+ test_and_validate(name, params)
117
125
  end
118
126
  it "Should fail if unsupported SCM is specified" do
127
+ name = "test_job_unsupported_scm"
119
128
  params = {
120
- :name => "test_job_unsupported_scm",
129
+ :name => name,
121
130
  :scm_provider => "non-existent",
122
131
  :scm_url => "http://non-existent.com/non-existent.non",
123
132
  :scm_branch => "master"
@@ -127,57 +136,119 @@ describe JenkinsApi::Client::Job do
127
136
  ).to raise_error
128
137
  end
129
138
  it "Should accept restricted_node option" do
139
+ name = "test_job_restricted_node"
130
140
  params = {
131
- :name => "test_job_restricted_node",
141
+ :name => name,
132
142
  :restricted_node => "master"
133
143
  }
134
- @client.job.create_freestyle(params).to_i.should == 200
135
- @client.job.delete("test_job_restricted_node").to_i.should == 302
144
+ test_and_validate(name, params)
136
145
  end
137
146
  it "Should accept block_build_when_downstream_building option" do
147
+ name = "test_job_block_build_when_downstream_building"
138
148
  params = {
139
- :name => "test_job_block_build_when_downstream_building",
149
+ :name => name,
140
150
  :block_build_when_downstream_building => true,
141
151
  }
142
- @client.job.create_freestyle(params).to_i.should == 200
143
- @client.job.delete(
144
- "test_job_block_build_when_downstream_building"
145
- ).to_i.should == 302
152
+ test_and_validate(name, params)
146
153
  end
147
154
  it "Should accept block_build_when_upstream_building option" do
155
+ name = "test_job_block_build_when_upstream_building"
148
156
  params = {
149
- :name => "test_job_block_build_when_upstream_building",
157
+ :name => name,
150
158
  :block_build_when_upstream_building => true
151
159
  }
152
- @client.job.create_freestyle(params).to_i.should == 200
153
- @client.job.delete(
154
- "test_job_block_build_when_upstream_building"
155
- ).to_i.should == 302
160
+ test_and_validate(name, params)
156
161
  end
157
162
  it "Should accept concurrent_build option" do
163
+ name = "test_job_concurrent_build"
158
164
  params = {
159
- :name => "test_job_concurrent_build",
165
+ :name => name,
160
166
  :concurrent_build => true
161
167
  }
162
- @client.job.create_freestyle(params).to_i.should == 200
163
- @client.job.delete("test_job_concurrent_build").to_i.should == 302
168
+ test_and_validate(name, params)
169
+ end
170
+ it "Should accept the timer option" do
171
+ name = "test_job_using_timer"
172
+ params = {
173
+ :name => name,
174
+ :timer => "* * * * *"
175
+ }
176
+ test_and_validate(name, params)
164
177
  end
165
178
  it "Should accept child projects option" do
179
+ name = "test_job_child_projects"
166
180
  params = {
167
- :name => "test_job_child_projects",
181
+ :name => name,
168
182
  :child_projects => @job_name,
169
183
  :child_threshold => "success"
170
184
  }
171
- @client.job.create_freestyle(params).to_i.should == 200
172
- @client.job.delete("test_job_child_projects").to_i.should == 302
185
+ test_and_validate(name, params)
173
186
  end
174
187
  it "Should accept notification_email option" do
188
+ name = "test_job_notification_email"
175
189
  params = {
176
- :name => "test_job_notification_email",
190
+ :name => name,
177
191
  :notification_email => "kannan@testdomain.com"
178
192
  }
193
+ test_and_validate(name, params)
194
+ end
195
+ it "Should accept notification for individual skype targets" do
196
+ name = "test_job_with_individual_skype_targets"
197
+ params = {
198
+ :name => name,
199
+ :skype_targets => "testuser"
200
+ }
201
+ test_and_validate(name, params)
202
+ end
203
+ it "Should accept notification for group skype targets" do
204
+ name = "test_job_with_group_skype_targets"
205
+ params = {
206
+ :name => name,
207
+ :skype_targets => "*testgroup"
208
+ }
209
+ test_and_validate(name, params)
210
+ end
211
+ it "Should accept complex skype configuration" do
212
+ name = "test_job_with_complex_skype_configuration"
213
+ params = {
214
+ :name => name,
215
+ :skype_targets => "testuser *testgroup anotheruser *anothergroup",
216
+ :skype_strategy => "failure_and_fixed",
217
+ :skype_notify_on_build_start => true,
218
+ :skype_notify_suspects => true,
219
+ :skype_notify_culprits => true,
220
+ :skype_notify_fixers => true,
221
+ :skype_notify_upstream_committers => false,
222
+ :skype_message => "summary_and_scm_changes"
223
+ }
224
+ test_and_validate(name, params)
225
+ end
226
+ end
227
+
228
+ describe "#add_skype_notification" do
229
+ it "Should accept skype configuration and add to existing job" do
230
+ name = "skype_notification_test_job"
231
+ params = {
232
+ :name => name
233
+ }
179
234
  @client.job.create_freestyle(params).to_i.should == 200
180
- @client.job.delete("test_job_notification_email").to_i.should == 302
235
+ @client.job.add_skype_notification(
236
+ :name => name,
237
+ :skype_targets => "testuser"
238
+ ).to_i.should == 200
239
+ @client.job.delete(name).to_i.should == 302
240
+ end
241
+ end
242
+ describe "#rename" do
243
+ it "Should accept new and old job names and rename the job" do
244
+ xml = @helper.create_job_xml
245
+ @client.job.create("old_job_rename_test", xml)
246
+ @client.job.rename("old_job_rename_test", "new_job_rename_test")
247
+ @client.job.list("old_job_rename_test").should == []
248
+ resp = @client.job.list("new_job_rename_test")
249
+ resp.size.should == 1
250
+ resp.first.should == "new_job_rename_test"
251
+ @client.job.delete("new_job_rename_test")
181
252
  end
182
253
  end
183
254
 
@@ -19,6 +19,12 @@ describe JenkinsApi::Client::Node do
19
19
  puts "WARNING: Credentials are not set properly."
20
20
  puts e.message
21
21
  end
22
+
23
+ @client.node.create_dump_slave(
24
+ :name => "slave",
25
+ :slave_host => "10.0.0.1",
26
+ :private_key_file => "/root/.ssh/id_rsa"
27
+ ) unless @client.node.list.include?("slave")
22
28
  end
23
29
 
24
30
  describe "InstanceMethods" do
@@ -170,5 +176,9 @@ describe JenkinsApi::Client::Node do
170
176
  end
171
177
 
172
178
  end
179
+
180
+ after(:all) do
181
+ @client.node.delete("slave")
182
+ end
173
183
  end
174
184
  end
@@ -93,6 +93,74 @@ describe JenkinsApi::Client::Job do
93
93
  @client.should_receive(:post_config)
94
94
  @job.create_freestyle(params)
95
95
  end
96
+ it "accepts timer and creates job" do
97
+ params = {
98
+ :name => "test_job_with_timer",
99
+ :timer => "* * * * *"
100
+ }
101
+ @client.should_receive(:post_config)
102
+ @job.create_freestyle(params)
103
+ end
104
+ it "accepts individual targets for skype notification" do
105
+ params = {
106
+ :name => "test_job_with_individual_skype_target",
107
+ :skype_targets => "testuser"
108
+ }
109
+ @client.should_receive(:post_config)
110
+ @job.create_freestyle(params)
111
+ end
112
+ it "accepts group targets for skype notification" do
113
+ params = {
114
+ :name => "test_job_with_group_skype_target",
115
+ :skype_targets => "*testgroup"
116
+ }
117
+ @client.should_receive(:post_config)
118
+ @job.create_freestyle(params)
119
+ end
120
+ it "accepts complex configuration for skype notifications" do
121
+ params = {
122
+ :name => "test_job_with_complex_skype_configuration",
123
+ :skype_targets => "testuser *testgroup anotheruser *anothergroup",
124
+ :skype_strategy => "failure_and_fixed",
125
+ :skype_notify_on_build_start => true,
126
+ :skype_notify_suspects => true,
127
+ :skype_notify_culprits => true,
128
+ :skype_notify_fixers => true,
129
+ :skype_notify_upstream_committers => false,
130
+ :skype_message => "summary_and_scm_changes"
131
+ }
132
+ @client.should_receive(:post_config)
133
+ @job.create_freestyle(params)
134
+ end
135
+ end
136
+
137
+ describe "#add_skype_notification" do
138
+ it "accepts skype configuration and adds to existing job" do
139
+ params = {
140
+ :name => "skype_notification_test_job"
141
+ }
142
+ @client.should_receive(:post_config)
143
+ @job.create_freestyle(params)
144
+ @client.should_receive(:get_config).and_return(@sample_job_xml)
145
+ @client.should_receive(:post_config)
146
+ @job.add_skype_notification(
147
+ :name => "skype_notification_test_job",
148
+ :skype_targets => "testuser"
149
+ )
150
+ end
151
+ end
152
+
153
+ describe "#rename" do
154
+ it "accepts the old and new job names and renames the job" do
155
+ @client.should_receive(:get_config).with("/job/old_job")
156
+ @client.should_receive(:api_post_request).with(
157
+ "/job/old_job/doDelete"
158
+ )
159
+ @client.should_receive(:post_config).with(
160
+ "/createItem?name=new_job", nil
161
+ )
162
+ @job.rename("old_job", "new_job")
163
+ end
96
164
  end
97
165
 
98
166
  describe "#delete" do
@@ -251,6 +319,11 @@ describe JenkinsApi::Client::Job do
251
319
  "/job/test_job/build").and_return(302)
252
320
  @job.build("test_job").should == 302
253
321
  end
322
+ it "accepts the job name with params and builds the job" do
323
+ @client.should_receive(:api_post_request).with(
324
+ "/job/test_job/buildWithParameters",{:branch => 'feature/new-stuff'}).and_return(302)
325
+ @job.build("test_job",{:branch => 'feature/new-stuff'}).should == 302
326
+ end
254
327
  end
255
328
 
256
329
  describe "#get_config" do
@@ -169,10 +169,8 @@ describe JenkinsApi::Client::Node do
169
169
 
170
170
  describe "#get_config" do
171
171
  it "accepts the node name and obtains the config xml from the server" do
172
- @client.should_receive(
173
- :get_config
174
- ).with(
175
- "/computer/slave/config.xml"
172
+ @client.should_receive(:get_config).with(
173
+ "/computer/slave"
176
174
  ).and_return(
177
175
  @sample_computer_xml
178
176
  )
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jenkins_api_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.8.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-05 00:00:00.000000000 Z
12
+ date: 2013-02-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
@@ -193,7 +193,6 @@ files:
193
193
  - Rakefile
194
194
  - bin/jenkinscli
195
195
  - config/login.yml.example
196
- - jenkins_api_client.gemspec
197
196
  - lib/jenkins_api_client.rb
198
197
  - lib/jenkins_api_client/build_queue.rb
199
198
  - lib/jenkins_api_client/cli/base.rb
@@ -1,101 +0,0 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
- # -*- encoding: utf-8 -*-
5
-
6
- Gem::Specification.new do |s|
7
- s.name = "jenkins_api_client"
8
- s.version = "0.7.2"
9
-
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Kannan Manickam"]
12
- s.date = "2013-02-02"
13
- s.description = "\nThis is a simple and easy-to-use Jenkins Api client with features focused on\nautomating Job configuration programaticaly and so forth"
14
- s.email = ["arangamani.kannan@gmail.com"]
15
- s.executables = ["jenkinscli"]
16
- s.files = [
17
- ".gitignore",
18
- ".jenkins.yml",
19
- ".travis.yml",
20
- "CHANGELOG.md",
21
- "Gemfile",
22
- "LICENCE",
23
- "README.md",
24
- "Rakefile",
25
- "bin/jenkinscli",
26
- "config/login.yml.example",
27
- "lib/jenkins_api_client.rb",
28
- "lib/jenkins_api_client/build_queue.rb",
29
- "lib/jenkins_api_client/cli/base.rb",
30
- "lib/jenkins_api_client/cli/helper.rb",
31
- "lib/jenkins_api_client/cli/job.rb",
32
- "lib/jenkins_api_client/cli/node.rb",
33
- "lib/jenkins_api_client/cli/system.rb",
34
- "lib/jenkins_api_client/client.rb",
35
- "lib/jenkins_api_client/exceptions.rb",
36
- "lib/jenkins_api_client/job.rb",
37
- "lib/jenkins_api_client/node.rb",
38
- "lib/jenkins_api_client/system.rb",
39
- "lib/jenkins_api_client/version.rb",
40
- "lib/jenkins_api_client/view.rb",
41
- "scripts/login_with_irb.rb",
42
- "spec/func_tests/client_spec.rb",
43
- "spec/func_tests/job_spec.rb",
44
- "spec/func_tests/node_spec.rb",
45
- "spec/func_tests/spec_helper.rb",
46
- "spec/func_tests/system_spec.rb",
47
- "spec/func_tests/view_spec.rb",
48
- "spec/unit_tests/client_spec.rb",
49
- "spec/unit_tests/fixtures/files/computer_sample.xml",
50
- "spec/unit_tests/fixtures/files/job_sample.xml",
51
- "spec/unit_tests/job_spec.rb",
52
- "spec/unit_tests/node_spec.rb",
53
- "spec/unit_tests/spec_helper.rb",
54
- "spec/unit_tests/system_spec.rb",
55
- "spec/unit_tests/view_spec.rb"
56
- ]
57
- s.homepage = "https://github.com/arangamani/jenkins_api_client"
58
- s.require_paths = ["lib"]
59
- s.rubygems_version = "1.8.24"
60
- s.summary = "Jenkins JSON API Client"
61
-
62
- if s.respond_to? :specification_version then
63
- s.specification_version = 3
64
-
65
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
66
- s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
67
- s.add_runtime_dependency(%q<activesupport>, ["~> 3.2.8"])
68
- s.add_runtime_dependency(%q<thor>, [">= 0.16.0"])
69
- s.add_runtime_dependency(%q<json>, [">= 0"])
70
- s.add_runtime_dependency(%q<terminal-table>, [">= 1.4.0"])
71
- s.add_runtime_dependency(%q<builder>, ["~> 3.1.3"])
72
- s.add_development_dependency(%q<bundler>, [">= 1.0"])
73
- s.add_development_dependency(%q<jeweler>, [">= 1.6.4"])
74
- s.add_development_dependency(%q<simplecov>, [">= 0"])
75
- s.add_development_dependency(%q<rspec>, [">= 0"])
76
- else
77
- s.add_dependency(%q<nokogiri>, [">= 0"])
78
- s.add_dependency(%q<activesupport>, ["~> 3.2.8"])
79
- s.add_dependency(%q<thor>, [">= 0.16.0"])
80
- s.add_dependency(%q<json>, [">= 0"])
81
- s.add_dependency(%q<terminal-table>, [">= 1.4.0"])
82
- s.add_dependency(%q<builder>, ["~> 3.1.3"])
83
- s.add_dependency(%q<bundler>, [">= 1.0"])
84
- s.add_dependency(%q<jeweler>, [">= 1.6.4"])
85
- s.add_dependency(%q<simplecov>, [">= 0"])
86
- s.add_dependency(%q<rspec>, [">= 0"])
87
- end
88
- else
89
- s.add_dependency(%q<nokogiri>, [">= 0"])
90
- s.add_dependency(%q<activesupport>, ["~> 3.2.8"])
91
- s.add_dependency(%q<thor>, [">= 0.16.0"])
92
- s.add_dependency(%q<json>, [">= 0"])
93
- s.add_dependency(%q<terminal-table>, [">= 1.4.0"])
94
- s.add_dependency(%q<builder>, ["~> 3.1.3"])
95
- s.add_dependency(%q<bundler>, [">= 1.0"])
96
- s.add_dependency(%q<jeweler>, [">= 1.6.4"])
97
- s.add_dependency(%q<simplecov>, [">= 0"])
98
- s.add_dependency(%q<rspec>, [">= 0"])
99
- end
100
- end
101
-