jenkins_api_client 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +23 -0
- data/CHANGELOG.rdoc +7 -1
- data/Gemfile +5 -3
- data/{README.rdoc → README.md} +69 -46
- data/lib/jenkins_api_client/cli/base.rb +33 -9
- data/lib/jenkins_api_client/cli/helper.rb +43 -0
- data/lib/jenkins_api_client/cli/job.rb +8 -37
- data/lib/jenkins_api_client/cli/node.rb +83 -0
- data/lib/jenkins_api_client/cli/system.rb +53 -0
- data/lib/jenkins_api_client/client.rb +35 -1
- data/lib/jenkins_api_client/job.rb +32 -16
- data/lib/jenkins_api_client/node.rb +149 -0
- data/lib/jenkins_api_client/system.rb +87 -0
- data/lib/jenkins_api_client/version.rb +5 -1
- data/spec/client_spec.rb +5 -0
- data/spec/node_spec.rb +48 -0
- data/spec/spec_helper.rb +3 -3
- data/spec/system_spec.rb +46 -0
- metadata +54 -15
data/.travis.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
before_install:
|
5
|
+
- wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
|
6
|
+
- sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'
|
7
|
+
- sudo apt-get update -qq
|
8
|
+
- sudo apt-get install -qq jenkins
|
9
|
+
- echo `service jenkins status`
|
10
|
+
- echo `curl 10.0.2.15:8080`
|
11
|
+
- echo `curl 10.0.2.15`
|
12
|
+
- echo `curl localhost:8080`
|
13
|
+
- echo `ifconfig`
|
14
|
+
- echo `hostname`
|
15
|
+
- echo `netstat -an`
|
16
|
+
script: bundle exec rspec
|
17
|
+
notifications:
|
18
|
+
email: false
|
19
|
+
irc:
|
20
|
+
on_success: change
|
21
|
+
on_failure: always
|
22
|
+
channels:
|
23
|
+
- "irc.freenode.org##arangamani"
|
data/CHANGELOG.rdoc
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
= CHANGELOG
|
2
2
|
|
3
|
-
===== v0.
|
3
|
+
===== v0.3.0 [11-NOV-2012]
|
4
|
+
* Added System class to support quietdown and restart functionality.
|
5
|
+
* Added Node class to query the node interface of Jenkins server.
|
6
|
+
* Added Command line interface for System and Node class.
|
7
|
+
* Introduced terminal tables for displaying attributes in command line.
|
8
|
+
|
9
|
+
===== v0.2.1 [02-NOV-2012]
|
4
10
|
* Added command line interface for basic operations
|
5
11
|
|
6
12
|
===== v0.1.1 [30-OCT-2012]
|
data/Gemfile
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
gem "nokogiri"
|
3
|
+
gem "nokogiri"
|
4
4
|
gem "activesupport", "~> 3.2.8"
|
5
5
|
gem "thor", "~> 0.16.0"
|
6
6
|
gem "json", ">= 0"
|
7
|
+
gem "terminal-table", ">= 1.4.0"
|
7
8
|
|
8
9
|
group :development do
|
9
|
-
gem "bundler", "
|
10
|
-
gem "jeweler", "
|
10
|
+
gem "bundler", ">= 1.0"
|
11
|
+
gem "jeweler", ">= 1.6.4"
|
11
12
|
gem "builder", "~> 3.1.3"
|
12
13
|
gem "simplecov"
|
14
|
+
gem "rspec"
|
13
15
|
end
|
data/{README.rdoc → README.md}
RENAMED
@@ -1,8 +1,12 @@
|
|
1
|
-
|
1
|
+
Jenkins API Client
|
2
|
+
==================
|
3
|
+
|
4
|
+
Copyright © 2012, Kannan Manickam.
|
2
5
|
|
3
6
|
Client libraries for communicating with a Jenkins CI server and programatically managing jobs.
|
4
7
|
|
5
|
-
|
8
|
+
OVERVIEW:
|
9
|
+
---------
|
6
10
|
This project is a simple API client for interacting with Jenkins Continuous Integration server.
|
7
11
|
Jenkins provides three kinds of remote access API. 1. XML API, 2. JSON API, and 3. Python API.
|
8
12
|
This project aims at consuming the JSON API and provides some useful functions for controlling
|
@@ -10,23 +14,32 @@ jobs on the Jenkins programatically. Even though Jenkins provides an awesome UI
|
|
10
14
|
jobs, it would be nice and helpful to have a programmable interface so we can dynamically and
|
11
15
|
automatically manage jobs and other artifacts.
|
12
16
|
|
13
|
-
|
14
|
-
|
15
|
-
|
17
|
+
DETAILS:
|
18
|
+
--------
|
19
|
+
This projects currently only provides functionality for the <tt>jobs, node, and system</tt> interfaces.
|
20
|
+
This is still a work-in-progress project. I mainly use the functionality of this project for my autmation
|
16
21
|
work and the functionality mainly focussed on my usage and I believe others might find it useful
|
17
22
|
too. I would love to add more features to it and I will continue working on improving existing
|
18
23
|
features and add more interfaces such as nodes, views, build queue, etc,.
|
19
24
|
|
20
|
-
|
25
|
+
CODE STATUS:
|
26
|
+
------------
|
27
|
+
|
28
|
+
* Gemnasium: [![Dependency Status](https://gemnasium.com/arangamani/jenkins_api_client.png)](https://gemnasium.com/arangamani/jenkins_api_client)
|
29
|
+
|
30
|
+
* Code Climate: [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/arangamani/jenkins_api_client)
|
31
|
+
|
32
|
+
USAGE:
|
33
|
+
------
|
21
34
|
|
22
|
-
|
35
|
+
### Installation
|
23
36
|
|
24
37
|
Install jenkins_api_client by <tt>sudo gem install jenkins_api_client</tt>
|
25
38
|
Include this gem in your code as a require statement.
|
26
39
|
|
27
|
-
|
40
|
+
require 'jenkins_api_client'
|
28
41
|
|
29
|
-
|
42
|
+
### Using with IRB
|
30
43
|
|
31
44
|
If you want to just play with it and not actually want to write a script, you can just use the
|
32
45
|
irb launcher script which is available in <tt>scripts/login_with_irb.rb</tt>. But make sure that
|
@@ -35,62 +48,68 @@ you have your credentials file in <tt>~/.jenkins_api_client/login.yml</tt>. If y
|
|
35
48
|
location and would like to use a different location, just modify that script to point to the
|
36
49
|
location where the credentials file exists.
|
37
50
|
|
38
|
-
|
51
|
+
ruby scripts/login_with_irb.rb
|
39
52
|
|
40
53
|
You will see the that it entered IRB session and you can play with the API client with the
|
41
54
|
<tt>@client</tt> object that it has returned.
|
42
55
|
|
43
|
-
|
56
|
+
### Authentication
|
44
57
|
|
45
58
|
This project supports two types of password-based authentication. You can just you the plain
|
46
59
|
password by using <tt>password</tt> parameter. If you don't prefer leaving plain passwords in the
|
47
60
|
credentials file, you can encode your password in base64 format and use <tt>password_base64</tt>
|
48
61
|
parameter to specify the password either in the arguments or in the credentials file.
|
49
62
|
|
50
|
-
|
63
|
+
### Basic Usage
|
51
64
|
|
52
65
|
As discussed earlier, you can either specify all the credentials and server information as
|
53
66
|
parameters to the Client or have a credentials file and just parse the yaml file and pass it in.
|
54
67
|
The following call just passes the information as parameters
|
55
68
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
69
|
+
```ruby
|
70
|
+
@client = JenkinsApi::Client.new(:server_ip => '0.0.0.0',
|
71
|
+
:username => 'somename', :password => 'secret password')
|
72
|
+
# The following call will return all jobs matching 'Testjob'
|
73
|
+
puts @client.job.list("^Testjob")
|
74
|
+
```
|
60
75
|
|
61
76
|
The following example passes the YAML file contents. An example yaml file is located in
|
62
77
|
<tt>config/login.yml.example</tt>.
|
63
78
|
|
64
|
-
|
65
|
-
|
66
|
-
|
79
|
+
```ruby
|
80
|
+
@client = JenkinsApi::Client.new(YAML.Load_file(File.expand_path('~/.jenkins_api_client/login.yml', __FILE__)))
|
81
|
+
# The following call lists all jobs
|
82
|
+
puts @client.job.list_all
|
83
|
+
```
|
67
84
|
|
68
|
-
|
85
|
+
### Chaining and Building Jobs
|
69
86
|
|
70
87
|
Sometimes we want certain jobs to be added as downstream projects and run them sequencially.
|
71
88
|
The following example will explain how this could be done.
|
72
89
|
|
73
|
-
|
90
|
+
```ruby
|
91
|
+
require 'jenkins_api_client'
|
74
92
|
|
75
|
-
|
76
|
-
|
77
|
-
|
93
|
+
# We want to filter all jobs that start with 'test_job'
|
94
|
+
# Just write a regex to match all the jobs that start with 'test_job'
|
95
|
+
jobs_to_filter = "^test_job.*"
|
78
96
|
|
79
|
-
|
80
|
-
|
97
|
+
# Create an instance to jenkins_api_client
|
98
|
+
@client = JenkinsApi::Client.new(YAML.load_file(File.expand_path('~/.jenkins_api_client/login.yml', __FILE__)))
|
81
99
|
|
82
|
-
|
83
|
-
|
100
|
+
# Get a filtered list of jobs from the server
|
101
|
+
jobs = @client.job.list(jobs_to_filter)
|
84
102
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
103
|
+
# Chain all the jobs with 'success' as the threshold
|
104
|
+
# The chain method will return the jobs that is in the head of the sequence
|
105
|
+
# This method will also remove any existing chaining
|
106
|
+
initial_jobs = @client.job.chain(jobs, 'success', ["all"])
|
89
107
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
108
|
+
# 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
|
110
|
+
code = @client.job.build(initial_jobs[0])
|
111
|
+
raise "Could not build the job specified" unless code == 302
|
112
|
+
```
|
94
113
|
|
95
114
|
In the above example, you might have noticed that the chain method returns an array instead of a
|
96
115
|
single job. There is a reason behind it. In simple chain, such as the one in the example above, all
|
@@ -115,14 +134,16 @@ fails, and <tt>unstable</tt> will move to the job even if the build is unstable.
|
|
115
134
|
The following call to the <tt>chain</tt> method will consider only failed and unstable jobs, chain then
|
116
135
|
with 'failure' as the threshold, and also chain three jobs in parallel.
|
117
136
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
}
|
137
|
+
```ruby
|
138
|
+
initial_jobs = @client.job.chain(jobs, 'failure', ["failure", "unstable"], 3)
|
139
|
+
# We will receive three jobs as a result and we can build them all
|
140
|
+
initial_jobs.each { |job|
|
141
|
+
code = @client.job.build(job)
|
142
|
+
raise "Unable to build job: #{job}" unless code == 302
|
143
|
+
}
|
144
|
+
```
|
124
145
|
|
125
|
-
|
146
|
+
### Using with command line
|
126
147
|
Command line interface is supported only from version 0.2.0.
|
127
148
|
See help using <tt>jenkinscli help</tt>
|
128
149
|
|
@@ -131,12 +152,13 @@ There are three ways for authentication using command line interface
|
|
131
152
|
2. Passing the credentials file as the command line parameter
|
132
153
|
3. Having the credentials file in the default location <tt>HOME/.jenkins_api_client/login.yml</tt>
|
133
154
|
|
134
|
-
|
155
|
+
### Debug
|
135
156
|
|
136
157
|
The call to client initialization accepts a debug parameter. If it is set to <tt>true</tt> it will print
|
137
158
|
some debug information to the console. By default it is set to false.
|
138
159
|
|
139
|
-
|
160
|
+
CONTRIBUTING:
|
161
|
+
-------------
|
140
162
|
|
141
163
|
If you would like to contribute to this project, just do the following:
|
142
164
|
|
@@ -147,7 +169,8 @@ If you would like to contribute to this project, just do the following:
|
|
147
169
|
5. Once changes are done or no changes are required, pull request will be merged.
|
148
170
|
6. The next release will have your changes in it.
|
149
171
|
|
150
|
-
|
172
|
+
FEATURE REQUEST:
|
173
|
+
----------------
|
151
174
|
|
152
175
|
If you use this gem for your project and you think it would be nice to have a particular feature
|
153
176
|
that is presently not implemented, I would love to hear that and consider working on it.
|
@@ -23,27 +23,51 @@
|
|
23
23
|
require 'thor'
|
24
24
|
require 'thor/group'
|
25
25
|
require "#{File.dirname(__FILE__)}/../client.rb"
|
26
|
+
require "#{File.dirname(__FILE__)}/node.rb"
|
26
27
|
require "#{File.dirname(__FILE__)}/job.rb"
|
28
|
+
require "#{File.dirname(__FILE__)}/system.rb"
|
27
29
|
|
28
30
|
module JenkinsApi
|
29
31
|
module CLI
|
30
32
|
|
31
33
|
class Base < Thor
|
34
|
+
|
35
|
+
class_option :username, :aliases => "-u", :desc => "Name of Jenkins user"
|
36
|
+
class_option :password, :aliases => "-p", :desc => "Password of Jenkins user"
|
37
|
+
class_option :password_base64, :aliases => "-b", :desc => "Base 64 encoded password of Jenkins user"
|
38
|
+
class_option :server_ip, :aliases => "-s", :desc => "Jenkins server IP address"
|
39
|
+
class_option :server_port, :aliases => "-o", :desc => "Jenkins server port"
|
40
|
+
class_option :creds_file, :aliases => "-c", :desc => "Credentials file for communicating with Jenkins server"
|
41
|
+
|
42
|
+
|
32
43
|
map "-v" => :version
|
33
44
|
|
34
45
|
desc "version", "Shows current version"
|
35
46
|
def version
|
36
47
|
puts JenkinsApi::Client::VERSION
|
37
48
|
end
|
38
|
-
end
|
39
49
|
|
40
|
-
|
41
|
-
|
50
|
+
register(
|
51
|
+
CLI::Node,
|
52
|
+
'node',
|
53
|
+
'node [subcommand]',
|
54
|
+
'Provides functions to access the node interface of Jenkins CI server'
|
55
|
+
)
|
56
|
+
|
57
|
+
register(
|
58
|
+
CLI::Job,
|
59
|
+
'job',
|
60
|
+
'job [subcommand]',
|
61
|
+
'Provides functions to access the job interface of Jenkins CI server'
|
62
|
+
)
|
42
63
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
)
|
64
|
+
register(
|
65
|
+
CLI::System,
|
66
|
+
'system',
|
67
|
+
'system [subcommand]',
|
68
|
+
'Provides functions to access system functions of the Jenkins CI server'
|
69
|
+
)
|
49
70
|
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2012 Kannan Manickam <arangamani.kannan@gmail.com>
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in
|
12
|
+
# all copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
# THE SOFTWARE.
|
21
|
+
#
|
22
|
+
|
23
|
+
require 'fileutils'
|
24
|
+
|
25
|
+
module JenkinsApi
|
26
|
+
module CLI
|
27
|
+
class Helper
|
28
|
+
def self.setup(options)
|
29
|
+
if options[:username] && options[:server_ip] && (options[:password] || options[:password_base64])
|
30
|
+
creds = options
|
31
|
+
elsif options[:creds_file]
|
32
|
+
creds = YAML.load_file(File.expand_path(options[:creds_file], __FILE__))
|
33
|
+
elsif File.exist?("#{ENV['HOME']}/.jenkins_api_client/login.yml")
|
34
|
+
creds = YAML.load_file(File.expand_path("#{ENV['HOME']}/.jenkins_api_client/login.yml", __FILE__))
|
35
|
+
else
|
36
|
+
puts "Credentials are not set. Please pass them as parameters or set them in the default credentials file"
|
37
|
+
exit 1
|
38
|
+
end
|
39
|
+
JenkinsApi::Client.new(creds)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -20,48 +20,19 @@
|
|
20
20
|
# THE SOFTWARE.
|
21
21
|
#
|
22
22
|
|
23
|
-
require
|
24
|
-
require '
|
23
|
+
require 'thor'
|
24
|
+
require 'thor/group'
|
25
25
|
|
26
26
|
module JenkinsApi
|
27
27
|
module CLI
|
28
28
|
|
29
29
|
class Job < Thor
|
30
30
|
include Thor::Actions
|
31
|
-
class_option :username, :aliases => "-u", :desc => "Name of Jenkins user"
|
32
|
-
class_option :password, :aliases => "-p", :desc => "Password of Jenkins user"
|
33
|
-
class_option :password_base64, :aliases => "-b", :desc => "Base 64 encoded password of Jenkins user"
|
34
|
-
class_option :server_ip, :aliases => "-s", :desc => "Jenkins server IP address"
|
35
|
-
class_option :server_port, :aliases => "-o", :desc => "Jenkins server port"
|
36
|
-
class_option :creds_file, :aliases => "-c", :desc => "Credentials file for communicating with Jenkins server"
|
37
|
-
|
38
|
-
no_tasks {
|
39
|
-
def setup
|
40
|
-
if options[:username] && options[:server_ip] && (options[:password] || options[:password_base64])
|
41
|
-
creds = options
|
42
|
-
elsif options[:creds_file]
|
43
|
-
creds = YAML.load_file(File.expand_path(options[:creds_file], __FILE__))
|
44
|
-
elsif File.exist?("#{ENV['HOME']}/.jenkins_api_client/login.yml")
|
45
|
-
creds = YAML.load_file(File.expand_path("#{ENV['HOME']}/.jenkins_api_client/login.yml", __FILE__))
|
46
|
-
else
|
47
|
-
say "Credentials are not set. Please pass them as parameters or set them in the default credentials file", :red
|
48
|
-
end
|
49
|
-
JenkinsApi::Client.new(creds)
|
50
|
-
end
|
51
|
-
}
|
52
|
-
|
53
|
-
desc "test", "Test job"
|
54
|
-
def test
|
55
|
-
#invoke :creds
|
56
|
-
setup
|
57
|
-
puts "test: #{options[:username]}"
|
58
|
-
#puts self.options[:username] if self.options[:username]
|
59
|
-
end
|
60
31
|
|
61
32
|
desc "list", "List jobs"
|
62
33
|
method_option :filter, :aliases => "-f", :desc => "Regular expression to filter jobs"
|
63
34
|
def list
|
64
|
-
@client = setup
|
35
|
+
@client = Helper.setup(parent_options)
|
65
36
|
if options[:filter]
|
66
37
|
puts @client.job.list(options[:filter])
|
67
38
|
else
|
@@ -71,32 +42,32 @@ module JenkinsApi
|
|
71
42
|
|
72
43
|
desc "build JOB", "Build a job"
|
73
44
|
def build(job)
|
74
|
-
@client = setup
|
45
|
+
@client = Helper.setup(parent_options)
|
75
46
|
@client.job.build(job)
|
76
47
|
end
|
77
48
|
|
78
49
|
desc "status JOB", "Get the current build status of a job"
|
79
50
|
def status(job)
|
80
|
-
@client = setup
|
51
|
+
@client = Helper.setup(parent_options)
|
81
52
|
puts @client.job.get_current_build_status(job)
|
82
53
|
end
|
83
54
|
|
84
55
|
desc "listrunning", "List running jobs"
|
85
56
|
def listrunning
|
86
|
-
@client = setup
|
57
|
+
@client = Helper.setup(parent_options)
|
87
58
|
puts @client.job.list_running
|
88
59
|
end
|
89
60
|
|
90
61
|
desc "delete JOB", "Delete the job"
|
91
62
|
def delete(job)
|
92
|
-
@client = setup
|
63
|
+
@client = Helper.setup(parent_options)
|
93
64
|
puts @client.job.delete(job)
|
94
65
|
end
|
95
66
|
|
96
67
|
desc "restrict JOB", "Restricts a job to a specific node"
|
97
68
|
method_option :node, :aliases => "-n", :desc => "Node to be restricted to"
|
98
69
|
def restrict(job)
|
99
|
-
@client = setup
|
70
|
+
@client = Helper.setup(parent_options)
|
100
71
|
if options[:node]
|
101
72
|
@client.job.restrict_to_node(job, options[:node])
|
102
73
|
else
|