Stream Travis-CI updates into notifications center
OSX 10.8 comes with a new feature i've been waiting for - Notifications Center. Its pretty much the same notifications panel that already exists on iOS platform. It also seems like a logical way to organize application notifications. Technical part of it is the same as existing apple push notifications service except it offers local delivery method. I wanted to hook up build notifications from Travis-CI. It uses Pusher service to handle all events, plus it has few ruby libraries to work with.
Eloy Durán created a very simple terminal tool to send local notifications called terminal-notifier. It does exactly what i needed and the source code is available so you can customize application icon and name if you want to.
To send a notification all you have to do is run command:
$ ./terminal-notifier_1.1.0/terminal-notifier.app/Contents/MacOS/terminal-notifier group title message
All i had to do it write some ruby code (didnt want to mess with Objective-C) that gets an event stream from public travis-ci and call notifier application.
Here is some code (travis.rb
):
require 'pusher-client'
require 'json'
class Travis
def initialize(pusher_token)
@socket = PusherClient::Socket.new(pusher_token)
end
def parse_build(payload)
JSON.parse(payload)
end
def make_notification(data)
result = data['build']['result'] == 0 ? 'PASSED' : 'FAILED'
title = data['repository']['slug']
message = "Build ##{data['repository']['last_build_number']} #{result}"
{:title => title, :message => message}
end
def start
@socket.subscribe('common')
@socket['common'].bind('build:finished') do |data|
n = make_notification(parse_build(data))
add_notification(n[:title], n[:message])
end
@socket.connect
end
def add_notification(title, message)
`./terminal-notifier_1.1.0/terminal-notifier.app/Contents/MacOS/terminal-notifier "#{title}" "#{title}" "#{message}"`
end
end
travis = Travis.new('23ed642e81512118260e')
travis.start
Unfortunately, the original pusher-client
gem is broken, so you'd have to create a
Gemfile
with following content:
source :rubygems
gem 'pusher-client', :git => 'git://github.com/pusher/pusher-ruby-client.git'
Then run:
bundle install
This will get you customized gem. Fire up the client by running:
bundle exec ruby travis.rb
Check out the result:
You can also grab the source code here - https://gist.github.com/3186275
Update
Eloy Durán had recently released a ruby gem terminal-notifier that adds ability to send notifications straight from ruby. Installation is easy:
gem install terminal-notifier
I also made an update to the original script, by clicking on notification message it opens up url to travis build details. Updated code:
require 'terminal-notifier'
require 'pusher-client'
require 'json'
require 'pp'
class Travis
attr_accessor :watchlist
# Initialize a new connection to travis feed
#
# publisher_token - Valid pusher token
# watchlist - Array or repositories to watch
#
def initialize(pusher_token, watchlist=[])
@socket = PusherClient::Socket.new(pusher_token)
@watchlist = watchlist
end
def start
@socket.subscribe('common')
@socket['common'].bind('build:finished') do |data|
n = make_notification(parse_build(data))
if watchlist.empty?
add_notification(n)
else
add_notification(n) if watchlist.include?(n[:title])
end
end
@socket.connect
end
private
def parse_build(payload)
JSON.parse(payload)
end
def make_notification(data)
id = data['build']['id']
number = data['repository']['last_build_number']
result = data['build']['result'] == 0 ? 'PASSED' : 'FAILED'
title = data['repository']['slug']
message = "Build ##{number} #{result}"
url = "http://travis-ci.org/#!/#{title}/builds/#{id}"
{:title => title, :message => message, :url => url}
end
def add_notification(n)
TerminalNotifier.notify(n[:message], :title => n[:title], :open => n[:url])
end
end
travis = Travis.new('23ed642e81512118260e')
travis.start
You can also specify a list of watched repositories by providing an additional parameter:
Travis.new('token', ['rails/rails'])
# or directly
travis = Travis.new('token')
travis.watchlist = ['rails/rails']