[Buildbot-devel] Making IRC bot annouce every failure?

Nathaniel Smith njs at pobox.com
Tue Oct 18 00:36:27 UTC 2005


On Mon, Oct 17, 2005 at 05:35:47PM -0700, Nathaniel Smith wrote:
> On Sat, Oct 15, 2005 at 11:21:38AM +1000, Brad Hards wrote:
> > I can only get the IRC bot to respond to commands and watch a single builder, 
> > not to do asynchronous announcements for every failure for every builder.
> > 
> > Is that possible?
> 
> We use the attached patch (which is a hacked-up version of a patch I

This one.

-- Nathaniel

-- 
"...these, like all words, have single, decontextualized meanings: everyone
knows what each of these words means, everyone knows what constitutes an
instance of each of their referents.  Language is fixed.  Meaning is
certain.  Santa Claus comes down the chimney at midnight on December 24."
  -- The Language War, Robin Lakoff
-------------- next part --------------
Index: status/words.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/words.py,v
retrieving revision 1.32
diff -u -r1.32 words.py
--- status/words.py	8 Dec 2004 04:15:23 -0000	1.32
+++ status/words.py	18 Oct 2005 00:34:15 -0000
@@ -480,6 +480,11 @@
         self.channels = channels
         self.allowForce = allowForce
 
+        self.watched = [] # list of all builders we are watching
+
+        # allow us to keep track of previous builds
+        self.lastBuilds = {} # name -> last build
+
         # need to stash the factory so we can give it the status object
         self.f = IrcStatusFactory(self.nick, self.channels)
 
@@ -489,14 +494,85 @@
     def setServiceParent(self, parent):
         service.MultiService.setServiceParent(self, parent)
         self.f.status = parent.getStatus()
+        # by subscribing, we will get
+        # builderChangedState, buildStarted, and buildFinished
+        self.f.status.subscribe(self)
         if self.allowForce:
             self.f.control = interfaces.IControl(parent)
 
+    # unsubscribe ourselves, and unsubscribe from all watched builders
+    def disownServiceParent(self):
+        self.f.status.unsubscribe(self)
+        for w in self.watched:
+            w.unsubscribe(self)
+        return service.Service.disownServiceParent(self)
+
     def stopService(self):
         # make sure the factory will stop reconnecting
         self.f.shutdown()
         return service.MultiService.stopService(self)
 
+    # overridable base methods
+
+    # subscribe ourselves to each builder added and watch them
+    def builderAdded(self, builderName, builder):
+        self._botMsg("builder %s added" % builderName)
+        self.watched.append(builder)
+        return self
+
+    def builderRemoved(self, builderName, builder):
+        self._botMsg("builder %s removed" % builderName)
+        self.watched.remove(builder)
+        return self
+
+    # status.subscribe-triggered methods
+    def builderChangedState(self, builderName, state, eta=None):
+        #self._botMsg('builder %s changed to %r' % (builderName, state)) 
+        pass
+
+    def buildStarted(self, builderName, build):
+        #self._botMsg('builder %s started build %r' % (builderName, build)) 
+        pass
+
+    def buildFinished(self, name, build, results):
+        # get the responsible
+        users = build.getResponsibleUsers()
+        if not users:
+            users = ["<unknown>"]
+
+        # get the last build status
+        lastBuild = None
+        if name in self.lastBuilds:
+            lastBuild = self.lastBuilds[name]
+
+        # if build got broken when it was working before, announce it
+        if build.getResults() == FAILURE:
+            if not lastBuild or lastBuild.getResults() == SUCCESS:
+                self._botMsg('%s build just went RED; changes by: %s. (http://venge.net:9000)'
+                             % (name, ", ".join(users)))
+            elif lastBuild.getResults() == FAILURE:
+                self._botMsg('%s build is still RED; changes by: %s. (http://venge.net:9000)'
+                             % (name, ", ".join(users)))
+
+        # if build now works when it was broken before, announce it
+        if build.getResults() == SUCCESS:
+            if lastBuild and lastBuild.getResults() == FAILURE:
+                self._botMsg('%s builds just went GREEN; changes by: %s. (http://venge.net:9000)'
+                             % (name, ", ".join(users)))
+
+        # store this build result for the next comparison
+        self.lastBuilds[name] = build
+        
+    # make the bot msg in all channels if connected
+    def _botMsg(self, msg):
+        bot = self.f.p
+        if not bot:
+            log.msg("No bot, could not say", msg)
+            return
+        for channel in self.channels:
+            log.msg("Saying in channel %s" % channel, msg)
+            bot.msg(channel, msg)
+
 
 def main():
     from twisted.internet import app


More information about the devel mailing list