Skip to content

Commit

Permalink
add useRevisions option for altered IRC bot messages
Browse files Browse the repository at this point in the history
This fixes #1707 by allowing the IRC bot messages to
give a list of revisions instead of the build number
when sending status messages. This also added the
`getRevisions` method to IBuildStatus instances.
  • Loading branch information
dzhurley committed Aug 25, 2011
1 parent bfefb90 commit cb4c5b2
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 23 deletions.
4 changes: 4 additions & 0 deletions master/buildbot/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,10 @@ def getChanges():
"""Return a list of Change objects which represent which source
changes went into the build."""

def getRevisions():
"""Returns a string representing the list of revisions that led to
the build, rendered from each Change.revision"""

def getResponsibleUsers():
"""Return a list of Users who are to blame for the changes that went
into this build. If anything breaks (at least anything that wasn't
Expand Down
9 changes: 9 additions & 0 deletions master/buildbot/status/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ def getReason(self):
def getChanges(self):
return self.changes

def getRevisions(self):
revs = []
for c in self.changes:
rev = str(c.revision)
if rev > 7: # for long hashes
rev = rev[:7]
revs.append(rev)
return ", ".join(revs)

def getResponsibleUsers(self):
return self.blamelist

Expand Down
3 changes: 3 additions & 0 deletions master/buildbot/status/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ def remote_getReason(self):
def remote_getChanges(self):
return [IRemote(c) for c in self.b.getChanges()]

def remote_getRevisions(self):
return self.b.getRevisions()

def remote_getResponsibleUsers(self):
return self.b.getResponsibleUsers()

Expand Down
90 changes: 67 additions & 23 deletions master/buildbot/status/words.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ class IrcBuildRequest:
hasStarted = False
timer = None

def __init__(self, parent):
def __init__(self, parent, useRevisions=False):
self.parent = parent
self.useRevisions = useRevisions
self.timer = reactor.callLater(5, self.soon)

def soon(self):
Expand All @@ -65,7 +66,10 @@ def started(self, s):
self.timer.cancel()
del self.timer
eta = s.getETA()
response = "build #%d forced" % s.getNumber()
if self.useRevisions:
response = "build containing revision(s) [%s] forced" % s.getRevisions()
else:
response = "build #%d forced" % s.getNumber()
if eta is not None:
response = "build forced [ETA %s]" % self.parent.convertTime(eta)
self.parent.send(response)
Expand Down Expand Up @@ -93,6 +97,7 @@ def __init__(self, channel):
self.notify_events = {}
self.subscribed = 0
self.muted = False
self.useRevisions = channel.useRevisions
self.reported_builds = [] # tuples (when, buildername, buildnum)
self.add_notification_events(channel.notify_events)

Expand Down Expand Up @@ -298,8 +303,12 @@ def command_WATCH(self, args, who):
assert not build.isFinished()
d = build.waitUntilFinished()
d.addCallback(self.watchedBuildFinished)
r = "watching build %s #%d until it finishes" \
% (which, build.getNumber())
if self.useRevisions:
r = "watching build %s containing revision(s) [%s] until it finishes" \
% (which, build.getRevisions())
else:
r = "watching build %s #%d until it finishes" \
% (which, build.getNumber())
eta = build.getETA()
if eta is not None:
r += " [%s]" % self.convertTime(eta)
Expand Down Expand Up @@ -339,11 +348,15 @@ def buildStarted(self, builderName, build):
log.msg('Not notifying for a build when started-notification disabled')
return

r = "build #%d of %s started, including [%s]" % \
(build.getNumber(),
builder.getName(),
", ".join([str(c.revision) for c in build.getChanges()])
)
if self.useRevisions:
r = "build containing revision(s) [%s] on %s started" % \
(build.getRevisions(), builder.getName())
else:
r = "build #%d of %s started, including [%s]" % \
(build.getNumber(),
builder.getName(),
", ".join([str(c.revision) for c in build.getChanges()])
)

self.send(r)

Expand All @@ -370,12 +383,19 @@ def buildFinished(self, builderName, build, results):

builder_name = builder.getName()
buildnum = build.getNumber()
buildrevs = build.getRevisions()

if self.reportBuild(builder_name, buildnum):
r = "build #%d of %s is complete: %s" % \
(buildnum,
builder_name,
self.results_descriptions.get(build.getResults(), "??"))
if self.useRevisions:
r = "build containing revision(s) [%s] on %s is complete: %s" % \
(buildrevs,
builder_name,
self.results_descriptions.get(build.getResults(), "??"))
else:
r = "build #%d of %s is complete: %s" % \
(buildnum,
builder_name,
self.results_descriptions.get(build.getResults(), "??"))
r += " [%s]" % " ".join(build.getText())
buildurl = self.channel.status.getURLForThing(build)
if buildurl:
Expand Down Expand Up @@ -421,12 +441,19 @@ def watchedBuildFinished(self, b):

builder_name = b.getBuilder().getName()
buildnum = b.getNumber()
buildrevs = b.getRevisions()

if self.reportBuild(builder_name, buildnum):
r = "Hey! build %s #%d is complete: %s" % \
(builder_name,
buildnum,
self.results_descriptions.get(b.getResults(), "??"))
if self.useRevisions:
r = "Hey! build %s containing revision(s) [%s] is complete: %s" % \
(builder_name,
buildrevs,
self.results_descriptions.get(b.getResults(), "??"))
else:
r = "Hey! build %s #%d is complete: %s" % \
(builder_name,
buildnum,
self.results_descriptions.get(b.getResults(), "??"))
r += " [%s]" % " ".join(b.getText())
self.send(r)
buildurl = self.channel.status.getURLForThing(b)
Expand Down Expand Up @@ -470,7 +497,7 @@ def command_FORCE(self, args, who):
ss = SourceStamp(branch=branch, revision=revision)
d = bc.submitBuildRequest(ss, reason)
def subscribe(buildreq):
ireq = IrcBuildRequest(self)
ireq = IrcBuildRequest(self, self.useRevisions)
buildreq.subscribe(ireq.started)
d.addCallback(subscribe)
d.addErrback(log.err, "while forcing a build")
Expand All @@ -497,14 +524,19 @@ def command_STOP(self, args, who):
return
for build in builds:
num = build.getNumber()
revs = build.getRevisions()

# obtain the BuildControl object
buildcontrol = buildercontrol.getBuild(num)

# make it stop
buildcontrol.stopBuild(r)

self.send("build %d interrupted" % num)
if self.useRevisions:
response = "build containing revision(s) [%s] interrupted" % revs
else:
response = "build %d interrupted" % num
self.send(response)

command_STOP.usage = "stop build <which> <reason> - Stop a running build"

Expand Down Expand Up @@ -724,7 +756,9 @@ class IrcStatusBot(irc.IRCClient):
implements(IChannel)
contactClass = IRCContact

def __init__(self, nickname, password, channels, status, categories, notify_events, noticeOnChannel = False, showBlameList = False):
def __init__(self, nickname, password, channels, status, categories,
notify_events, noticeOnChannel=False, useRevisions=False,
showBlameList=False):
"""
@type nickname: string
@param nickname: the nickname by which this bot should be known
Expand All @@ -739,6 +773,10 @@ def __init__(self, nickname, password, channels, status, categories, notify_even
@param noticeOnChannel: Defaults to False. If True, error messages
for bot commands will be sent to the channel
as notices. Otherwise they are sent as a msg.
@type useRevisions: boolean
@param useRevisions: if True, messages from the bot will use the
revisions from the Changes in the build and not
the build number.
"""
self.nickname = nickname
self.channels = channels
Expand All @@ -751,6 +789,7 @@ def __init__(self, nickname, password, channels, status, categories, notify_even
self.hasQuit = 0
self.contacts = {}
self.noticeOnChannel = noticeOnChannel
self.useRevisions = useRevisions
self.showBlameList = showBlameList

def msgOrNotice(self, dest, message):
Expand Down Expand Up @@ -856,7 +895,8 @@ class IrcStatusFactory(ThrottledClientFactory):
shuttingDown = False
p = None

def __init__(self, nickname, password, channels, categories, notify_events, noticeOnChannel = False, showBlameList = False):
def __init__(self, nickname, password, channels, categories, notify_events,
noticeOnChannel=False, useRevisions=False, showBlameList=False):
#ThrottledClientFactory.__init__(self) # doesn't exist
self.status = None
self.nickname = nickname
Expand All @@ -865,6 +905,7 @@ def __init__(self, nickname, password, channels, categories, notify_events, noti
self.categories = categories
self.notify_events = notify_events
self.noticeOnChannel = noticeOnChannel
self.useRevisions = useRevisions
self.showBlameList = showBlameList

def __getstate__(self):
Expand All @@ -882,6 +923,7 @@ def buildProtocol(self, address):
self.channels, self.status,
self.categories, self.notify_events,
noticeOnChannel = self.noticeOnChannel,
useRevisions = self.useRevisions,
showBlameList = self.showBlameList)
p.factory = self
p.status = self.status
Expand Down Expand Up @@ -915,12 +957,12 @@ class IRC(base.StatusReceiverMultiService):

compare_attrs = ["host", "port", "nick", "password",
"channels", "allowForce", "useSSL",
"categories"]
"useRevisions", "categories"]

def __init__(self, host, nick, channels, port=6667, allowForce=False,
categories=None, password=None, notify_events={},
noticeOnChannel = False, showBlameList = True,
useSSL=False):
useRevisions=False, useSSL=False):
base.StatusReceiverMultiService.__init__(self)

assert allowForce in (True, False) # TODO: implement others
Expand All @@ -932,12 +974,14 @@ def __init__(self, host, nick, channels, port=6667, allowForce=False,
self.channels = channels
self.password = password
self.allowForce = allowForce
self.useRevisions = useRevisions
self.categories = categories
self.notify_events = notify_events
log.msg('Notify events %s' % notify_events)
self.f = IrcStatusFactory(self.nick, self.password,
self.channels, self.categories, self.notify_events,
noticeOnChannel = noticeOnChannel,
useRevisions = useRevisions,
showBlameList = showBlameList)

# don't set up an actual ClientContextFactory if we're running tests.
Expand Down
7 changes: 7 additions & 0 deletions master/docs/manual/cfg-statustargets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,13 @@ If the `categories` is set to a category of builders (see categories
option in :ref:`Builder-Configuration`) changes related to only that
category of builders will be sent to the channel.

If the `useRevisions` option is set to `True`, the IRC bot will send status messages
that replace the build number with a list of revisions that are contained in that
build. So instead of seeing `build #253 of ...`, you would see something like
`build containing revisions [a87b2c4]`. Revisions that are stored as hashes are
shortened to 7 characters in length, as multiple revisions can be contained in one
build and may exceed the IRC message length limit.

.. _PBListener:

PBListener
Expand Down

0 comments on commit cb4c5b2

Please sign in to comment.