Skip to content

Instantly share code, notes, and snippets.

@joepadmiraal
Last active December 21, 2020 16:41
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save joepadmiraal/33e0c2a7a7b00cc2e0aa to your computer and use it in GitHub Desktop.
Save joepadmiraal/33e0c2a7a7b00cc2e0aa to your computer and use it in GitHub Desktop.
Jenkins build status widget for Dashing

##Preview See images below.

Description

Simple Dashing widget (and associated job) to display the current build status of a Jenkins server. When all jobs are fine a blue background with a thumbs-up icons is shown. When one or more jobs are in a failed state, they are listed on a red background. If culprits are available the user which has broken the build will also be shown. When the Speech Synthesis API is available on the browser it will say one of the predefined texts out loud every 5 minutes. See jenkins_build_status.coffee for the texts and the timeBetweenSounds parameter.

Calls are made to the Jenkins API to retrieve the build status and culprits if they are available.

Please leave a comment below or click on the star if you are using this widget :-)

Installing the widget

Create the folder widgets/jenkins_build_status and put these files in it:

  • jenkins_build_status.coffee
  • jenkins_build_status.html
  • jenkins_build_status.scss

Place the following file in your jobs/ folder:

  • jenkins_build_status.rb

Configuring the widget for use with your Jenkins instance

There are a few parameters that must be set up before using this widget with your Jenkins instance.

In the jenkins_build_status.rb file, modify the following parameters according to your needs:

Parameter Meaning
JENKINS_URI Jenkins base URL
JENKINS_AUTH Jenkins user credentials

Adding the Jenkins build status widget to your dashboard

To add this widget to your dashboard, add the following to your [Dashboard-filename].erb file:

    <li data-row="1" data-col="1" data-sizex="2" data-sizey="1">
      <div data-id="jenkinsBuildStatus" data-view="JenkinsBuildStatus" data-title="Jenkins"></div>
    </li>
class Dashing.JenkinsBuildStatus extends Dashing.Widget
lastPlayed: 0
timeBetweenSounds: 300000
onData: (data) ->
if data.failed
$(@node).find('div.build-failed').show()
$(@node).find('div.build-succeeded').hide()
$(@node).css("background-color", "red")
if 'speechSynthesis' of window
@playSoundForUser data.failedJobs[0].value if Date.now() - @lastPlayed > @timeBetweenSounds
else
$(@node).find('div.build-failed').hide()
$(@node).find('div.build-succeeded').show()
$(@node).css("background-color", "#12b0c5")
playSoundForUser: (user) ->
@lastPlayed = Date.now()
texts = ["#{user} has broken the build.", "The build is broken by #{user}", "#{user} is great, but lacks some programming skills", "Oops, I did it again."]
textNr = Math.floor((Math.random() * texts.length));
@playSound texts[textNr]
playSound: (text) ->
msg = new SpeechSynthesisUtterance(text)
msg.voice = speechSynthesis.getVoices()[0]
speechSynthesis.speak msg
<div class="build-failed">
<h1 class="jenkins-status"><span data-bind="title"></span> FAILED</h1>
<ul class="list-nostyle list-failed">
<li data-foreach-item="failedJobs">
<div class="label" data-bind="item.label"></div>
<div class="value" data-bind="item.value"></div>
</li>
</ul>
</div>
<div class="build-succeeded">
<h1 class="jenkins-status">All <span data-bind="title"></span> builds are successful</h1>
<i class="fa fa-thumbs-o-up"></i>
</div>
<p class="updated-at" data-bind="updatedAtMessage"></p>
require 'net/http'
require 'json'
JENKINS_URI = "http://localhost:8080/"
JENKINS_AUTH = {
'name' => null,
'password' => null
}
SCHEDULER.every '10s' do
json = getFromJenkins(JENKINS_URI + 'api/json?pretty=true')
failedJobs = Array.new
succeededJobs = Array.new
array = json['jobs']
array.each {
|job|
next if job['color'] == 'disabled'
next if job['color'] == 'notbuilt'
next if job['color'] == 'blue'
next if job['color'] == 'blue_anime'
jobStatus = '';
if job['color'] == 'yellow' || job['color'] == 'yellow_anime'
jobStatus = getFromJenkins(job['url'] + 'lastUnstableBuild/api/json')
elsif job['color'] == 'aborted' || job['color'] == 'aborted_anime'
jobStatus = getFromJenkins(job['url'] + 'lastUnsuccessfulBuild/api/json')
else
jobStatus = getFromJenkins(job['url'] + 'lastFailedBuild/api/json')
end
culprits = jobStatus['culprits']
culpritName = getNameFromCulprits(culprits)
if culpritName != ''
culpritName = culpritName.partition('<').first
end
failedJobs.push({ label: job['name'], value: culpritName})
}
failed = failedJobs.size > 0
send_event('jenkinsBuildStatus', { failedJobs: failedJobs, succeededJobs: succeededJobs, failed: failed })
end
def getFromJenkins(path)
uri = URI.parse(path)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Get.new(uri.request_uri)
if JENKINS_AUTH['name']
request.basic_auth(JENKINS_AUTH['name'], JENKINS_AUTH['password'])
end
response = http.request(request)
json = JSON.parse(response.body)
return json
end
def getNameFromCulprits(culprits)
culprits.each {
|culprit|
return culprit['fullName']
}
return ''
end
// ----------------------------------------------------------------------------
// Sass declarations
// ----------------------------------------------------------------------------
$background-color: #ec663c;
$title-color: rgba(255, 255, 255, 0.7);
$label-color: rgba(255, 255, 255, 0.7);
$value-color: #fff;
// ----------------------------------------------------------------------------
// Widget-text styles
// ----------------------------------------------------------------------------
.widget-jenkins-build-status {
background-color: $background-color;
.title {
color: $title-color;
}
.updated-at {
color: rgba(255, 255, 255, 0.7);
}
ol, ul {
margin: 0 15px;
text-align: left;
color: $label-color;
}
li {
margin-bottom: 5px;
font-size: 40px;
}
.label {
color: $label-color;
}
.value {
margin-left: 12px;
font-weight: 600;
color: $value-color;
}
.updated-at {
color: rgba(0, 0, 0, 0.3);
}
.build-failed {
display: none;
}
.fa {
font-size: 10em;
color: $label-color;
}
}

The MIT License (MIT)

Copyright (c) 2014 David Underwood

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@sbange
Copy link

sbange commented Mar 12, 2015

Hi Joe,

I'm trying to get this to run on Mac OS X (Yosemite) with Ruby 2.0, gem 2.4.6 and Bundler 1.8.5. The following error occurs:

/Library/Ruby/Gems/2.0.0/gems/backports-3.6.4/lib/backports/std_lib.rb:9:in require': cannot load such file -- httpclient (LoadError) from /Library/Ruby/Gems/2.0.0/gems/backports-3.6.4/lib/backports/std_lib.rb:9:inrequire_with_backports'
from /Users/sbange/workspaces/dashboards/fricke/jobs/jenkins_build_status.rb:1:in <top (required)>' from /Library/Ruby/Gems/2.0.0/gems/backports-3.6.4/lib/backports/std_lib.rb:9:inrequire'
from /Library/Ruby/Gems/2.0.0/gems/backports-3.6.4/lib/backports/std_lib.rb:9:in `require_with_backports'

I'm new to ruby, I tried "gem install httpclient" and "bundler install", which both worked fine, but the error persists. Any ideas how to move on?

Thanks and Regards,
Sven.

@sbange
Copy link

sbange commented Mar 13, 2015

Figured it out: I did not add httpclient to the Gemfile. Nice widget, thanks!

@joepadmiraal
Copy link
Author

Ah great, I will update the gist with this info.

@joepadmiraal
Copy link
Author

sbange, the httpclient is now removed from the job file as it was not used.

@gambastian
Copy link

Hi Joe, (Thanks by the way)

I'm having the same problem described by ChethanaPuneeth, did you solve it? My widget keeps saying "All Jenkins builds are successful" with orange background, but in the log:

scheduler caught exception:
getaddrinfo: Name or service not known
/usr/lib/ruby/1.9.1/net/http.rb:763:in initialize' /usr/lib/ruby/1.9.1/net/http.rb:763:inopen'
/usr/lib/ruby/1.9.1/net/http.rb:763:in block in connect' /usr/lib/ruby/1.9.1/timeout.rb:55:intimeout'
/usr/lib/ruby/1.9.1/timeout.rb:100:in timeout' /usr/lib/ruby/1.9.1/net/http.rb:763:inconnect'
/usr/lib/ruby/1.9.1/net/http.rb:756:in do_start' /usr/lib/ruby/1.9.1/net/http.rb:745:instart'
/usr/lib/ruby/1.9.1/net/http.rb:1285:in request' /home/dev/git/dashboard/jobs/jenkins_build_status.rb:66:ingetFromJenkins'
/home/dev/git/dashboard/jobs/jenkins_build_status.rb:13:in block in <top (required)>' /var/lib/gems/1.9.1/gems/rufus-scheduler-2.0.24/lib/rufus/sc/jobs.rb:230:incall'
/var/lib/gems/1.9.1/gems/rufus-scheduler-2.0.24/lib/rufus/sc/jobs.rb:230:in trigger_block' /var/lib/gems/1.9.1/gems/rufus-scheduler-2.0.24/lib/rufus/sc/jobs.rb:204:inblock in trigger'
/var/lib/gems/1.9.1/gems/rufus-scheduler-2.0.24/lib/rufus/sc/scheduler.rb:430:in call' /var/lib/gems/1.9.1/gems/rufus-scheduler-2.0.24/lib/rufus/sc/scheduler.rb:430:inblock in trigger_job'

Thanks
Sebastian

@gambastian
Copy link

Hi Again,

I found the problem, in my case the Jenkins configurations replaced the jenkins host for localhost (I saw this making a get request to the json api : http://jenkins_HOST:jenkins_PORT/api/json?pretty=true) in the jobs urls, so in the begining it connected successfully to the host when looking for jobs, but when it tried to retrieve the job status it was trying to reach a jenkins in localhost.

@joepadmiraal
Copy link
Author

Hi gambastian, thanks for the info.
I will see if I can add some kind of error message which describes what's going on.

@larrycai
Copy link

If https, then need below codes

http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE 

@larrycai
Copy link

JENKINS_URI actually works for Jenkins View as well, which help you to monitor one group of jobs instead of all jobs from one jenkins instance

@larrycai
Copy link

Can we have title in the widget ? (so it is jenkins view, it will be better to show view name in title)

@joepadmiraal
Copy link
Author

@larrycai, I updated the html to use the data-title from the dashboard.erb file.

Copy link

ghost commented May 5, 2015

I cannot get this to work for HTTPS. I just get the "All jenkins builds are sucessful" message

@lethe3000
Copy link

hi, if I have tow jenkins servers to show, which is the correct approach?
I simply copy jenkins_build_status.rb to jenkins_build_status-2.rb
and modify the name of JENKINS_URI, JENKINS_AUTH to JENKINS_URI_2 and JENKINS_AUTH_2,but met such error:

/usr/local/rvm/gems/ruby-2.1.2/gems/eventmachine-1.0.7/lib/eventmachine.rb:526:in start_tcp_server': no acceptor (port is in use or requires root privileges) (RuntimeError) from /usr/local/rvm/gems/ruby-2.1.2/gems/eventmachine-1.0.7/lib/eventmachine.rb:526:instart_server'
from /usr/local/rvm/gems/ruby-2.1.2/gems/thin-1.6.3/lib/thin/backends/tcp_server.rb:16:in connect' from /usr/local/rvm/gems/ruby-2.1.2/gems/thin-1.6.3/lib/thin/backends/base.rb:63:inblock in start'
from /usr/local/rvm/gems/ruby-2.1.2/gems/eventmachine-1.0.7/lib/eventmachine.rb:187:in call' from /usr/local/rvm/gems/ruby-2.1.2/gems/eventmachine-1.0.7/lib/eventmachine.rb:187:inrun_machine'
from /usr/local/rvm/gems/ruby-2.1.2/gems/eventmachine-1.0.7/lib/eventmachine.rb:187:in run' from /usr/local/rvm/gems/ruby-2.1.2/gems/thin-1.6.3/lib/thin/backends/base.rb:73:instart'
from /usr/local/rvm/gems/ruby-2.1.2/gems/thin-1.6.3/lib/thin/server.rb:162:in start' from /usr/local/rvm/gems/ruby-2.1.2/gems/thin-1.6.3/lib/thin/controllers/controller.rb:87:instart'
from /usr/local/rvm/gems/ruby-2.1.2/gems/thin-1.6.3/lib/thin/runner.rb:200:in run_command' from /usr/local/rvm/gems/ruby-2.1.2/gems/thin-1.6.3/lib/thin/runner.rb:156:inrun!'
from /usr/local/rvm/gems/ruby-2.1.2/gems/thin-1.6.3/bin/thin:6:in <top (required)>' from /usr/local/rvm/gems/ruby-2.1.2/bin/thin:23:inload'
from /usr/local/rvm/gems/ruby-2.1.2/bin/thin:23:in <main>' from /usr/local/rvm/gems/ruby-2.1.2/bin/ruby_executable_hooks:15:ineval'
from /usr/local/rvm/gems/ruby-2.1.2/bin/ruby_executable_hooks:15:in `

'

@joepadmiraal
Copy link
Author

@aspence7 Please provide some more information. What do the logs say. Did you follow the tip from larrycai?

@larrycai
Copy link

Hi Joe:

Curious to know where is fa-thumbs-o-up, how can I see the thumb icon ?

@bemosior
Copy link

Thanks for sharing this, @joepadmiraal!

Found a minor bug. Line 29 of jenkins_build_status.rb should probably accommodate the aborted_anime "color", as it's the state entered when an aborted build becomes in-progress again:

elsif job['color'] == 'aborted' || job['color'] == 'aborted_anime'

@bemosior
Copy link

@larrycai: The Font Awesome icon set is used: https://fortawesome.github.io/Font-Awesome/icons/

@meichau
Copy link

meichau commented Oct 9, 2015

Thanks for sharing this @joepadmiraal.

Since you unfortunately didn't provide a license file with it: could you make clear under which license this project has been provided? Did you intend to use the MIT as given in the Dashing dashboard itself? Or anything else?

Thanks for any clarification.

@bean5
Copy link

bean5 commented Oct 27, 2015

@joepadmiraal Could you ad a license to this? It might be the only thing keeping it from being merged in...is that right @meichau.

@joepadmiraal
Copy link
Author

@bemosior Thanks for sharing the fix. I will update the script.
@meichau I'll add the MIT license

@meichau
Copy link

meichau commented Dec 16, 2015

@joepadmiraal Great, thanks.

@ch0wdan
Copy link

ch0wdan commented Jan 21, 2016

@joepadmiraal - My jenkins server is behind Okta integration. Due to this, running a redirect to Okta signin occurs, which triggers an exception of the widget. Ideas/tips on how to account for this?

scheduler caught exception:
757: unexpected token at '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head>
                                        <meta http-equiv="content-type" content="text/html; charset=utf-8">
                                        <title>Redirect</title>
                                </head><body><h1>Redirect</h1><p>You were redirected to: <a id="redirlink" href=

@joepadmiraal
Copy link
Author

@ch0wdan Looking at your exception it seems like Otwa is returning a normal html page for its redirect. So there is no way for me to create a generic redirect function for this. I guess you would have to parse the html response yourself in the jenkins_build_status.rb file and use the link from redirlink to connect to your Jenkins server.

@ziadvictor
Copy link

I got this in the console:
"You're speaking plain HTTP to an SSL-enabled server port."
Where should I put these lines for HTTPS ?
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

@joepadmiraal
Copy link
Author

@ziadvictor
This could be placed below:

http = Net::HTTP.new(uri.host, uri.port)

after line 53.

@levsa
Copy link

levsa commented Sep 26, 2016

Default values for JENKINS_AUTH['name'] and JENKINS_AUTH['password'] should be nil, null is not a valid ruby value.

@dramamask
Copy link

jenkins_build_status.rb needs the following line:

next if job['color'].nil?

Because jobs of the 'jenkins.branch.OrganizationFolder' do not have a color.

@ak-roche
Copy link

@joepadmiraal thank you.

I would like to monitor specific jobs on my jenkins server -- currently is shows all jobs on my server

ie one release of our product consists of 3 jenkins jobs out of the many we have running.

I would also like to include the iframe widget to show our sonar status of the above 3 git repositories.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment