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 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.2.0 [02-NOV-2012]
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", "~> 1.5.5"
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", "~> 1.2.1"
10
- gem "jeweler", "~> 1.6.4"
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
@@ -1,8 +1,12 @@
1
- = Jenkins API Client
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
- == OVERVIEW:
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
- == DETAILS:
14
- This projects currently only provides functionality for the <tt>jobs</tt> interface. This is
15
- still a work-in-progress project. I mainly use the functionality of this project for my autmation
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
- == USAGE:
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
- === Installation
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
- require 'jenkins_api_client'
40
+ require 'jenkins_api_client'
28
41
 
29
- === Using with IRB
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
- ruby scripts/login_with_irb.rb
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
- === Authentication
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
- === Basic Usage
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
- @client = JenkinsApi::Client.new(:server_ip => '0.0.0.0',
57
- :username => 'somename', :password => 'secret password')
58
- # The following call will return all jobs matching 'Testjob'
59
- puts @client.job.list("^Testjob")
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
- @client = JenkinsApi::Client.new(YAML.Load_file(File.expand_path('~/.jenkins_api_client/login.yml', __FILE__)))
65
- # The following call lists all jobs
66
- puts @client.job.list_all
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
- === Chaining and Building Jobs
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
- require 'jenkins_api_client'
90
+ ```ruby
91
+ require 'jenkins_api_client'
74
92
 
75
- # We want to filter all jobs that start with 'test_job'
76
- # Just write a regex to match all the jobs that start with 'test_job'
77
- jobs_to_filter = "^test_job.*"
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
- # Create an instance to jenkins_api_client
80
- @client = JenkinsApi::Client.new(YAML.load_file(File.expand_path('~/.jenkins_api_client/login.yml', __FILE__)))
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
- # Get a filtered list of jobs from the server
83
- jobs = @client.job.list(jobs_to_filter)
100
+ # Get a filtered list of jobs from the server
101
+ jobs = @client.job.list(jobs_to_filter)
84
102
 
85
- # Chain all the jobs with 'success' as the threshold
86
- # The chain method will return the jobs that is in the head of the sequence
87
- # This method will also remove any existing chaining
88
- initial_jobs = @client.job.chain(jobs, 'success', ["all"])
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
- # Now that we have the initial job(s) we can build them
91
- # The build function returns a code from the API which should be 302 if the build was successful
92
- code = @client.job.build(initial_jobs[0])
93
- raise "Could not build the job specified" unless code == 302
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
- initial_jobs = @client.job.chain(jobs, 'failure', ["failure", "unstable"], 3)
119
- # We will receive three jobs as a result and we can build them all
120
- initial_jobs.each { |job|
121
- code = @client.job.build(job)
122
- raise "Unable to build job: #{job}" unless code == 302
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
- === Using with command line
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
- === Debug
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
- == CONTRIBUTING:
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
- == FEATURE REQUEST:
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
- end
41
- end
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
- JenkinsApi::CLI::Base.register(
44
- JenkinsApi::CLI::Job,
45
- 'job',
46
- 'job [subcommand]',
47
- 'Provides functions to access the job interface of Jenkins CI server'
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 File.expand_path('../base', __FILE__)
24
- require 'fileutils'
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