from twisted.internet import reactor from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, EXCEPTION from twisted.python import log from buildbot.status.base import StatusReceiver import sys, time existing = sys.modules.pop('buildbot.status.words', None) from buildbot.status import words sys.modules.pop('buildbot.status.words', None) class CustomIrcStatusBot(words.IrcStatusBot, StatusReceiver): def __init__(self, *args, **kwargs): self.builds_underway = {} self.build_unique = 0 words.IrcStatusBot.__init__(self, *args, **kwargs) def buildFinished(self, buildername, build, results): results = {SUCCESS: "Success", WARNINGS: "Warnings", FAILURE: "Failure", EXCEPTION: "Exception", } builder = build.getBuilder() changes = build.getChanges() key = self.mk_changes_key(changes) build_num, branch, start_time = self.builds_underway.get(key, (-1, "unknown branch")) finish_time = time.time() if build_num == -1: self.announce("odd; untracked build just occured: %s" % key) self.builds_underway[key] = (build_num, branch, finish_time) self.announce("builder %s, build %i, %s: %s; %d seconds" % (builder.getName(), build_num, branch, results.get(build.getResults(), "??"), finish_time - start_time)) def command_LOADAVG(self, user, reply, args): self.reply(reply, "loadavg is:%s" % open("/proc/loadavg").read().strip()) @staticmethod def mk_changes_key(changes): return ';;'.join(sorted("%s;%s;%s" % (change.branch, change.revision, change.who) for change in changes)) @property def unique_change_num(self): self.build_unique += 1 return self.build_unique def announce_changes(self, build): changes = build.getChanges() key = self.mk_changes_key(changes) if key in self.builds_underway: return unique = self.unique_change_num branches = ', '.join(sorted(set(change.branch for change in changes))) self.builds_underway[key] = (unique, branches, time.time()) changes_msg = ', '.join('"%s"' % change.comments for change in changes) if len(changes_msg) > 150: changes_msg = changes_msg[:200] + "..." self.announce("started build %i for %s: %s" % (unique, branches, changes_msg)) # let changes sit for 30 minutes. reactor.callLater(30*60, self.builds_underway.pop, key, None) def buildStarted(self, buildername, build): self.announce_changes(build) def connectionMade(self): self.irb = IrcBuildRequest(self, self.announce) words.IrcStatusBot.connectionMade(self) r = self.factory.status.subscribe(self) def announce(self, msg): for c in self.channels: self.reply(c, msg) def builderAdded(self, name, status): status.subscribe(self) # def builderChangedState(self, *args): # log.msg("invoked builderChanged: %s" % (args,)) # return StatusReceiver.builderChangedState(self, *args) orig_IrcBuildRequest = words.IrcBuildRequest class IrcBuildRequest(orig_IrcBuildRequest): def started(self, c): self.hasStarted = True if self.timer: self.timer.cancel() del self.timer s = c.getStatus() eta = s.getETA() response = "build #%d" % s.getNumber() if eta is not None: response += " ETA %s" % self.parent.convertTime(eta) self.parent.reply(self.reply, response) d = s.waitUntilFinished() d.addCallback(self.parent.buildFinished, self.reply) self.reply(str(self.reply)) class IRC(words.IRC): def remote_buildFinished(self, build, result): log.msg("remote invoked") def buildFinished(self, build, result): log.msg("local invoked") def builderAdded(self, *args): log.msg("invoked: builderAdded %s", (args, )) words.IrcBuildRequest = IrcBuildRequest words.IrcStatusFactory.protocol = CustomIrcStatusBot IRC = words.IRC if existing is not None: sys.modules['buildbot.status.words'] = existing del existing