Hudson Build Status Lava Lamps

This Ruby program lights lava lamps based on the status of a Hudson RSS feed- if the most recent of any builds fails, the red lamp will light; if the most recent of each builds succeeds, the program will light the green lamp.

This solution is based on the Pragmatic Programmer's Lava Lamp solution for Cruise Control: http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Monitor/Devices/BubbleBubbleBuildsInTrouble.rdoc

You will need:

Once you can run the program, it's no trouble to automate this through cron or Hudson.

#!/usr/bin/env ruby
require 'net/http'
require 'uri'
require 'rubygems'
require 'atom'

# Light lava lamps based on Hudson build status RSS feed
# Green lamp lights if all builds are good;
# Red lamp lights if any build fails.
#
# Requires atom gem and bottlerocket X10 control software to be installed.
#
class HudsonLava

  def initialize
    @BOTTLE_ROCKET_COMMAND="/usr/local/bin/br"
    @GREEN_LAMP='1' # codes set on X10 lamp moduels
    @RED_LAMP='2'
  end

  def usage
    puts "hudsonLava [hudsonRssFeedUrl]"
    puts "  Light lava lamps based on Hudson build status RSS feed."
    puts "  hudsonRssFeedUrl: URL of RSS feed for builds you want to monitor; must contain SUCCESS and FAILURE messages."
  end

  def parse_args
    if ARGV.size == 1 then
      @FEED_URL = ARGV[0]
    else
      usage
      exit
    end
  end

  def get_rss_feed(feedUrl)
    feedXml = Net::HTTP::get(URI::parse(feedUrl))
    Atom::Feed.new(feedXml)
  end

  def parse_rss_feed(rssFeed)
    buildList = []
    rssFeed.entries.each { |entry|
       buildLine = "#{entry.title} #{entry.published.strftime('%Y-%m-%d')}"
       buildName, buildNumber, buildStatus, buildDate = buildLine.split
       buildNumber = buildNumber[1..-1]
       buildStatus = buildStatus[1..-2]
       buildList += [[buildName, buildNumber, buildStatus, buildDate]]
    }

    buildDataHash = {}
    buildList.each { |buildData|
       buildName, buildNumber, buildStatus, buildDate = buildData

       if buildDataHash.member?(buildName)
          buildDataHash[buildName].addInfo(["#{buildNumber} #{buildStatus} #{buildDate}"])
       else
          buildDataHash[buildName] = BuildData.new
          buildDataHash[buildName].setName("#{buildName}")
          buildDataHash[buildName].setInfo(["#{buildNumber} #{buildStatus} #{buildDate}"])
       end
    }

    buildDataHash
  end

  def get_success_indicator(buildDataHash)
    success = true
    buildDataHash.each { |buildName, buildData|
      if buildData.getInfo().first =~ /FAILED/
         puts "#{buildName} failed."
         success = false
      end
    }
    success
  end

  def lava_lamp(onOff, lampName)
    system "#{@BOTTLE_ROCKET_COMMAND} --#{onOff}=#{lampName}"
  end

  def light_green_lamp
    lava_lamp("on", @GREEN_LAMP)
    lava_lamp("off", @RED_LAMP)
  end

  def light_red_lamp
    lava_lamp("on", @RED_LAMP)
    lava_lamp("off", @GREEN_LAMP)
  end

  def light_lava_lamp(status)
    if status == true
      puts "No failed builds- lamp is green."
      light_green_lamp
    else
      puts "At least one build failed- lamp is red."
      light_red_lamp
    end
  end

  def main
    parse_args
    rssFeed = get_rss_feed(@FEED_URL)
    buildDataHash = parse_rss_feed(rssFeed)
    status = get_success_indicator(buildDataHash)
    light_lava_lamp(status)
  end

end

class BuildData
  def initialize
    @buildName = ""
    @buildInfo = []
  end

  def setName(name)
    @name = name
  end

  def setInfo(info)
    @info = info
  end

  def addInfo(info)
    @info += info
  end

  def getInfo()
    return @info
  end

  def getName()
    return @name
  end

end

if $0 == __FILE__
  HudsonLava.new.main
end

Labels

  Edit Labels
(None)
  1. Oct 19, 2007

    Anonymous says:

    This script breaks if your projects have a space in them. I replaced buildLi...

    This script breaks if your projects have a space in them. I replaced

    buildLine = "#{entry.title} #{entry.published.strftime('%Y-%m-%d')}"
           buildName, buildNumber, buildStatus, buildDate = buildLine.split
           buildNumber = buildNumber[1..-1]

    with

           buildName, rest = buildLine.split "#"
           buildNumber, buildStatus, buildDate = rest.split 

    Also, it's nice for the planet to turn your lamps off at night and on weekends! Add a method:

      def lights_off
        lava_lamp("off", @RED_LAMP)
        lava_lamp("off", @GREEN_LAMP)
      end

    and change light_lava_lamp to

      def light_lava_lamp(status)
        # lights off at night and weekends!
        unless Date.today.wday.between? 0,5 and Time.now.hour.between? 8,19
          puts "It's %s, so lights out!" % Time.now.to_s
          lights_off
        else
          if status == true
            puts "At %s: No failed builds- lamp is green." % Time.now.to_s
            light_green_lamp
          else
            puts "At %s: At least one build failed- lamp is red." % Time.now.to_s
            light_red_lamp
          end
        end
      end
  2. Feb 12, 2008

    Anonymous says:

    Gday, This line doesn't work with my Hudson ver 1.159: if buildData.getInfo().f...

    Gday,

    This line doesn't work with my Hudson ver 1.159:

    if buildData.getInfo().first =~ /FAILED/
    

    Change to

    if buildData.getInfo().first =~ /FAIL/
    

    Cheers,
    Bill

  3. Mar 22

    Vijay Doshi says:

    Agile toys has a kit that includes a beacon light and the x10 hardware for a rea...

    Agile toys has a kit that includes a beacon light and the x10 hardware for a reasonable price.

     http://www.agiletoys.com