Skip to content

Commit

Permalink
raise Timeout::Error on build timeout (compatibility) plus docs
Browse files Browse the repository at this point in the history
  • Loading branch information
dougforpres committed Oct 10, 2013
1 parent b6b028e commit 603b102
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 3 deletions.
78 changes: 78 additions & 0 deletions README.md
Expand Up @@ -169,6 +169,84 @@ initial_jobs.each do |job|
end
```

### Waiting for a build to start/Getting the build number
Newer versions of Jenkins (starting with the 1.519 build) make it easier for
an application to determine the build number for a 'build' request. (previously
there would be a degree of guesswork involved). The new version actually
returns information allowing the jenkins_api_client to check the build queue
for the job and see if it has started yet (once it has started, the build-
number is available.

If you wish to take advantage of this hands-off approach, the build method
supports an additional 'opts' hash that lets you specify how long you wish to
wait for the build to start.

## Old Jenkins vs New Jenkins (1.519+)
# Old (v < 1.519)
The 'opts' parameter will work with older versions of Jenkins with the following
caveats:
* The 'cancel_on_build_start_timeout' option has no effect
* The build_number is calculated by calling 'current_build_number' and adding
1 before the build is started. This might break if there are multiple
entities running builds on the same job, or there are queued builds.
# New (v >= 1.519)
* All options work, and build number is accurately determined from queue
info.

## Initiating a build and returning the build_number
# Minimum required
```ruby
# Minimum options required
opts = {'build_start_timeout' => 30}
@client.job.build(job_name, job_params || {}, opts)
```
This method will block for up to 30 seconds, while waiting for the build to
start. Instead of returning an http-status code, it will return the
build_number, or if the build has not started will raise 'Timeout::Error'
Note: to maintain legacy compatibility, passing 'true' will set the timeout
to the default timeout specified when creating the @client.

# Auto cancel the queued-build on timeout
```ruby
# Wait for up to 30 seconds, attempt to cancel queued build
opts = {'build_start_timeout' => 30,
'cancel_on_build_start_timeout' => true}
@client.job.build(job_name, job_params || {}, opts)
```
This method will block for up to 30 seconds, while waiting for the build to
start. Instead of returning an http-status code, it will return the
build_number, or if the build has not started will raise 'Timeout::Error'.
Prior to raising the Timeout::Error, it will attempt to cancel the queued
build - thus preventing it from starting.

# Getting some feedback while you're waiting
The opts parameter supports two values that can be assigned proc objects
(which will be 'call'ed). Both are optional, and will only be called if
specified in opts.
These are initially intended to assist with logging progress.
'progress_proc' - called when job is initially queued, and periodically
thereafter.
Params:
max_wait - the value of 'build_start_timeout'
current_wait - how long we've been waiting so far
poll_count - how many times we've polled the queue
'completion_proc' - called just prior to return/Timeout::Error
Params:
build_number - the build number assigned (or nil if timeout)
cancelled - whether the build was cancelled (true if 'new' Jenkins
and it was able to cancel the build, false otherwise)
To use a class method, just specify 'instance.method(:method_name)', or
use a proc or lambda

```ruby
# Wait for up to 30 seconds, attempt to cancel queued build, progress
opts = {'build_start_timeout' => 30,
'cancel_on_build_start_timeout' => true,
'poll_interval' => 2, # 2 is actually the default :)
'progress_proc' => lambda {|max,curr,count| ... },
'completion_proc' => lambda {|build_number,cancelled| ... }}
@client.job.build(job_name, job_params || {}, opts)
```
### Running Jenkins CLI
To running [Jenkins CLI](https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+CLI)

Expand Down
7 changes: 6 additions & 1 deletion lib/jenkins_api_client/job.rb
Expand Up @@ -858,6 +858,9 @@ def get_build_id_from_queue(response, expected_build_id, opts)
@logger.info "Jenkins build for '#{job_name}' failed to start in a timely manner"
completion_proc.call(nil, false) if completion_proc
end

# Old version used to throw timeout error, so we should let that go thru now
raise
rescue JenkinsApi::Exceptions::ApiException => e
# Jenkins Api threw an error at us
completion_proc.call(nil, false) if completion_proc
Expand Down Expand Up @@ -920,7 +923,9 @@ def get_build_id_the_old_way(expected_build_id, opts)
# Now we need to raise an exception so that the build can be officially failed
completion_proc.call(nil, false) if completion_proc
@logger.info "Jenkins '#{job_name}' build failed to start in a timely manner"
return nil

# Old version used to propagate timeout error
raise
rescue JenkinsApi::Exceptions::ApiException => e
completion_proc.call(nil, false) if completion_proc
# Jenkins Api threw an error at us
Expand Down
4 changes: 2 additions & 2 deletions spec/unit_tests/job_spec.rb
Expand Up @@ -437,7 +437,7 @@
@client.should_receive(:api_get_request).with(
"/job/test_job/1/").twice.ordered.and_raise(JenkinsApi::Exceptions::NotFound.new(@client.logger))
@client.should_receive(:get_jenkins_version).and_return("1.1")
@job.build("test_job", {}, {'build_start_timeout' => 3}).should be_nil
expect( lambda { @job.build("test_job", {}, {'build_start_timeout' => 3}) }).to raise_error(Timeout::Error)
end

### JENKINS POST 1.519 (QUEUE RESPONSE) ###
Expand Down Expand Up @@ -475,7 +475,7 @@
@client.should_receive(:api_get_request).with(
"/queue/item/42").and_return({}, {})
@client.should_receive(:get_jenkins_version).and_return("1.519")
@job.build("test_job", {}, {'build_start_timeout' => 3}).should be_nil
expect( lambda { @job.build("test_job", {}, {'build_start_timeout' => 3}) }).to raise_error(Timeout::Error)
end
end

Expand Down

0 comments on commit 603b102

Please sign in to comment.