Adding a buildNumber variable and changed the text.
2 # Derived from code from the status/mail.py in buildbot 0.7.9
3 # Needs python-twitter installed to function.
7 from zope.interface import implements
8 from twisted.internet import defer, threads
9 from twisted.mail.smtp import sendmail
10 from twisted.python import log as twlog
12 from buildbot import interfaces, util
13 from buildbot.status import base
14 from buildbot.status.builder import FAILURE, SUCCESS, WARNINGS
16 class TwitterNotifier(base.StatusReceiverMultiService):
18 compare_attrs = ["twitname", "twitpass", "mode", "categories", "builders",
21 def __init__(self, twitname, twitpass, mode="all", categories=None, builders=None,
22 message="%(buildSlave)s reported build %(buildNumber)s as a %(result)s %(buildUrl)s"):
25 @param twitname: The twitter user
27 @param twitpass: The twitter user's password.
28 @type mode: string (defaults to all)
30 - 'all': send mail about all builds, passing and failing
31 - 'failing': only send mail about builds which fail
32 - 'passing': only send mail about builds which succeed
33 - 'problem': only send mail about a build which failed
34 when the previous build passed
37 @param message: a string to be used as the subject line of the message.
38 - %(buildSlave)s will be replaced with the name of the slave doing the building.
39 - %(projectName)s with the name of the project
40 - %(result)s will be the result of the build
41 - %(buildUrl)s will be the url with the details of the build.
42 - %(revision)s The revision of the change.
44 @type categories: list of strings
45 @param categories: a list of category names to serve status
46 information for. Defaults to None (all
47 categories). Use either builders or categories,
49 builder which provoked the message.
51 @type builders: list of strings
52 @param builders: a list of builder names for which mail should be
53 sent. Defaults to None (send mail for all builds).
54 Use either builders or categories, but not both.
57 base.StatusReceiverMultiService.__init__(self)
58 self.twitname = twitname
59 self.twitpass = twitpass
60 assert mode in ('all', 'failing', 'problem')
62 self.message = message
63 self.categories = categories
64 self.builders = builders
68 # you should either limit on builders or categories, not both
69 if self.builders != None and self.categories != None:
70 twlog.err("Please specify only builders to ignore or categories to include")
71 raise # FIXME: the asserts above do not raise some Exception either
73 def setServiceParent(self, parent):
75 @type parent: L{buildbot.master.BuildMaster}
77 base.StatusReceiverMultiService.setServiceParent(self, parent)
81 self.status = self.parent.getStatus()
82 self.status.subscribe(self)
84 def disownServiceParent(self):
85 self.status.unsubscribe(self)
86 for w in self.watched:
88 return base.StatusReceiverMultiService.disownServiceParent(self)
90 def builderAdded(self, name, builder):
91 # only subscribe to builders we are interested in
92 if self.categories != None and builder.category not in self.categories:
95 self.watched.append(builder)
96 return self # subscribe to this builder
98 def builderRemoved(self, name):
101 def builderChangedState(self, name, state):
103 def buildStarted(self, name, build):
105 def buildFinished(self, name, build, results):
106 # here is where we actually do something.
107 builder = build.getBuilder()
108 if self.builders is not None and name not in self.builders:
109 return # ignore this build
110 if self.categories is not None and \
111 builder.category not in self.categories:
112 return # ignore this build
114 if self.mode == "failing" and results != FAILURE:
116 if self.mode == "passing" and results != SUCCESS:
118 if self.mode == "problem":
119 if results != FAILURE:
121 prev = build.getPreviousBuild()
122 if prev and prev.getResults() == FAILURE:
124 # for testing purposes, buildMessage returns a Deferred that fires
125 # when the mail has been sent. To help unit tests, we return that
126 # Deferred here even though the normal IStatusReceiver.buildFinished
127 # signature doesn't do anything with it. If that changes (if
128 # .buildFinished's return value becomes significant), we need to
130 return self.buildMessage(name, build, results)
132 def buildMessage(self, name, build, results):
133 projectName = self.status.getProjectName()
134 buildSlave = build.getSlavename()
135 buildUrl = self.status.getURLForThing(build)
136 buildNumber = build.getNumber()
138 ss = build.getSourceStamp()
140 revision = "unavailable"
144 source += ss.revision
148 if results == SUCCESS:
150 elif results == WARNINGS:
155 text = self.message % {
156 'projectName': projectName,
157 'buildSlave': buildSlave,
159 'revision': revision,
160 'buildUrl': buildUrl,
161 'buildNumber' : buildNumber,
164 d = threads.deferToThread(_sendTwitter, self.twitname, self.twitpass,
168 def _sendTwitter(twitname, twitpass, text):
169 api = twitter.Api(twitname, twitpass)