├── .gitignore
├── README.md
├── assets
└── images
│ └── jenkins_weather
│ ├── health-00to19.gif
│ ├── health-20to39.gif
│ ├── health-40to59.gif
│ ├── health-60to79.gif
│ └── health-80plus.gif
├── config.ru
├── dashboards
└── jenkins.erb
├── jobs
├── jenkins_jobs.rb
├── jenkins_jobstates.rb
├── jenkins_queue.rb
└── jenkins_weather.rb
└── widgets
├── jenkins_jobs
├── jenkins_jobs.coffee
├── jenkins_jobs.html
└── jenkins_jobs.scss
├── jenkins_jobstates
├── jenkins_jobstates.coffee
├── jenkins_jobstates.html
└── jenkins_jobstates.scss
├── jenkins_queue
├── jenkins_queue.coffee
├── jenkins_queue.html
└── jenkins_queue.scss
└── jenkins_weather
├── jenkins_weather.coffee
├── jenkins_weather.html
└── jenkins_weather.scss
/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mneudert/dashing-jenkins/1af351ebe5a7ba764237ed23e011a224b5cd9bcc/.gitignore
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Dashing-Jenkins
2 |
3 | [Dashing](http://shopify.github.com/dashing/) widgets displaying [Jenkins](http://jenkins-ci.org/) API data.
4 |
5 | ## Installation
6 |
7 | 1. copy the job files of all widgets you want to use to your dashboards jobs folder.
8 | 2. configure *url* and *view* in your dashboards *config.ru*.
9 | 3. copy the corresponding assets to your dashboards assets folder.
10 | 4. copy the corresponding html snippets from the demo dashboard to your own dashboard.
11 | 5. copy the corresponding widgets to your dashboards widgets folder.
12 | 6. ???
13 | 7. profit!
14 |
15 | ## Sources
16 |
17 | ### Weather Icons
18 |
19 | Taken from local jenkins installation.
20 |
21 | With just a little modification in the jenkins_weather.scss you could of course load them from a jenkins instance instead of the dashboard host.
22 |
--------------------------------------------------------------------------------
/assets/images/jenkins_weather/health-00to19.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mneudert/dashing-jenkins/1af351ebe5a7ba764237ed23e011a224b5cd9bcc/assets/images/jenkins_weather/health-00to19.gif
--------------------------------------------------------------------------------
/assets/images/jenkins_weather/health-20to39.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mneudert/dashing-jenkins/1af351ebe5a7ba764237ed23e011a224b5cd9bcc/assets/images/jenkins_weather/health-20to39.gif
--------------------------------------------------------------------------------
/assets/images/jenkins_weather/health-40to59.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mneudert/dashing-jenkins/1af351ebe5a7ba764237ed23e011a224b5cd9bcc/assets/images/jenkins_weather/health-40to59.gif
--------------------------------------------------------------------------------
/assets/images/jenkins_weather/health-60to79.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mneudert/dashing-jenkins/1af351ebe5a7ba764237ed23e011a224b5cd9bcc/assets/images/jenkins_weather/health-60to79.gif
--------------------------------------------------------------------------------
/assets/images/jenkins_weather/health-80plus.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mneudert/dashing-jenkins/1af351ebe5a7ba764237ed23e011a224b5cd9bcc/assets/images/jenkins_weather/health-80plus.gif
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | require 'dashing'
2 |
3 | configure do
4 | set :jenkins, {
5 | 'url' => 'https://jenkins.domain:8081/path/to/index',
6 | 'view' => 'All'
7 | }
8 | end
9 |
10 | map Sinatra::Application.assets_prefix do
11 | run Sinatra::Application.sprockets
12 | end
13 |
14 | run Sinatra::Application
15 |
--------------------------------------------------------------------------------
/dashboards/jenkins.erb:
--------------------------------------------------------------------------------
1 | <% content_for(:title) { "Jenkins Dashboard" } %>
2 |
3 |
4 |
5 | -
6 |
7 |
8 |
9 | -
10 |
11 |
12 |
13 | -
14 |
15 |
16 |
17 | -
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/jobs/jenkins_jobs.rb:
--------------------------------------------------------------------------------
1 | require 'net/http'
2 | require 'json'
3 |
4 | http = nil
5 |
6 | SCHEDULER.every '2m', :first_in => 0 do
7 | if not defined? settings.jenkins?
8 | next
9 | end
10 |
11 | if nil == http
12 | url = URI.parse(settings.jenkins['url'])
13 | http = Net::HTTP.new(url.host, url.port)
14 |
15 | if ('https' == url.scheme)
16 | http.use_ssl = true
17 | http.verify_mode = OpenSSL::SSL::VERIFY_NONE
18 | end
19 | end
20 |
21 | api_url = '%s/view/%s/api/json?tree=jobs[name,color]' \
22 | % [ settings.jenkins['url'].chomp('/'), settings.jenkins['view'] ]
23 | response = http.request(Net::HTTP::Get.new(api_url))
24 | jobs = JSON.parse(response.body)['jobs']
25 |
26 | if jobs.empty?
27 | next
28 | end
29 |
30 | jobs.map! { |job|
31 | color = 'grey'
32 |
33 | case job['color']
34 | when 'blue', 'blue_anime'
35 | color = 'blue'
36 | when 'red', 'red_anime'
37 | color = 'red'
38 | end
39 |
40 | { name: job['name'], state: color }
41 | }
42 |
43 | jobs.sort_by { |job| job['name'] }
44 |
45 | send_event('jenkins_jobs', { jobs: jobs })
46 | end
47 |
--------------------------------------------------------------------------------
/jobs/jenkins_jobstates.rb:
--------------------------------------------------------------------------------
1 | require 'net/http'
2 | require 'json'
3 |
4 | http = nil
5 |
6 | SCHEDULER.every '2m', :first_in => 0 do
7 | if not defined? settings.jenkins?
8 | next
9 | end
10 |
11 | if nil == http
12 | url = URI.parse(settings.jenkins['url'])
13 | http = Net::HTTP.new(url.host, url.port)
14 |
15 | if ('https' == url.scheme)
16 | http.use_ssl = true
17 | http.verify_mode = OpenSSL::SSL::VERIFY_NONE
18 | end
19 | end
20 |
21 | api_url = '%s/view/%s/api/json?tree=jobs[color]' \
22 | % [ settings.jenkins['url'].chomp('/'), settings.jenkins['view'] ]
23 | response = http.request(Net::HTTP::Get.new(api_url))
24 | jobs = JSON.parse(response.body)['jobs']
25 |
26 | if jobs.empty?
27 | next
28 | end
29 |
30 | blue = 0
31 | red = 0
32 | grey = 0
33 |
34 | jobs.each { |job|
35 | case job['color']
36 | when 'blue', 'blue_anime'
37 | blue += 1
38 | when 'red', 'red_anime'
39 | red += 1
40 | else
41 | grey += 1
42 | end
43 | }
44 |
45 | send_event('jenkins_jobstates', { blue: blue, red: red, grey: grey })
46 | end
47 |
--------------------------------------------------------------------------------
/jobs/jenkins_queue.rb:
--------------------------------------------------------------------------------
1 | require 'net/http'
2 | require 'json'
3 |
4 | http = nil
5 |
6 | SCHEDULER.every '2m', :first_in => 0 do
7 | if not defined? settings.jenkins?
8 | next
9 | end
10 |
11 | if nil == http
12 | url = URI.parse(settings.jenkins['url'])
13 | http = Net::HTTP.new(url.host, url.port)
14 |
15 | if ('https' == url.scheme)
16 | http.use_ssl = true
17 | http.verify_mode = OpenSSL::SSL::VERIFY_NONE
18 | end
19 | end
20 |
21 | api_url = '%s/queue/api/json?tree=items[inQueueSince,task[color,name]]' \
22 | % [ settings.jenkins['url'].chomp('/') ]
23 | response = http.request(Net::HTTP::Get.new(api_url))
24 | items = JSON.parse(response.body)['items']
25 |
26 | if items.empty?
27 | next
28 | end
29 |
30 | items.sort_by { |item| item['inQueueSince'] }
31 | items.reverse!
32 |
33 | items = items[0..7]
34 |
35 | items.map! { |item|
36 | color = 'grey'
37 |
38 | case item['task']['color']
39 | when 'blue', 'blue_anime'
40 | color = 'blue'
41 | when 'red', 'red_anime'
42 | color = 'red'
43 | end
44 |
45 | { name: item['task']['name'], state: color }
46 | }
47 |
48 | send_event('jenkins_queue', { items: items })
49 | end
50 |
--------------------------------------------------------------------------------
/jobs/jenkins_weather.rb:
--------------------------------------------------------------------------------
1 | require 'json'
2 | require 'net/http'
3 | require 'uri'
4 |
5 | http = nil
6 |
7 | SCHEDULER.every '2m', :first_in => 0 do
8 | if not defined? settings.jenkins?
9 | next
10 | end
11 |
12 | if nil == http
13 | url = URI.parse(settings.jenkins['url'])
14 | http = Net::HTTP.new(url.host, url.port)
15 |
16 | if ('https' == url.scheme)
17 | http.use_ssl = true
18 | http.verify_mode = OpenSSL::SSL::VERIFY_NONE
19 | end
20 | end
21 |
22 | api_url = '%s/view/%s/api/json?tree=jobs[healthReport[iconUrl]]' \
23 | % [ settings.jenkins['url'].chomp('/'), settings.jenkins['view'] ]
24 | response = http.request(Net::HTTP::Get.new(api_url))
25 | jobs = JSON.parse(response.body)['jobs']
26 |
27 | if jobs.empty?
28 | next
29 | end
30 |
31 | report = {
32 | '80plus' => 0,
33 | '60to79' => 0,
34 | '40to59' => 0,
35 | '20to39' => 0,
36 | '00to19' => 0
37 | }
38 |
39 | jobs.each { |job|
40 | next if not job['healthReport']
41 | next if not job['healthReport'][0]
42 | next if not job['healthReport'][0]['iconUrl']
43 |
44 | case job['healthReport'][0]['iconUrl']
45 | when 'health-80plus.png'
46 | report['80plus'] += 1
47 | when 'health-60to79.png'
48 | report['60to79'] += 1
49 | when 'health-40to59.png'
50 | report['40to59'] += 1
51 | when 'health-20to39.png'
52 | report['20to39'] += 1
53 | when 'health-00to19.png'
54 | report['00to19'] += 1
55 | end
56 | }
57 |
58 | send_event('jenkins_weather', { weather: report })
59 | end
60 |
--------------------------------------------------------------------------------
/widgets/jenkins_jobs/jenkins_jobs.coffee:
--------------------------------------------------------------------------------
1 | class Dashing.Jenkins_Jobs extends Dashing.Widget
2 |
--------------------------------------------------------------------------------
/widgets/jenkins_jobs/jenkins_jobs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/widgets/jenkins_jobs/jenkins_jobs.scss:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Widget-jenkins-jobs styles
3 | // ----------------------------------------------------------------------------
4 | .widget-jenkins-jobs {
5 | background-color: lightgrey;
6 | padding-bottom: 0px !important;
7 | padding-left: 0px !important;
8 | padding-right: 0px !important;
9 |
10 | .title {
11 | color: black;
12 | }
13 |
14 | .job {
15 | border-radius: 8px;
16 | float: left;
17 | padding: 4px 0px;
18 | }
19 |
20 | .job[data-state="blue"] {
21 | background-color: green;
22 | }
23 |
24 | .job[data-state="red"] {
25 | background-color: red;
26 | }
27 |
28 | .job[data-state="grey"] {
29 | background-color: grey;
30 | }
31 |
32 | .job span {
33 | padding: 0px 4px;
34 | }
35 | }
36 |
37 | .widget-jenkins-jobs[data-cols="4"] {
38 | .job {
39 | margin-bottom: 1%;
40 | margin-left: 1%;
41 | width: 23.75%;
42 | }
43 |
44 | .job:nth-child(4n + 1) {
45 | clear: left;
46 | }
47 | }
48 |
49 | .widget-jenkins-jobs[data-cols="5"] {
50 | .job {
51 | margin-bottom: 1%;
52 | margin-left: 1%;
53 | width: 18.8%;
54 | }
55 |
56 | .job:nth-child(5n + 1) {
57 | clear: left;
58 | }
59 | }
60 |
61 | .widget-jenkins-jobs[data-cols="6"] {
62 | .job {
63 | margin-bottom: 1%;
64 | margin-left: 1%;
65 | width: 15.5%;
66 | }
67 |
68 | .job:nth-child(6n + 1) {
69 | clear: left;
70 | }
71 | }
72 |
73 | .widget-jenkins-jobs[data-cols="7"] {
74 | .job {
75 | margin-bottom: 1%;
76 | margin-left: 1%;
77 | width: 13.14285%;
78 | }
79 |
80 | .job:nth-child(7n + 1) {
81 | clear: left;
82 | }
83 | }
84 |
85 | .widget-jenkins-jobs[data-cols="8"] {
86 | .job {
87 | margin-bottom: 1%;
88 | margin-left: 1%;
89 | width: 11.375%;
90 | }
91 |
92 | .job:nth-child(8n + 1) {
93 | clear: left;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/widgets/jenkins_jobstates/jenkins_jobstates.coffee:
--------------------------------------------------------------------------------
1 | class Dashing.Jenkins_Jobstates extends Dashing.Widget
2 |
--------------------------------------------------------------------------------
/widgets/jenkins_jobstates/jenkins_jobstates.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/widgets/jenkins_jobstates/jenkins_jobstates.scss:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Widget-jenkins-jobstates styles
3 | // ----------------------------------------------------------------------------
4 | .widget-jenkins-jobstates {
5 | background-color: lightgrey;
6 |
7 | .title {
8 | color: black;
9 | }
10 |
11 | .jobs {
12 | margin: 0 auto
13 | }
14 |
15 | .job {
16 | border-radius: 24px;
17 | display: inline-block;
18 | height: 60px;
19 | line-height: 60px;
20 | margin-left: 12px;
21 | text-align: center;
22 | width: 60px;
23 | }
24 |
25 | .job:first-child {
26 | margin-left: 0;
27 | }
28 |
29 | .job[data-state="blue"] {
30 | background-color: green;
31 | }
32 |
33 | .job[data-state="red"] {
34 | background-color: red;
35 | }
36 |
37 | .job[data-state="grey"] {
38 | background-color: grey;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/widgets/jenkins_queue/jenkins_queue.coffee:
--------------------------------------------------------------------------------
1 | class Dashing.Jenkins_Queue extends Dashing.Widget
2 |
--------------------------------------------------------------------------------
/widgets/jenkins_queue/jenkins_queue.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
--------------------------------------------------------------------------------
/widgets/jenkins_queue/jenkins_queue.scss:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Widget-jenkins-queue styles
3 | // ----------------------------------------------------------------------------
4 | .widget-jenkins-queue {
5 | background-color: lightgrey;
6 |
7 | .title {
8 | color: black;
9 | }
10 |
11 | .queue {
12 | counter-reset: item
13 | }
14 |
15 | .job {
16 | border-radius: 8px;
17 | float: left;
18 | list-style-type: none;
19 | margin: 4px;
20 | padding: 6px;
21 | }
22 |
23 | .job:before {
24 | content: counter(item) ". ";
25 | counter-increment: item;
26 | color: black;
27 | }
28 |
29 | .job[data-state="blue"] {
30 | background-color: green;
31 | }
32 |
33 | .job[data-state="red"] {
34 | background-color: red;
35 | }
36 |
37 | .job[data-state="grey"] {
38 | background-color: grey;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/widgets/jenkins_weather/jenkins_weather.coffee:
--------------------------------------------------------------------------------
1 | class Dashing.Jenkins_Weather extends Dashing.Widget
2 |
--------------------------------------------------------------------------------
/widgets/jenkins_weather/jenkins_weather.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/widgets/jenkins_weather/jenkins_weather.scss:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------------
2 | // Widget-jenkins-weather styles
3 | // ----------------------------------------------------------------------------
4 | .widget-jenkins-weather {
5 | background-color: lightgrey;
6 |
7 | .title {
8 | color: black;
9 | }
10 |
11 | .ranges {
12 | margin: 0 auto
13 | }
14 |
15 | .range {
16 | background-color: grey;
17 | background-position: 4px 4px;
18 | background-repeat: no-repeat;
19 | border-radius: 24px;
20 | display: inline-block;
21 | height: 40px;
22 | line-height: 40px;
23 | margin-bottom: 12px;
24 | margin-left: 12px;
25 | text-align: right;
26 | padding-right: 12px;
27 | width: 60px;
28 | }
29 |
30 | .range:first-child {
31 | margin-left: 0;
32 | }
33 |
34 | .range[data-range="80plus"] {
35 | background-image: url("/assets/jenkins_weather/health-80plus.gif")
36 | }
37 |
38 | .range[data-range="60to79"] {
39 | background-image: url("/assets/jenkins_weather/health-60to79.gif")
40 | }
41 |
42 | .range[data-range="40to59"] {
43 | background-image: url("/assets/jenkins_weather/health-40to59.gif")
44 | }
45 |
46 | .range[data-range="20to39"] {
47 | background-image: url("/assets/jenkins_weather/health-20to39.gif")
48 | }
49 |
50 | .range[data-range="00to19"] {
51 | background-image: url("/assets/jenkins_weather/health-00to19.gif")
52 | }
53 | }
54 |
--------------------------------------------------------------------------------