Last active
August 17, 2018 09:16
-
-
Save gatopeich/e2d2a2b549744e0c5e9f3997f91ede7b to your computer and use it in GitHub Desktop.
Simple tray icon to display status of Jenkins builds, based on Python, wget, GTK StatusIcon, and some random art
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# Display status of several Jenkins jobs in system tray | |
# Tooltip shows the list of builds and status | |
# SVG-based art represents the jobs status (random circles whose color reflects build status, green for OK etc.) | |
# On click, point default browser to ON_CLICK_URL | |
JOBS_URL = 'http://jenkins/job/' | |
ON_CLICK_URL = 'http://jenkins/user/myself/my-views/view/My%20Dashboard/' | |
WGET_AUTH = '--auth-no-challenge --user=XXX --password=YYY' | |
JOBS = 'job1 job2 job3'.split() | |
# End of company-specific info | |
COLORS = { 'passing' : 'lawngreen', 'passed' : 'forestgreen', 'running' : 'deepskyblue', 'unknown' : 'grey', 'failing' : 'red' } | |
# Preiods in milliseconds | |
ANIMATION_PERIOD = 2000 | |
REFRESH_PERIOD = 10000 | |
import gtk | |
import gobject | |
import random | |
import subprocess | |
import tempfile | |
import time | |
import ast, urllib2, base64 | |
def pyJenkins(url): | |
request = urllib2.Request(url+'/api/python') | |
request.add_header('Authorization', 'Basic YWd1c3RpbnA6NFJhczFTNWE=') | |
return ast.literal_eval(urllib2.urlopen(request).read()) | |
my_dashboard = pyJenkins(ON_CLICK_URL) | |
print (my_dashboard) | |
JOBS = [] | |
for job in my_dashboard['jobs']: | |
details = pyJenkins(job['url']+'/lastBuild') | |
details['actions'] = len(details['actions']) | |
details['changeSet'] = len(details['changeSet']) | |
print job['name'], details | |
JOBS += [job['name']] | |
icon = gtk.StatusIcon() | |
icon.set_from_stock(gtk.STOCK_CANCEL) | |
icon.set_visible(True) | |
svg = tempfile.NamedTemporaryFile() | |
time_to_refresh = 0 | |
def refresh(): | |
global time_to_refresh, all_status | |
if time_to_refresh > 0: | |
time_to_refresh -= ANIMATION_PERIOD | |
else: | |
time_to_refresh = REFRESH_PERIOD | |
all_status = [] | |
tooltip = '' | |
for job in JOBS: | |
lastBuild = pyJenkins(JOBS_URL+job+'/lastBuild') | |
status = 'running' if lastBuild['building'] else 'passing' if lastBuild['result'] == 'SUCCESS' else 'failing' | |
hours_ago = (time.time() - lastBuild['timestamp']/1000) / 3600 | |
if status == 'passing' and hours_ago > 24: status = 'passed' | |
# print (job,status) | |
color = COLORS.get(status,'yellow') | |
line = '%s: <span color="%s">%s</span>'%(job,color,status) | |
if status not in ('passed','unknown'): line = '<big>'+line+'</big>' | |
line += ' %d hours ago'%hours_ago if hours_ago < 24 else ' %d days ago'%(hours_ago/24) | |
tooltip += '\n'+line if tooltip else line | |
print (line) | |
all_status += [color] | |
icon.set_tooltip_markup('<b>'+tooltip+'</b>') | |
# Animate status icon every second: | |
svg.seek(0) | |
svg.write('<svg width="99" height="99">') | |
random.shuffle(all_status) | |
for color in all_status: | |
style = 'fill="%s" fill-opacity="0.8"'%color | |
# style += 'stroke="%s" stroke-width="3"'%color # Looks nicer at higher scale | |
def rnd(): return random.randint(20,80) | |
x,y = rnd(),rnd() | |
svg.write('<circle cx="%d" cy="%d" r="%d" %s/>'%(x,y,min(x,y,99-x,99-y),style)) | |
svg.write('</svg>') | |
svg.truncate() | |
svg.flush() | |
icon.set_from_file(svg.name) | |
return True | |
gobject.timeout_add(ANIMATION_PERIOD, refresh) | |
refresh() | |
def on_click(icon): | |
refresh(); | |
subprocess.call("xdg-open " + ON_CLICK_URL, shell=True) | |
icon.connect('activate', on_click) | |
menu = gtk.Menu() | |
quit_item = gtk.MenuItem("Quit MyJenkinsTray") | |
menu.append(quit_item) | |
quit_item.connect('activate', gtk.main_quit) | |
quit_item.show() | |
icon.connect('popup-menu', lambda data, button, time: menu.popup(None, None, None, button, time)) | |
gtk.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment