jenkins_api_client 1.0.0.alpha.2 → 1.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -124,8 +124,9 @@ module JenkinsApi
124
124
  # )
125
125
  #
126
126
  def create_dump_slave(params)
127
- unless params[:name] && params[:slave_host]
128
- raise ArgumentError, "Name, slave host are required for creating a slave."
127
+ unless params[:name] && params[:slave_host] && params[:private_key_file]
128
+ raise ArgumentError, "Name, slave host, and private key file are" +
129
+ " required for creating a slave."
129
130
  end
130
131
 
131
132
  @logger.info "Creating a dump slave '#{params[:name]}'"
@@ -136,11 +137,7 @@ module JenkinsApi
136
137
  :remote_fs => "/var/jenkins",
137
138
  :labels => params[:name],
138
139
  :slave_port => 22,
139
- :mode => "normal",
140
- :credential_id => "",
141
- :java_path => "",
142
- :prefix_start_slave_cmd => "",
143
- :suffix_start_slave_cmd => ""
140
+ :mode => "normal"
144
141
  }
145
142
 
146
143
  params = default_params.merge(params)
@@ -168,13 +165,8 @@ module JenkinsApi
168
165
  "stapler-class" => "hudson.plugins.sshslaves.SSHLauncher",
169
166
  "host" => params[:slave_host],
170
167
  "port" => params[:slave_port],
171
- "credentialsId" => params[:credential_id],
172
- "javaPath" => params[:java_path],
173
- "jvmOptions" => params[:jvm_options],
174
- "prefixStartSlaveCmd" => params[:prefix_start_slave_cmd],
175
- "suffixStartSlaveCmd" => params[:suffix_start_slave_cmd]
176
- #"username" => params[:slave_user],
177
- #"privatekey" => params[:private_key_file],
168
+ "username" => params[:slave_user],
169
+ "privatekey" => params[:private_key_file],
178
170
  }
179
171
  }.to_json
180
172
  }
@@ -302,37 +294,6 @@ module JenkinsApi
302
294
  @client.post_config("/computer/#{node_name}/config.xml", xml)
303
295
  end
304
296
 
305
-
306
- def create_cred
307
- post_params = {
308
- "name" => "testcred",
309
- "description" => "test cred description",
310
- "json" => {
311
- "domainCredentials" => {
312
- "domain" => {
313
- "name" => "",
314
- "description" => "",
315
- },
316
- "credentials" => {
317
- "scope" => "GLOBAL",
318
- "id" => "",
319
- "username" => "root",
320
- "description" => "root users credential",
321
- "privateKeySource" => {
322
- "value" => "0",
323
- "privateKey" => "blah blah blah",
324
- "stapler-class" => "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey$DirectEntryPrivateKeySource"
325
- },
326
- "passphrase" => "",
327
- "stapler-class" => "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey",
328
- "kind" => "com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey"
329
- }
330
- }
331
- }.to_json
332
- }
333
- @client.api_post_request("/credentials/configSubmit", post_params)
334
- end
335
-
336
297
  end
337
298
  end
338
299
  end
@@ -0,0 +1,17 @@
1
+ require 'uri'
2
+
3
+ module JenkinsApi
4
+ module UriHelper
5
+ # Encode a string for using in the query part of an URL
6
+ #
7
+ def form_encode(string)
8
+ URI.encode_www_form_component string.encode(Encoding::UTF_8)
9
+ end
10
+
11
+ # Encode a string for use in the hiearchical part of an URL
12
+ #
13
+ def path_encode(path)
14
+ URI.escape(path.encode(Encoding::UTF_8))
15
+ end
16
+ end
17
+ end
@@ -21,6 +21,7 @@
21
21
  #
22
22
 
23
23
  require 'timeout'
24
+ require 'jenkins_api_client/urihelper'
24
25
 
25
26
  module JenkinsApi
26
27
  class Client
@@ -31,6 +32,7 @@ module JenkinsApi
31
32
  # @since 0.14.0
32
33
  #
33
34
  class User
35
+ include JenkinsApi::UriHelper
34
36
 
35
37
  # Initializes a new User object.
36
38
  #
@@ -111,7 +113,7 @@ module JenkinsApi
111
113
  # }
112
114
  #
113
115
  def get(user_id)
114
- response = @client.api_get_request("/user/#{user_id}")
116
+ response = @client.api_get_request("/user/#{path_encode user_id}")
115
117
  end
116
118
 
117
119
  end
@@ -29,7 +29,7 @@ module JenkinsApi
29
29
  # Tiny version of the gem used for patches
30
30
  TINY = 0
31
31
  # Used for pre-releases
32
- PRE = 'alpha.2'
32
+ PRE = 'beta.1'
33
33
  # Version String of Jenkins API Client.
34
34
  VERSION = [MAJOR, MINOR, TINY, PRE].compact.join('.')
35
35
  end
@@ -20,6 +20,8 @@
20
20
  # THE SOFTWARE.
21
21
  #
22
22
 
23
+ require 'jenkins_api_client/urihelper'
24
+
23
25
  module JenkinsApi
24
26
  class Client
25
27
  # This class communicates with Jenkins "/view" API and used to create,
@@ -27,6 +29,7 @@ module JenkinsApi
27
29
  # API.
28
30
  #
29
31
  class View
32
+ include JenkinsApi::UriHelper
30
33
 
31
34
  # Initializes a new view object
32
35
  #
@@ -150,7 +153,7 @@ module JenkinsApi
150
153
  post_params.merge!("filterExecutors" => "on") if params[:filter_executors]
151
154
  post_params.merge!("useincluderegex" => "on",
152
155
  "includeRegex" => params[:regex]) if params[:regex]
153
- @client.api_post_request("/view/#{params[:name]}/configSubmit",
156
+ @client.api_post_request("/view/#{path_encode params[:name]}/configSubmit",
154
157
  post_params)
155
158
  end
156
159
 
@@ -160,7 +163,7 @@ module JenkinsApi
160
163
  #
161
164
  def delete(view_name)
162
165
  @logger.info "Deleting view '#{view_name}'"
163
- @client.api_post_request("/view/#{view_name}/doDelete")
166
+ @client.api_post_request("/view/#{path_encode view_name}/doDelete")
164
167
  end
165
168
 
166
169
  # Deletes all views (except the All view) in Jenkins.
@@ -211,7 +214,7 @@ module JenkinsApi
211
214
  job_names = []
212
215
  raise "The view #{view_name} doesn't exists on the server"\
213
216
  unless exists?(view_name)
214
- response_json = @client.api_get_request("/view/#{view_name}")
217
+ response_json = @client.api_get_request("/view/#{path_encode view_name}")
215
218
  response_json["jobs"].each do |job|
216
219
  job_names << job["name"]
217
220
  end
@@ -225,7 +228,7 @@ module JenkinsApi
225
228
  #
226
229
  def add_job(view_name, job_name)
227
230
  @logger.info "Adding job '#{job_name}' to view '#{view_name}'"
228
- post_msg = "/view/#{view_name}/addJobToView?name=#{job_name}"
231
+ post_msg = "/view/#{path_encode view_name}/addJobToView?name=#{form_encode job_name}"
229
232
  @client.api_post_request(post_msg)
230
233
  end
231
234
 
@@ -236,7 +239,7 @@ module JenkinsApi
236
239
  #
237
240
  def remove_job(view_name, job_name)
238
241
  @logger.info "Removing job '#{job_name}' from view '#{view_name}'"
239
- post_msg = "/view/#{view_name}/removeJobFromView?name=#{job_name}"
242
+ post_msg = "/view/#{path_encode view_name}/removeJobFromView?name=#{form_encode job_name}"
240
243
  @client.api_post_request(post_msg)
241
244
  end
242
245
 
@@ -246,7 +249,7 @@ module JenkinsApi
246
249
  #
247
250
  def get_config(view_name)
248
251
  @logger.info "Obtaining the configuration of view '#{view_name}'"
249
- @client.get_config("/view/#{view_name}")
252
+ @client.get_config("/view/#{path_encode view_name}")
250
253
  end
251
254
 
252
255
  # Post the configuration of a view given the view name and the config.xml
@@ -256,7 +259,7 @@ module JenkinsApi
256
259
  #
257
260
  def post_config(view_name, xml)
258
261
  @logger.info "Posting the configuration of view '#{view_name}'"
259
- @client.post_config("/view/#{view_name}/config.xml", xml)
262
+ @client.post_config("/view/#{path_encode view_name}/config.xml", xml)
260
263
  end
261
264
 
262
265
  end
@@ -481,6 +481,14 @@ describe JenkinsApi::Client::Job do
481
481
  end
482
482
 
483
483
  describe "#build" do
484
+
485
+ def wait_for_job_to_finish(job_name)
486
+ while @client.job.get_current_build_status(@job_name) == "running" do
487
+ # Waiting for this job to finish so it doesn't affect other tests
488
+ sleep 10
489
+ end
490
+ end
491
+
484
492
  it "Should build the specified job" do
485
493
  @client.job.get_current_build_status(
486
494
  @job_name
@@ -489,14 +497,89 @@ describe JenkinsApi::Client::Job do
489
497
  # As of Jenkins version 1.519 the job build responds with a 201
490
498
  # status code.
491
499
  @valid_post_responses.should include(response.to_i)
492
- # Sleep for 6 seconds so we don't hit the Jenkins quiet period (5
500
+ # Sleep for 10 seconds so we don't hit the Jenkins quiet period (5
493
501
  # seconds)
494
- sleep 6
502
+ sleep 10
495
503
  @client.job.get_current_build_status(@job_name).should == "running"
496
- while @client.job.get_current_build_status(@job_name) == "running" do
497
- # Waiting for this job to finish so it doesn't affect other tests
498
- sleep 10
499
- end
504
+ wait_for_job_to_finish(@job_name)
505
+ end
506
+
507
+ it "Should build the specified job (wait for start)" do
508
+ @client.job.get_current_build_status(
509
+ @job_name
510
+ ).should_not == "running"
511
+ expected_build_id = (@client.job.get_current_build_number(@job_name) || 0) + 1
512
+
513
+ build_opts = {
514
+ 'build_start_timeout' => 10,
515
+ 'progress_proc' => lambda do |max_wait, curr_wait, poll_count|
516
+ puts "Waited #{curr_wait}s of #{max_wait}s max - poll count = #{poll_count}"
517
+ end,
518
+ 'completion_proc' => lambda do |build_number, cancelled|
519
+ if build_number
520
+ puts "Wait over: build #{build_number} started"
521
+ else
522
+ puts "Wait over: build not started, build #{cancelled ? "" : "NOT "} cancelled"
523
+ end
524
+ end
525
+ }
526
+ build_id = @client.job.build(@job_name, {}, build_opts)
527
+ build_id.should_not be_nil
528
+ build_id.should eql(expected_build_id)
529
+ @client.job.get_current_build_status(@job_name).should == "running"
530
+ wait_for_job_to_finish(@job_name)
531
+ end
532
+
533
+ # This build doesn't start in time, but we don't cancel it, so it will run if
534
+ # Jenkins gets to it
535
+ it "Should build the specified job (wait for start - but not long enough)" do
536
+ @client.job.get_current_build_status(
537
+ @job_name
538
+ ).should_not == "running"
539
+
540
+ build_opts = {
541
+ 'build_start_timeout' => 1,
542
+ 'progress_proc' => lambda do |max_wait, curr_wait, poll_count|
543
+ puts "Waited #{curr_wait}s of #{max_wait}s max - poll count = #{poll_count}"
544
+ end,
545
+ 'completion_proc' => lambda do |build_number, cancelled|
546
+ if build_number
547
+ puts "Wait over: build #{build_number} started"
548
+ else
549
+ puts "Wait over: build not started, build #{cancelled ? "" : "NOT "}cancelled"
550
+ end
551
+ end
552
+ }
553
+ expect( lambda { @client.job.build(@job_name, {}, build_opts) } ).to raise_error(Timeout::Error)
554
+ # Sleep for 10 seconds so we don't hit the Jenkins quiet period (5
555
+ # seconds)
556
+ sleep 10
557
+ @client.job.get_current_build_status(@job_name).should == "running"
558
+ wait_for_job_to_finish(@job_name)
559
+ end
560
+
561
+ # This build doesn't start in time, and we will attempt to cancel it so it
562
+ # doesn't run
563
+ it "Should build the specified job (wait for start - but not long enough, cancelled)" do
564
+ @client.job.get_current_build_status(
565
+ @job_name
566
+ ).should_not == "running"
567
+
568
+ build_opts = {
569
+ 'build_start_timeout' => 1,
570
+ 'cancel_on_build_start_timeout' => true,
571
+ 'progress_proc' => lambda do |max_wait, curr_wait, poll_count|
572
+ puts "Waited #{curr_wait}s of #{max_wait}s max - poll count = #{poll_count}"
573
+ end,
574
+ 'completion_proc' => lambda do |build_number, cancelled|
575
+ if build_number
576
+ puts "Wait over: build #{build_number} started"
577
+ else
578
+ puts "Wait over: build not started, build #{cancelled ? "" : "NOT "}cancelled"
579
+ end
580
+ end
581
+ }
582
+ expect( lambda { @client.job.build(@job_name, {}, build_opts) } ).to raise_error(Timeout::Error)
500
583
  end
501
584
  end
502
585
 
@@ -527,7 +610,7 @@ describe JenkinsApi::Client::Job do
527
610
  @job_name
528
611
  ).should_not == "running"
529
612
  @client.job.build(@job_name)
530
- sleep 6
613
+ sleep 10
531
614
  @client.job.get_current_build_status(@job_name).should == "running"
532
615
  sleep 5
533
616
  @valid_post_responses.should include(
@@ -142,75 +142,129 @@ describe JenkinsApi::Client do
142
142
  end
143
143
 
144
144
  describe "InstanceMethods" do
145
- describe "#getroot" do
145
+ describe "#get_root" do
146
146
  it "is defined with no parameters" do
147
- expect(
148
- lambda { @client.get_root }
149
- ).not_to raise_error(NoMethodError)
147
+ @client.respond_to?(:get_root).should be_true
148
+ @client.method(:get_root).parameters.size.should == 0
150
149
  end
151
150
  end
152
151
 
153
152
  describe "#api_get_request" do
154
153
  it "defined and should accept url_prefix, tree, and url_suffix" do
155
- expect(
156
- lambda { @client.api_get_request("/some/prefix", "tree", "/json") }
157
- ).not_to raise_error(NoMethodError)
154
+ @client.respond_to?(:api_get_request).should be_true
155
+ @client.method(:api_get_request).parameters.size.should == 4
158
156
  end
159
157
  end
160
158
 
161
159
  describe "#api_post_request" do
162
160
  it "is defined and should accept url_prefix" do
163
- expect(
164
- lambda { @client.api_post_request("/some/prefix") }
165
- ).not_to raise_error(NoMethodError)
161
+ @client.respond_to?(:api_post_request).should be_true
162
+ @client.method(:api_post_request).parameters.size.should == 3
166
163
  end
167
164
  end
168
165
 
169
166
  describe "#get_config" do
170
167
  it "is defined and should accept url_prefix" do
171
- expect(
172
- lambda { @client.get_config("/some/prefix") }
173
- ).not_to raise_error(NoMethodError)
168
+ @client.respond_to?(:get_config).should be_true
169
+ @client.method(:get_config).parameters.size.should == 1
174
170
  end
175
171
  end
176
172
 
177
173
  describe "#post_config" do
178
174
  it "is defined and should accept url_prefix and xml" do
179
- expect(
180
- lambda { @client.post_config("/some/prefix", "<tag></tag>") }
181
- ).not_to raise_error(NoMethodError)
175
+ @client.respond_to?(:post_config).should be_true
176
+ @client.method(:post_config).parameters.size.should == 2
182
177
  end
183
178
  end
184
179
 
185
180
  describe "#get_jenkins_version" do
186
181
  it "is defined and accepts no parameters" do
187
- expect(
188
- lambda { @client.get_jenkins_version }
189
- ).not_to raise_error(NoMethodError)
182
+ @client.respond_to?(:get_jenkins_version).should be_true
183
+ @client.method(:get_jenkins_version).parameters.size.should == 0
190
184
  end
191
185
  end
192
186
 
193
187
  describe "#get_hudson_version" do
194
188
  it "is defined and accepts no parameters" do
195
- expect(
196
- lambda { @client.get_hudson_version }
197
- ).not_to raise_error(NoMethodError)
189
+ @client.respond_to?(:get_hudson_version).should be_true
190
+ @client.method(:get_hudson_version).parameters.size.should == 0
198
191
  end
199
192
  end
200
193
 
201
194
  describe "#get_server_date" do
202
195
  it "is defined and accepts no parameters" do
203
- expect(
204
- lambda { @client.get_server_date }
205
- ).not_to raise_error(NoMethodError)
196
+ @client.respond_to?(:get_server_date).should be_true
197
+ @client.method(:get_server_date).parameters.size.should == 0
206
198
  end
207
199
  end
208
200
 
209
201
  describe "#exec_cli" do
210
202
  it "is defined and should execute the CLI" do
203
+ @client.respond_to?(:exec_cli).should be_true
204
+ @client.method(:exec_cli).parameters.size.should == 2
205
+ end
206
+ end
207
+
208
+ describe "#deconstruct_version_string" do
209
+ it "is defined and accepts a single param" do
210
+ @client.respond_to?(:deconstruct_version_string).should be_true
211
+ @client.method(:deconstruct_version_string).parameters.size.should == 1
212
+ end
213
+
214
+ it "takes a version string in the form 'a.b' and returns an array [a,b,c]" do
215
+ TEST_2_PART_VERSION_STRING = "1.002"
216
+ version = @client.deconstruct_version_string(TEST_2_PART_VERSION_STRING)
217
+ version.should_not be_nil
218
+ version.should_not be_empty
219
+ version.size.should eql 3
220
+ version[0].should eql 1
221
+ version[1].should eql 2
222
+ version[2].should eql 0
223
+ end
224
+
225
+ it "takes a version string in the form 'a.b.c' and returns an array [a,b]" do
226
+ TEST_3_PART_VERSION_STRING = "1.002.3"
227
+ version = @client.deconstruct_version_string(TEST_3_PART_VERSION_STRING)
228
+ version.should_not be_nil
229
+ version.should_not be_empty
230
+ version.size.should eql 3
231
+ version[0].should eql 1
232
+ version[1].should eql 2
233
+ version[2].should eql 3
234
+ end
235
+
236
+ it "should fail if parameter is not a string" do
211
237
  expect(
212
- lambda { @client.exec_cli("version") }
213
- ).not_to raise_error(NoMethodError)
238
+ lambda { @client.deconstruct_version_string(1) }
239
+ ).to raise_error(NoMethodError) # match for fixnum
240
+ end
241
+
242
+ it "should return nil if parameter is not a string in the form '\d+.\d+(.\d+)'" do
243
+ @client.deconstruct_version_string("A.B").should be_nil
244
+ @client.deconstruct_version_string("1").should be_nil
245
+ @client.deconstruct_version_string("1.").should be_nil
246
+ @client.deconstruct_version_string("1.2.3.4").should be_nil
247
+ end
248
+ end
249
+
250
+ describe "#compare_versions" do
251
+ it "is defined and accepts two params" do
252
+ @client.respond_to?(:compare_versions).should be_true
253
+ @client.method(:compare_versions).parameters.size.should == 2
254
+ end
255
+
256
+ it "should correctly compare version numbers" do
257
+ @client.compare_versions("1.0", "1.0").should eql(0)
258
+ @client.compare_versions("1.0", "1.1").should eql(-1)
259
+ @client.compare_versions("1.1", "1.0").should eql(1)
260
+ @client.compare_versions("2.0", "1.99").should eql(1)
261
+ @client.compare_versions("1.10", "1.2").should eql(1)
262
+
263
+ @client.compare_versions("1.0.0", "1.0.0").should eql(0)
264
+ @client.compare_versions("1.0", "1.0.1").should eql(-1)
265
+ @client.compare_versions("1.1", "1.0.1").should eql(1)
266
+ @client.compare_versions("2.0.0", "1.999.99").should eql(1)
267
+ @client.compare_versions("1.0.10", "1.0.2").should eql(1)
214
268
  end
215
269
  end
216
270
  end