jenkins_api_client 1.5.3 → 2.1.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.
- checksums.yaml +5 -5
- data/jenkins_api_client.gemspec +3 -6
- data/lib/jenkins_api_client/client.rb +65 -13
- data/lib/jenkins_api_client/job.rb +175 -9
- data/lib/jenkins_api_client/node.rb +26 -2
- data/lib/jenkins_api_client/plugin_manager.rb +3 -3
- data/lib/jenkins_api_client/root.rb +67 -0
- data/lib/jenkins_api_client/system.rb +8 -1
- data/lib/jenkins_api_client/urihelper.rb +2 -1
- data/lib/jenkins_api_client/version.rb +1 -9
- data/lib/jenkins_api_client/view.rb +32 -0
- data/lib/jenkins_api_client.rb +1 -0
- metadata +25 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a499520438bb2fdcedc254768700d30b74c5c083e2557048a97b8a9f9b2e23ea
|
4
|
+
data.tar.gz: cf1d9d37530711baed6c6909ee34077a07c0161c68705ca3c7691d1ac53ba82e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '05659348d3846adbba1bb231ef5e751515d26aff76a2ea16d42ed4973507ca606192bfcd0bc5915d14e636c110d21dd3e2f99e59578f43e110c3f84724a3834f'
|
7
|
+
data.tar.gz: 0ad06756109a85dda032414524752cba25575061afb4f4b030d63d34d62b0d16373048bed46b0b624c4be1b204c858f5ca5b75592302328ea16c5765b4a065e2
|
data/jenkins_api_client.gemspec
CHANGED
@@ -6,18 +6,15 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.name = "jenkins_api_client"
|
7
7
|
s.version = ::JenkinsApi::Client::VERSION
|
8
8
|
|
9
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
10
|
-
s.require_paths = ["lib"]
|
11
9
|
s.authors = ["Kannan Manickam"]
|
12
10
|
s.description = "\nThis is a simple and easy-to-use Jenkins Api client with features focused on\nautomating Job configuration programaticaly and so forth"
|
13
11
|
s.email = ["arangamani.kannan@gmail.com"]
|
14
12
|
s.executables = ['jenkinscli']
|
15
13
|
s.files = `git ls-files -z`.split("\x0").select { |f| f.match(%r{lib/|bin/|java_deps/|gemspec}) }
|
16
|
-
s.require_paths = ['lib']
|
17
14
|
s.homepage = 'https://github.com/arangamani/jenkins_api_client'
|
18
|
-
s.required_ruby_version =
|
19
|
-
s.rubygems_version = "2.4.5.1"
|
15
|
+
s.required_ruby_version = '>= 2.7'
|
20
16
|
s.summary = "Jenkins JSON API Client"
|
17
|
+
s.licenses = ["MIT"]
|
21
18
|
|
22
19
|
s.add_dependency 'nokogiri', '~> 1.6'
|
23
20
|
s.add_dependency 'thor', '>= 0.16.0'
|
@@ -25,5 +22,5 @@ Gem::Specification.new do |s|
|
|
25
22
|
s.add_dependency 'mixlib-shellout', '>= 1.1.0'
|
26
23
|
s.add_dependency 'socksify', '>= 1.7.0'
|
27
24
|
s.add_dependency 'json', '>= 1.0'
|
25
|
+
s.add_dependency 'addressable', '~> 2.7'
|
28
26
|
end
|
29
|
-
|
@@ -30,6 +30,7 @@ require 'mixlib/shellout'
|
|
30
30
|
require 'uri'
|
31
31
|
require 'logger'
|
32
32
|
require 'socksify/http'
|
33
|
+
require 'open-uri'
|
33
34
|
|
34
35
|
# The main module that contains the Client class and all subclasses that
|
35
36
|
# communicate with the Jenkins's Remote Access API.
|
@@ -66,6 +67,9 @@ module JenkinsApi
|
|
66
67
|
"http_open_timeout",
|
67
68
|
"http_read_timeout",
|
68
69
|
"ssl",
|
70
|
+
"pkcs_file_path",
|
71
|
+
"pass_phrase",
|
72
|
+
"ca_file",
|
69
73
|
"follow_redirects",
|
70
74
|
"identity_file",
|
71
75
|
"cookies"
|
@@ -91,6 +95,9 @@ module JenkinsApi
|
|
91
95
|
# @option args [String] :proxy_protocol the proxy protocol ('socks' or 'http' (defaults to HTTP)
|
92
96
|
# @option args [String] :jenkins_path ("/") the optional context path for Jenkins
|
93
97
|
# @option args [Boolean] :ssl (false) indicates if Jenkins is accessible over HTTPS
|
98
|
+
# @option args [String] :pkcs_file_path ("/") the optional context path for pfx or p12 binary certificate file
|
99
|
+
# @option args [String] :pass_phrase password for pkcs_file_path certificate file
|
100
|
+
# @option args [String] :ca_file the path to a PEM encoded file containing trusted certificates used to verify peer certificate
|
94
101
|
# @option args [Boolean] :follow_redirects this argument causes the client to follow a redirect (jenkins can
|
95
102
|
# return a 30x when starting a build)
|
96
103
|
# @option args [Fixnum] :timeout (120) This argument sets the timeout for operations that take longer (in seconds)
|
@@ -237,6 +244,14 @@ module JenkinsApi
|
|
237
244
|
JenkinsApi::Client::User.new(self)
|
238
245
|
end
|
239
246
|
|
247
|
+
# Creates an instance of the Root class by passing a reference to self
|
248
|
+
#
|
249
|
+
# @return [JenkinsApi::Client::Root] An object of Root subclass
|
250
|
+
#
|
251
|
+
def root
|
252
|
+
JenkinsApi::Client::Root.new(self)
|
253
|
+
end
|
254
|
+
|
240
255
|
# Returns a string representing the class name
|
241
256
|
#
|
242
257
|
# @return [String] string representation of class name
|
@@ -252,6 +267,7 @@ module JenkinsApi
|
|
252
267
|
def inspect
|
253
268
|
"#<JenkinsApi::Client:0x#{(self.__id__ * 2).to_s(16)}" +
|
254
269
|
" @ssl=#{@ssl.inspect}," +
|
270
|
+
" @ca_file=#{@ca_file.inspect}," +
|
255
271
|
" @log_location=#{@log_location.inspect}," +
|
256
272
|
" @log_level=#{@log_level.inspect}," +
|
257
273
|
" @crumbs_enabled=#{@crumbs_enabled.inspect}," +
|
@@ -269,13 +285,7 @@ module JenkinsApi
|
|
269
285
|
#
|
270
286
|
def get_artifact(job_name,filename)
|
271
287
|
@artifact = job.find_artifact(job_name)
|
272
|
-
|
273
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
274
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
275
|
-
http.use_ssl = @ssl
|
276
|
-
request = Net::HTTP::Get.new(uri.request_uri)
|
277
|
-
request.basic_auth(@username, @password)
|
278
|
-
response = http.request(request)
|
288
|
+
response = make_http_request(Net::HTTP::Get.new(@artifact))
|
279
289
|
if response.code == "200"
|
280
290
|
File.write(File.expand_path(filename), response.body)
|
281
291
|
else
|
@@ -283,6 +293,41 @@ module JenkinsApi
|
|
283
293
|
end
|
284
294
|
end
|
285
295
|
|
296
|
+
# Connects to the server and download all artifacts of a build to a specified location
|
297
|
+
#
|
298
|
+
# @param [String] job_name
|
299
|
+
# @param [String] dldir location to save artifacts
|
300
|
+
# @param [Integer] build_number optional, defaults to current build
|
301
|
+
# @returns [String, Array] list of retrieved artifacts
|
302
|
+
#
|
303
|
+
def get_artifacts(job_name, dldir, build_number = nil)
|
304
|
+
@artifacts = job.find_artifacts(job_name,build_number)
|
305
|
+
results = []
|
306
|
+
@artifacts.each do |artifact|
|
307
|
+
uri = URI.parse(artifact)
|
308
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
309
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
310
|
+
http.use_ssl = @ssl
|
311
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
312
|
+
request.basic_auth(@username, @password)
|
313
|
+
response = http.request(request)
|
314
|
+
# we want every thing after the last 'build' in the path to become the filename
|
315
|
+
if artifact.include?('/build/')
|
316
|
+
filename = artifact.split("/build/").last.gsub('/','-')
|
317
|
+
else
|
318
|
+
filename = File.basename(artifact)
|
319
|
+
end
|
320
|
+
filename = File.join(dldir, filename)
|
321
|
+
results << filename
|
322
|
+
if response.code == "200"
|
323
|
+
File.write(File.expand_path(filename), response.body)
|
324
|
+
else
|
325
|
+
raise "Couldn't get the artifact #{artifact} for job #{job}"
|
326
|
+
end
|
327
|
+
end
|
328
|
+
results
|
329
|
+
end
|
330
|
+
|
286
331
|
# Connects to the Jenkins server, sends the specified request and returns
|
287
332
|
# the response.
|
288
333
|
#
|
@@ -300,19 +345,26 @@ module JenkinsApi
|
|
300
345
|
when 'http'
|
301
346
|
http = Net::HTTP::Proxy(@proxy_ip, @proxy_port).new(@server_ip, @server_port)
|
302
347
|
when 'socks'
|
303
|
-
http = Net::HTTP::SOCKSProxy(@proxy_ip, @proxy_port).
|
348
|
+
http = Net::HTTP::SOCKSProxy(@proxy_ip, @proxy_port).new(@server_ip, @server_port)
|
304
349
|
else
|
305
|
-
raise "
|
350
|
+
raise "unknown proxy protocol: '#{@proxy_protocol}'"
|
306
351
|
end
|
307
352
|
else
|
308
353
|
http = Net::HTTP.new(@server_ip, @server_port)
|
309
354
|
end
|
310
355
|
|
311
|
-
if @ssl
|
356
|
+
if @ssl && @pkcs_file_path
|
312
357
|
http.use_ssl = true
|
358
|
+
pkcs12 =OpenSSL::PKCS12.new(File.binread(@pkcs_file_path), @pass_phrase!=nil ? @pass_phrase : "")
|
359
|
+
http.cert = pkcs12.certificate
|
360
|
+
http.key = pkcs12.key
|
313
361
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
314
|
-
|
362
|
+
elsif @ssl
|
363
|
+
http.use_ssl = true
|
315
364
|
|
365
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
366
|
+
http.ca_file = @ca_file if @ca_file
|
367
|
+
end
|
316
368
|
http.open_timeout = @http_open_timeout
|
317
369
|
http.read_timeout = @http_read_timeout
|
318
370
|
|
@@ -490,7 +542,7 @@ module JenkinsApi
|
|
490
542
|
@logger.info "Initializing Jenkins Update Center..."
|
491
543
|
@logger.debug "Obtaining the JSON data for Update Center..."
|
492
544
|
# TODO: Clean me up
|
493
|
-
update_center_data = open("
|
545
|
+
update_center_data = open("https://updates.jenkins.io/current/update-center.json").read
|
494
546
|
# The Jenkins mirror returns the data in the following format
|
495
547
|
# updateCenter.post(
|
496
548
|
# {.. JSON data...}
|
@@ -754,7 +806,7 @@ module JenkinsApi
|
|
754
806
|
# the queue.
|
755
807
|
when 200, 201, 302
|
756
808
|
if to_send == "body" && send_json
|
757
|
-
return JSON.parse(response.body)
|
809
|
+
return JSON.parse(response.body, max_nesting: false)
|
758
810
|
elsif to_send == "body"
|
759
811
|
return response.body
|
760
812
|
elsif to_send == "code"
|
@@ -299,6 +299,16 @@ module JenkinsApi
|
|
299
299
|
xml.description
|
300
300
|
xml.keepDependencies "#{params[:keep_dependencies]}"
|
301
301
|
xml.properties
|
302
|
+
#buildlogs related stuff
|
303
|
+
if params[:discard_old_builds]
|
304
|
+
xml.logRotator(:class => 'hudson.tasks.LogRotator') do
|
305
|
+
xml.daysToKeep params[:discard_old_builds][:daysToKeep] || -1
|
306
|
+
xml.numToKeep params[:discard_old_builds][:numToKeep] || -1
|
307
|
+
xml.artifactDaysToKeep params[:discard_old_builds][:artifactDaysToKeep] || -1
|
308
|
+
xml.artifactNumToKeep params[:discard_old_builds][:artifactNumToKeep] || -1
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
302
312
|
# SCM related stuff
|
303
313
|
if params[:scm_provider] == 'subversion'
|
304
314
|
# Build subversion related XML portion
|
@@ -744,13 +754,30 @@ module JenkinsApi
|
|
744
754
|
"not_run"
|
745
755
|
when "aborted"
|
746
756
|
"aborted"
|
757
|
+
when "disabled"
|
758
|
+
"disabled"
|
747
759
|
else
|
748
760
|
"invalid"
|
749
761
|
end
|
750
762
|
end
|
751
763
|
|
764
|
+
# Determine if the build is queued
|
765
|
+
#
|
766
|
+
# @param [String] job_name
|
767
|
+
#
|
768
|
+
# @return [Integer] build number if queued, or [Boolean] false if not queued
|
769
|
+
#
|
770
|
+
def queued?(job_name)
|
771
|
+
queue_result = @client.api_get_request("/job/#{path_encode job_name}")['inQueue']
|
772
|
+
if queue_result
|
773
|
+
return @client.api_get_request("/job/#{path_encode job_name}")['nextBuildNumber']
|
774
|
+
else
|
775
|
+
return queue_result
|
776
|
+
end
|
777
|
+
end
|
778
|
+
|
752
779
|
# Obtain the current build status of the job
|
753
|
-
# By
|
780
|
+
# By default Jenkins returns the color of the job status icon
|
754
781
|
# This function translates the color into a meaningful status
|
755
782
|
#
|
756
783
|
# @param [String] job_name
|
@@ -1086,6 +1113,23 @@ module JenkinsApi
|
|
1086
1113
|
nil
|
1087
1114
|
end
|
1088
1115
|
|
1116
|
+
# Obtain the plugin results for a specific build of a job
|
1117
|
+
#
|
1118
|
+
# @param [String] job_name
|
1119
|
+
# @param [Number] build_num
|
1120
|
+
# @param [String] plugin_name
|
1121
|
+
#
|
1122
|
+
def get_plugin_results(job_name, build_num, plugin_name)
|
1123
|
+
build_num = get_current_build_number(job_name) if build_num == 0
|
1124
|
+
@logger.info "Obtaining the '#{plugin_name}' plugin results of '#{job_name}'" +
|
1125
|
+
" Build ##{build_num}"
|
1126
|
+
@client.api_get_request("/job/#{path_encode job_name}/#{build_num}/#{plugin_name}Result")
|
1127
|
+
rescue Exceptions::NotFound
|
1128
|
+
# Not found is acceptable, as not all builds will have plugin results
|
1129
|
+
# and this is what jenkins throws at us in that case
|
1130
|
+
nil
|
1131
|
+
end
|
1132
|
+
|
1089
1133
|
# Obtain detailed build info for a job
|
1090
1134
|
#
|
1091
1135
|
# @param [String] job_name
|
@@ -1399,6 +1443,71 @@ module JenkinsApi
|
|
1399
1443
|
post_config(job_name, xml_modified)
|
1400
1444
|
end
|
1401
1445
|
|
1446
|
+
# Add upstream projects to a specific job given the job name,
|
1447
|
+
# projects to be added as upstream projects, and the threshold
|
1448
|
+
#
|
1449
|
+
# @param [String] job_name
|
1450
|
+
# @param [String] upstream_projects - separated with comma
|
1451
|
+
# @param [String] threshold - failure, success, or unstable
|
1452
|
+
# @param [Boolean] overwrite - true or false
|
1453
|
+
#
|
1454
|
+
# @return [String] response_code return code from HTTP POST
|
1455
|
+
#
|
1456
|
+
def add_upstream_projects(job_name,
|
1457
|
+
upstream_projects,
|
1458
|
+
threshold, overwrite = false)
|
1459
|
+
@logger.info "Adding #{upstream_projects.inspect} as upstream" +
|
1460
|
+
" projects for '#{job_name}' with the threshold of '#{threshold}'" +
|
1461
|
+
" and overwrite option of '#{overwrite}'"
|
1462
|
+
name, ord, col = get_threshold_params(threshold)
|
1463
|
+
xml = get_config(job_name)
|
1464
|
+
n_xml = Nokogiri::XML(xml)
|
1465
|
+
upstream_projects_node = n_xml.xpath("//upstreamProjects").first
|
1466
|
+
if upstream_projects_node
|
1467
|
+
if overwrite
|
1468
|
+
upstream_projects_node.content = "#{upstream_projects}"
|
1469
|
+
else
|
1470
|
+
to_replace = upstream_projects_node.content +
|
1471
|
+
", #{upstream_projects}"
|
1472
|
+
upstream_projects_node.content = to_replace
|
1473
|
+
end
|
1474
|
+
else
|
1475
|
+
triggers_node = n_xml.xpath("//triggers").first
|
1476
|
+
reverse_build_trigger_node = triggers_node.add_child(
|
1477
|
+
"<jenkins.triggers.ReverseBuildTrigger/>"
|
1478
|
+
)
|
1479
|
+
reverse_build_trigger_node.first.add_child(
|
1480
|
+
"<spec/>"
|
1481
|
+
)
|
1482
|
+
reverse_build_trigger_node.first.add_child(
|
1483
|
+
"<upstreamProjects>#{upstream_projects}</upstreamProjects>"
|
1484
|
+
)
|
1485
|
+
threshold_node = reverse_build_trigger_node.first.add_child(
|
1486
|
+
"<threshold/>"
|
1487
|
+
)
|
1488
|
+
threshold_node.first.add_child(
|
1489
|
+
"<name>#{name}</name><ordinal>#{ord}</ordinal><color>#{col}</color>"
|
1490
|
+
)
|
1491
|
+
end
|
1492
|
+
xml_modified = n_xml.to_xml
|
1493
|
+
post_config(job_name, xml_modified)
|
1494
|
+
end
|
1495
|
+
|
1496
|
+
# Remove all upstream projects of a specific job
|
1497
|
+
#
|
1498
|
+
# @param [String] job_name
|
1499
|
+
#
|
1500
|
+
# @return [String] response_code return code from HTTP POST
|
1501
|
+
#
|
1502
|
+
def remove_upstream_projects(job_name)
|
1503
|
+
@logger.info "Removing the upstream projects of '#{job_name}'"
|
1504
|
+
xml = get_config(job_name)
|
1505
|
+
n_xml = Nokogiri::XML(xml)
|
1506
|
+
n_xml.search("//jenkins.triggers.ReverseBuildTrigger").remove
|
1507
|
+
xml_modified = n_xml.to_xml
|
1508
|
+
post_config(job_name, xml_modified)
|
1509
|
+
end
|
1510
|
+
|
1402
1511
|
# Resctrict the given job to a specific node
|
1403
1512
|
#
|
1404
1513
|
# @param [String] job_name
|
@@ -1546,15 +1655,49 @@ module JenkinsApi
|
|
1546
1655
|
#A Method to find artifacts path from the Current Build
|
1547
1656
|
#
|
1548
1657
|
# @param [String] job_name
|
1658
|
+
# @param [Integer] build_number
|
1659
|
+
# defaults to latest build
|
1549
1660
|
#
|
1550
|
-
def find_artifact(job_name)
|
1551
|
-
|
1552
|
-
|
1553
|
-
|
1554
|
-
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1661
|
+
def find_artifact(job_name, build_number = 0)
|
1662
|
+
find_artifacts(job_name, build_number).first
|
1663
|
+
end
|
1664
|
+
|
1665
|
+
#A Method to check artifact exists path from the Current Build
|
1666
|
+
#
|
1667
|
+
# @param [String] job_name
|
1668
|
+
# @param [Integer] build_number
|
1669
|
+
# defaults to latest build
|
1670
|
+
#
|
1671
|
+
def artifact_exists?(job_name, build_number = 0)
|
1672
|
+
begin
|
1673
|
+
artifact_path(job_name: job_name, build_number: build_number)
|
1674
|
+
|
1675
|
+
return true
|
1676
|
+
rescue Exception => e
|
1677
|
+
return false
|
1678
|
+
end
|
1679
|
+
end
|
1680
|
+
|
1681
|
+
# Find the artifacts for build_number of job_name, defaulting to current job
|
1682
|
+
#
|
1683
|
+
# @param [String] job_name
|
1684
|
+
# @param [Integer] build_number Optional build number
|
1685
|
+
# @return [String, Hash] JSON response from Jenkins
|
1686
|
+
#
|
1687
|
+
def find_artifacts(job_name, build_number = nil)
|
1688
|
+
response_json = get_build_details(job_name, build_number)
|
1689
|
+
artifact_path(build_details: response_json).map do |p|
|
1690
|
+
path_encode("#{response_json['url']}artifact/#{p['relativePath']}")
|
1691
|
+
end
|
1692
|
+
end
|
1693
|
+
|
1694
|
+
# Find the artifacts for the current job
|
1695
|
+
#
|
1696
|
+
# @param [String] job_name
|
1697
|
+
# @return [String, Hash] JSON response from Jenkins
|
1698
|
+
#
|
1699
|
+
def find_latest_artifacts(job_name)
|
1700
|
+
find_artifacts(job_name)
|
1558
1701
|
end
|
1559
1702
|
|
1560
1703
|
private
|
@@ -1795,6 +1938,29 @@ module JenkinsApi
|
|
1795
1938
|
return nil unless tree_value
|
1796
1939
|
"tree=#{tree_value}"
|
1797
1940
|
end
|
1941
|
+
|
1942
|
+
# This private method gets the artifact path or throws an exception
|
1943
|
+
#
|
1944
|
+
# @param [Hash] job_name, build_number or build_details object
|
1945
|
+
#
|
1946
|
+
def artifact_path(params)
|
1947
|
+
job_name = params[:job_name]
|
1948
|
+
build_number = params[:build_number] || 0
|
1949
|
+
build_details = params[:build_details]
|
1950
|
+
|
1951
|
+
build_details = get_build_details(job_name, build_number) if build_details.nil?
|
1952
|
+
artifacts = build_details['artifacts']
|
1953
|
+
artifact_paths = []
|
1954
|
+
|
1955
|
+
if artifacts && artifacts.any?
|
1956
|
+
artifact_paths = artifacts.find_all{ |a| a.key?('relativePath') }
|
1957
|
+
end
|
1958
|
+
|
1959
|
+
if artifact_paths.empty?
|
1960
|
+
raise "No artifacts found."
|
1961
|
+
end
|
1962
|
+
artifact_paths
|
1963
|
+
end
|
1798
1964
|
end
|
1799
1965
|
end
|
1800
1966
|
end
|
@@ -211,18 +211,42 @@ module JenkinsApi
|
|
211
211
|
list.each { |node| delete(node) unless node == "master" }
|
212
212
|
end
|
213
213
|
|
214
|
+
# This method returns two lists 1) nodes online 2) nodes offline
|
215
|
+
#
|
216
|
+
# @param [String] filter a regex to filter node names
|
217
|
+
# @param [Bool] ignorecase whether to be case sensitive or not
|
218
|
+
#
|
219
|
+
def online_offline_lists(filter = nil, ignorecase = true)
|
220
|
+
@logger.info "Obtaining nodes from jenkins matching filter '#{filter}'"
|
221
|
+
offline_node_names = []
|
222
|
+
online_node_names = []
|
223
|
+
response_json = @client.api_get_request("/computer")
|
224
|
+
response_json["computer"].each do |computer|
|
225
|
+
if computer["displayName"] =~ /#{filter}/i
|
226
|
+
if computer["offline"] == true
|
227
|
+
offline_node_names << computer["displayName"]
|
228
|
+
else
|
229
|
+
online_node_names << computer["displayName"]
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
return online_node_names, offline_node_names
|
234
|
+
end
|
235
|
+
|
214
236
|
# This method lists all nodes
|
215
237
|
#
|
216
238
|
# @param [String] filter a regex to filter node names
|
217
239
|
# @param [Bool] ignorecase whether to be case sensitive or not
|
218
240
|
#
|
219
|
-
def list(filter = nil, ignorecase = true)
|
241
|
+
def list(filter = nil, ignorecase = true, slaveonly = false)
|
220
242
|
@logger.info "Obtaining nodes from jenkins matching filter '#{filter}'"
|
221
243
|
node_names = []
|
222
244
|
response_json = @client.api_get_request("/computer")
|
223
245
|
response_json["computer"].each do |computer|
|
224
246
|
if computer["displayName"] =~ /#{filter}/i
|
225
|
-
|
247
|
+
unless slaveonly && computer["displayName"] == "master"
|
248
|
+
node_names << computer["displayName"]
|
249
|
+
end
|
226
250
|
end
|
227
251
|
end
|
228
252
|
node_names
|
@@ -148,7 +148,7 @@ module JenkinsApi
|
|
148
148
|
# "pinned"=>true,
|
149
149
|
# "shortName"=>"ldap",
|
150
150
|
# "supportsDynamicLoad"=>"MAYBE",
|
151
|
-
# "url"=>"
|
151
|
+
# "url"=>"https://wiki.jenkins.io/display/JENKINS/LDAP+Plugin",
|
152
152
|
# "version"=>"1.5"
|
153
153
|
# }
|
154
154
|
#
|
@@ -256,7 +256,7 @@ module JenkinsApi
|
|
256
256
|
# => {
|
257
257
|
# "name"=>"status-view",
|
258
258
|
# "sourceId"=>"default",
|
259
|
-
# "url"=>"
|
259
|
+
# "url"=>"https://updates.jenkins.io/download/plugins/status-view/1.0/status-view.hpi",
|
260
260
|
# "version"=>"1.0",
|
261
261
|
# "categories"=>["ui"],
|
262
262
|
# "compatibleSinceVersion"=>nil,
|
@@ -266,7 +266,7 @@ module JenkinsApi
|
|
266
266
|
# "installed"=>nil, "neededDependencies"=>[],
|
267
267
|
# "requiredCore"=>"1.342",
|
268
268
|
# "title"=>"Status View Plugin",
|
269
|
-
# "wiki"=>"https://wiki.jenkins
|
269
|
+
# "wiki"=>"https://wiki.jenkins.io/display/JENKINS/Status+View+Plugin"
|
270
270
|
# }
|
271
271
|
#
|
272
272
|
def get_available_info(plugin)
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#
|
2
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
3
|
+
# of this software and associated documentation files (the "Software"), to deal
|
4
|
+
# in the Software without restriction, including without limitation the rights
|
5
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
6
|
+
# copies of the Software, and to permit persons to whom the Software is
|
7
|
+
# furnished to do so, subject to the following conditions:
|
8
|
+
#
|
9
|
+
# The above copyright notice and this permission notice shall be included in
|
10
|
+
# all copies or substantial portions of the Software.
|
11
|
+
#
|
12
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
13
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
14
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
15
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
16
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
17
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
18
|
+
# THE SOFTWARE.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'jenkins_api_client/urihelper'
|
22
|
+
|
23
|
+
module JenkinsApi
|
24
|
+
class Client
|
25
|
+
# This class communicates with Jenkins API at the root address to obtain details
|
26
|
+
# on the page displayed to users on the Jenkins' 'homepage,' and other
|
27
|
+
# data items such as quietingDown
|
28
|
+
class Root
|
29
|
+
include JenkinsApi::UriHelper
|
30
|
+
|
31
|
+
# Initializes a new root object
|
32
|
+
#
|
33
|
+
# @param client [Client] the client object
|
34
|
+
#
|
35
|
+
# @return [Root] the root object
|
36
|
+
#
|
37
|
+
def initialize(client)
|
38
|
+
@client = client
|
39
|
+
@logger = @client.logger
|
40
|
+
end
|
41
|
+
|
42
|
+
# Return a string representation of the object
|
43
|
+
#
|
44
|
+
def to_s
|
45
|
+
"#<JenkinsApi::Client::Root>"
|
46
|
+
end
|
47
|
+
|
48
|
+
# Check if Jenkins is in shutdown mode
|
49
|
+
#
|
50
|
+
# @return [Boolean] true if server in shutdown mode
|
51
|
+
#
|
52
|
+
def quieting_down?
|
53
|
+
response_json = @client.api_get_request('', 'tree=quietingDown')
|
54
|
+
response_json['quietingDown']
|
55
|
+
end
|
56
|
+
|
57
|
+
# Get message displayed to users on the homepage
|
58
|
+
#
|
59
|
+
# @return [String] description - message displayed to users
|
60
|
+
#
|
61
|
+
def description
|
62
|
+
response_json = @client.api_get_request('', 'tree=description')
|
63
|
+
response_json['description']
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -54,13 +54,20 @@ module JenkinsApi
|
|
54
54
|
@client.api_post_request("/quietDown")
|
55
55
|
end
|
56
56
|
|
57
|
-
# Cancels the quiet
|
57
|
+
# Cancels the quiet down request sent to the server.
|
58
58
|
#
|
59
59
|
def cancel_quiet_down
|
60
60
|
@logger.info "Cancelling jenkins form quiet down..."
|
61
61
|
@client.api_post_request("/cancelQuietDown")
|
62
62
|
end
|
63
63
|
|
64
|
+
# Checks if server is in quiet down mode.
|
65
|
+
#
|
66
|
+
def check_quiet_down?
|
67
|
+
@logger.info "Checking if jenkins is in quiet down mode..."
|
68
|
+
@client.root.quieting_down?
|
69
|
+
end
|
70
|
+
|
64
71
|
# Restarts the Jenkins server
|
65
72
|
#
|
66
73
|
# @param [Boolean] force whether to force restart or wait till all
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'uri'
|
2
|
+
require 'addressable/uri'
|
2
3
|
|
3
4
|
module JenkinsApi
|
4
5
|
module UriHelper
|
@@ -11,7 +12,7 @@ module JenkinsApi
|
|
11
12
|
# Encode a string for use in the hiearchical part of an URL
|
12
13
|
#
|
13
14
|
def path_encode(path)
|
14
|
-
URI.escape(path.encode(Encoding::UTF_8))
|
15
|
+
Addressable::URI.escape(path.encode(Encoding::UTF_8))
|
15
16
|
end
|
16
17
|
end
|
17
18
|
end
|
@@ -22,15 +22,7 @@
|
|
22
22
|
|
23
23
|
module JenkinsApi
|
24
24
|
class Client
|
25
|
-
# Major version of the gem
|
26
|
-
MAJOR = 1
|
27
|
-
# Minor version of the gem
|
28
|
-
MINOR = 5
|
29
|
-
# Tiny version of the gem used for patches
|
30
|
-
TINY = 3
|
31
|
-
# Used for pre-releases
|
32
|
-
PRE = nil
|
33
25
|
# Version String of Jenkins API Client.
|
34
|
-
VERSION =
|
26
|
+
VERSION = "2.1.0"
|
35
27
|
end
|
36
28
|
end
|
@@ -257,6 +257,38 @@ module JenkinsApi
|
|
257
257
|
@client.api_post_request(post_msg)
|
258
258
|
end
|
259
259
|
|
260
|
+
# List (sub-)views in a view
|
261
|
+
#
|
262
|
+
# @param [String] view_name
|
263
|
+
#
|
264
|
+
# @return [Array] view_names list of (sub-)views in the specified view
|
265
|
+
#
|
266
|
+
def list_views(view_name)
|
267
|
+
@logger.info "Obtaining the views present in view '#{view_name}'"
|
268
|
+
view_names = []
|
269
|
+
raise "The view #{view_name} doesn't exists on the server"\
|
270
|
+
unless exists?(view_name)
|
271
|
+
response_json = @client.api_get_request("/view/#{path_encode view_name}")
|
272
|
+
response_json["views"].each do |view|
|
273
|
+
view_names << view["name"]
|
274
|
+
end
|
275
|
+
view_names
|
276
|
+
end
|
277
|
+
|
278
|
+
# List (sub-)views in view along with their details
|
279
|
+
#
|
280
|
+
# @param [String] view_name
|
281
|
+
#
|
282
|
+
# @return [Array<Hash>] the details of (sub-)views in the specified view
|
283
|
+
#
|
284
|
+
def list_views_with_details(view_name)
|
285
|
+
@logger.info "Obtaining the views present in view '#{view_name}'"
|
286
|
+
raise "The view #{view_name} doesn't exists on the server"\
|
287
|
+
unless exists?(view_name)
|
288
|
+
response_json = @client.api_get_request("/view/#{path_encode view_name}")
|
289
|
+
response_json["views"]
|
290
|
+
end
|
291
|
+
|
260
292
|
# Obtain the configuration stored in config.xml of a specific view
|
261
293
|
#
|
262
294
|
# @param [String] view_name
|
data/lib/jenkins_api_client.rb
CHANGED
@@ -30,6 +30,7 @@ require 'jenkins_api_client/view'
|
|
30
30
|
require 'jenkins_api_client/build_queue'
|
31
31
|
require 'jenkins_api_client/plugin_manager'
|
32
32
|
require 'jenkins_api_client/user'
|
33
|
+
require 'jenkins_api_client/root'
|
33
34
|
|
34
35
|
require 'jenkins_api_client/cli/helper'
|
35
36
|
require 'jenkins_api_client/cli/base'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jenkins_api_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kannan Manickam
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '1.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: addressable
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2.7'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2.7'
|
97
111
|
description: |2-
|
98
112
|
|
99
113
|
This is a simple and easy-to-use Jenkins Api client with features focused on
|
@@ -124,32 +138,33 @@ files:
|
|
124
138
|
- lib/jenkins_api_client/plugin_settings/collection.rb
|
125
139
|
- lib/jenkins_api_client/plugin_settings/hipchat.rb
|
126
140
|
- lib/jenkins_api_client/plugin_settings/workspace_cleanup.rb
|
141
|
+
- lib/jenkins_api_client/root.rb
|
127
142
|
- lib/jenkins_api_client/system.rb
|
128
143
|
- lib/jenkins_api_client/urihelper.rb
|
129
144
|
- lib/jenkins_api_client/user.rb
|
130
145
|
- lib/jenkins_api_client/version.rb
|
131
146
|
- lib/jenkins_api_client/view.rb
|
132
147
|
homepage: https://github.com/arangamani/jenkins_api_client
|
133
|
-
licenses:
|
148
|
+
licenses:
|
149
|
+
- MIT
|
134
150
|
metadata: {}
|
135
|
-
post_install_message:
|
151
|
+
post_install_message:
|
136
152
|
rdoc_options: []
|
137
153
|
require_paths:
|
138
154
|
- lib
|
139
155
|
required_ruby_version: !ruby/object:Gem::Requirement
|
140
156
|
requirements:
|
141
|
-
- - "
|
157
|
+
- - ">="
|
142
158
|
- !ruby/object:Gem::Version
|
143
|
-
version: '2.
|
159
|
+
version: '2.7'
|
144
160
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
161
|
requirements:
|
146
162
|
- - ">="
|
147
163
|
- !ruby/object:Gem::Version
|
148
164
|
version: '0'
|
149
165
|
requirements: []
|
150
|
-
|
151
|
-
|
152
|
-
signing_key:
|
166
|
+
rubygems_version: 3.3.3
|
167
|
+
signing_key:
|
153
168
|
specification_version: 4
|
154
169
|
summary: Jenkins JSON API Client
|
155
170
|
test_files: []
|