Skip to content

Commit

Permalink
Merge branch 'webhook-retries' of git://github.com/dustin/buildbot
Browse files Browse the repository at this point in the history
  • Loading branch information
Dustin J. Mitchell committed Jul 5, 2009
2 parents 1b80f86 + 3043fbc commit 9b4c509
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 2 deletions.
4 changes: 2 additions & 2 deletions buildbot/status/builder.py
Expand Up @@ -2097,11 +2097,11 @@ def getURLForThing(self, thing):
break
else:
return None
return prefix + "builders/%s/builds/%d/steps/%s/logs/%d" % (
return prefix + "builders/%s/builds/%d/steps/%s/logs/%s" % (
urllib.quote(builder.getName(), safe=''),
build.getNumber(),
urllib.quote(step.getName(), safe=''),
lognum)
urllib.quote(log.getName()))

def getChangeSources(self):
return list(self.botmaster.parent.change_svc)
Expand Down
139 changes: 139 additions & 0 deletions contrib/webhook_status.py
@@ -0,0 +1,139 @@
import urllib

from twisted.python import log
from twisted.web import client, error
from twisted.application import service

from buildbot import status

class WebHookTransmitter(status.base.StatusReceiverMultiService):
"""
A webhook status listener for buildbot.
WebHookTransmitter listens for build events and sends the events
as http POSTs to one or more webhook URLs.
The easiest way to deploy this is to place it next to your
master.cfg and do something like this (assuming you've got a
postbin URL for purposes of demonstration):
from webhook_status import WebHookTransmitter
c['status'].append(WebHookTransmitter('http://www.postbin.org/xxxxxxx'))
Alternatively, you may provide a list of URLs and each one will
receive information on every event.
The following optional parameters influence when and what data is
transmitted:
categories: If provided, only events belonging to one of the
categories listed will be transmitted.
extra_params: Additional parameters to be supplied with every request.
"""

agent = 'buildbot webhook'

def __init__(self, url, categories=None, extra_params={}):
status.base.StatusReceiverMultiService.__init__(self)
if isinstance(url, basestring):
self.urls = [url]
else:
self.urls = url
self.categories = categories
self.extra_params = extra_params

def _transmit(self, event, params={}):

cat = dict(params).get('category', None)
if (cat and self.categories) and cat not in self.categories:
log.msg("Ignoring request for unhandled category: %s" % cat)
return

new_params = [('event', event)]
new_params.extend(list(self.extra_params.items()))
if hasattr(params, "items"):
new_params.extend(params.items())
else:
new_params.extend(params)
encoded_params = urllib.urlencode(new_params)

def _trap_status(x, *acceptable):
x.trap(error.Error)
if int(x.value.status) in acceptable:
return None
else:
return x

log.msg("WebHookTransmitter announcing a %s event" % event)
for u in self.urls:
d = client.getPage(u, method='POST', agent=self.agent,
postdata=encoded_params, followRedirect=0)
d.addErrback(lambda x: x.trap(error.PageRedirect))
d.addErrback(_trap_status, 204)
d.addCallback(lambda x: log.msg("Completed %s event hook" % event))
d.addErrback(log.err)

def builderAdded(self, builderName, builder):
builder.subscribe(self)
self._transmit('builderAdded',
{'builder': builderName,
'category': builder.getCategory()})

def builderRemoved(self, builderName, builder):
self._transmit('builderRemoved',
{'builder': builderName,
'category': builder.getCategory()})

def buildStarted(self, builderName, build):
build.subscribe(self)

args = {'builder': builderName,
'category': build.getBuilder().getCategory(),
'reason': build.getReason(),
'revision': build.getSourceStamp().revision,
'buildNumber': build.getNumber()}

if build.getSourceStamp().patch:
args['patch'] = build.getSourceStamp().patch[1]

self._transmit('buildStarted', args)

def buildFinished(self, builderName, build, results):
self._transmit('buildFinished',
{'builder': builderName,
'category': build.getBuilder().getCategory(),
'result': status.builder.Results[results],
'revision': build.getSourceStamp().revision,
'had_patch': bool(build.getSourceStamp().patch),
'buildNumber': build.getNumber()})

def stepStarted(self, build, step):
step.subscribe(self)
self._transmit('stepStarted',
[('builder', build.getBuilder().getName()),
('category', build.getBuilder().getCategory()),
('buildNumber', build.getNumber()),
('step', step.getName())])

def stepFinished(self, build, step, results):
gu = self.status.getURLForThing
self._transmit('stepFinished',
[('builder', build.getBuilder().getName()),
('category', build.getBuilder().getCategory()),
('buildNumber', build.getNumber()),
('resultStatus', status.builder.Results[results[0]]),
('resultString', ' '.join(results[1])),
('step', step.getName())]
+ [('logFile', gu(l)) for l in step.getLogs()])

def _subscribe(self):
self.status.subscribe(self)

def setServiceParent(self, parent):
status.base.StatusReceiverMultiService.setServiceParent(self, parent)
self.status = parent.getStatus()

self._transmit('startup')

self._subscribe()

0 comments on commit 9b4c509

Please sign in to comment.