Skip to content

Commit

Permalink
Merge pull request #1335 from delanne/IRCContact
Browse files Browse the repository at this point in the history
IRCContact use the DATA API
  • Loading branch information
Mikhail Sobolev committed Nov 8, 2014
2 parents 6c4d702 + 1283cf0 commit 3b8608e
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 131 deletions.
163 changes: 75 additions & 88 deletions master/buildbot/status/words.py
Expand Up @@ -44,6 +44,7 @@
from buildbot.status.results import SUCCESS
from buildbot.status.results import WARNINGS


# twisted.internet.ssl requires PyOpenSSL, so be resilient if it's missing
try:
from twisted.internet import ssl
Expand Down Expand Up @@ -184,6 +185,9 @@ def doSilly(self, message):
reactor.callLater(when, self.send, r)
when += 2.5

def builderMatchesAnyTag(self, builder_tags):
return any(tag for tag in builder_tags if tag in self.bot.tags)

@defer.inlineCallbacks
def getBuilder(self, buildername=None, builderid=None):
if buildername:
Expand All @@ -206,6 +210,9 @@ def getBuilder(self, buildername=None, builderid=None):
raise UsageError("no such builder '%s'" % which)
defer.returnValue(bdict)

def getPreviousBuild(self, build):
return self.master.data.get(('builders', build['builderid'], 'builds', build['number'] - 1))

def getControl(self, which):
# TODO in nine: there's going to be a better way to do all this.
# For now, this continues to work.
Expand Down Expand Up @@ -332,17 +339,20 @@ def notify_for(self, *events):
return True
return False

@defer.inlineCallbacks
def subscribe_to_build_events(self):
startConsuming = self.master.mq.startConsuming

def buildStarted(key, msg):
return self.buildStarted(msg)

# FIXME:
# -- builderAdded
# -- builderRemoved
# -- builderStarted
# -- buildFinished
def buildFinished(key, msg):
return self.buildFinished(msg)

handle = True # self.master.data.startConsuming(watchForCompleteEvent, {},
# (build['link'].path))
self.subscribed.append(handle)
for e, f in (("new", buildStarted), # BuilderStarted
("finished", buildFinished)): # BuilderFinished
handle = yield startConsuming(f, ('builders', None, 'builds', None, e))
self.subscribed.append(handle)

def unsubscribe_from_build_events(self):
# Cancel all the subscriptions we have
Expand Down Expand Up @@ -462,32 +472,16 @@ def watchForCompleteEvent(key, msg):
self.send(r)
command_WATCH.usage = "watch <which> - announce the completion of an active build"

# OLD_STYLE
def builderAdded(self, builderName, builder):
# FIXME: NEED TO THINK ABOUT!
if (self.bot.tags is not None and
not builder.matchesAnyTag(tags=self.bot.tags)):
return

log.msg('[Contact] Builder %s added' % (builderName))
builder.subscribe(self)

# OLD_STYLE
def builderRemoved(self, builderName):
# FIXME: NEED TO THINK ABOUT!
log.msg('[Contact] Builder %s removed' % (builderName))

# OLD_STYLE
@defer.inlineCallbacks
def buildStarted(self, builderName, build):
# FIXME: NEED TO THINK ABOUT!
builder = build.getBuilder()
log.msg('[Contact] Builder %r started' % (builder,))
def buildStarted(self, build):
builder = yield self.getBuilder(builderid=build['builderid'])
builderName = builder['name']
buildNumber = build['number']
log.msg('[Contact] Builder %s started' % (builder['name'],))

# only notify about builders we are interested in

if (self.bot.tags is not None and
not builder.matchesAnyTag(tags=self.bot.tags)):
not self.builderMatchesAnyTag(builder.get('tags', []))):
log.msg('Not notifying for a build that does not match any tags')
return

Expand All @@ -497,96 +491,86 @@ def buildStarted(self, builderName, build):
if self.useRevisions:
revisions = yield self.getRevisionsForBuild(build)
r = "build containing revision(s) [%s] on %s started" % \
(','.join(revisions), builder.getName())
(','.join(revisions), builderName)
else:
# Abbreviate long lists of changes to simply two
# revisions, and the number of additional changes.
changes = [str(c.revision) for c in build.getChanges()][:2]
# TODO: We can't get the list of the changes related to a build in nine
changes_str = ""

if len(build.getChanges()) > 0:
changes_str = "including [%s]" % ', '.join(changes)

if len(build.getChanges()) > 2:
# Append number of truncated changes
changes_str += " and %d more" % (len(build.getChanges()) - 2)

r = "build #%d of %s started" % (
build.getNumber(),
builder.getName())

r = "build #%d of %s started" % (buildNumber, builderName)
if changes_str:
r += " (%s)" % changes_str

self.send(r)

results_descriptions = {
SUCCESS: ("Success", 'GREEN'),
WARNINGS: ("Warnings", 'YELLOW'),
FAILURE: ("Failure", 'RED'),
EXCEPTION: ("Exception", 'PURPLE'),
RETRY: ("Retry", 'AQUA_LIGHT'),
CANCELLED: ("Cancelled", 'PINK'),
}

def getResultsDescriptionAndColor(self, results):
return self.results_descriptions.get(results, ("??", 'RED'))

# OLD_STYLE
def buildFinished(self, builderName, build, results):
# FIXME: NEED TO THINK ABOUT!
builder = build.getBuilder()
@defer.inlineCallbacks
def buildFinished(self, build):
builder = yield self.getBuilder(builderid=build['builderid'])
builderName = builder['name']
buildNumber = build['number']
buildResult = build['results']

# only notify about builders we are interested in
if (self.bot.tags is not None and
not builder.matchesAnyTag(tags=self.bot.tags)):
not self.builderMatchesAnyTag(builder.get('tags', []))):
log.msg('Not notifying for a build that does not match any tags')
return

if not self.notify_for_finished(build):
return

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

results = self.getResultsDescriptionAndColor(build.getResults())
if not self.shouldReportBuild(builder_name, buildnum):
if not self.shouldReportBuild(builderName, buildNumber):
return

bdict = None # ???
results = self.getResultsDescriptionAndColor(buildResult)

if self.useRevisions:
revisions = yield self.getRevisionsForBuild(bdict)
r = "build containing revision(s) [%s] on %s is complete: %s" % \
(','.join(revisions), builder_name, results[0])
revisions = yield self.getRevisionsForBuild(build)
r = "Hey! build %s containing revision(s) [%s] is complete: %s" % \
(builderName, ','.join(revisions), results[0])
else:
r = "build #%d of %s is complete: %s" % \
(buildnum, builder_name, results[0])
r = "Hey! build %s #%d is complete: %s" % \
(builderName, buildNumber, results[0])

r += ' [%s]' % maybeColorize(" ".join(build.getText()), results[1], self.useColors)
buildurl = self.bot.status.getURLForThing(build)
r += ' [%s]' % maybeColorize(build['state_string'], results[1], self.useColors)
self.send(r)

# FIXME: where do we get the list of changes for a build ?
# if self.bot.showBlameList and buildResult != SUCCESS and len(build.changes) != 0:
# r += ' blamelist: ' + ', '.join(list(set([c.who for c in build.changes])))

# FIXME: where do we get the base_url? Then do we use the build Link to make the URL?
buildurl = None # self.bot.status.getBuildbotURL() + build
if buildurl:
r += " Build details are at %s" % buildurl
self.send("Build details are at %s" % buildurl)

if self.bot.showBlameList and build.getResults() != SUCCESS and len(build.changes) != 0:
r += ' blamelist: ' + ', '.join(list(set([c.who for c in build.changes])))
results_descriptions = {
SUCCESS: ("Success", 'GREEN'),
WARNINGS: ("Warnings", 'YELLOW'),
FAILURE: ("Failure", 'RED'),
EXCEPTION: ("Exception", 'PURPLE'),
RETRY: ("Retry", 'AQUA_LIGHT'),
CANCELLED: ("Cancelled", 'PINK'),
}

self.send(r)
def getResultsDescriptionAndColor(self, results):
return self.results_descriptions.get(results, ("??", 'RED'))

def notify_for_finished(self, build):
# FIXME: NEED TO THINK ABOUT!
results = build.getResults()

if self.notify_for('finished'):
return True

if self.notify_for(lower(self.results_descriptions.get(results)[0])):
if self.notify_for(lower(self.results_descriptions.get(build['results'])[0])):
return True

prevBuild = build.getPreviousBuild()
prevBuild = self.getPreviousBuild(build)
if prevBuild:
prevResult = prevBuild.getResults()
prevResult = prevBuild['results']

required_notification_control_string = join((lower(self.results_descriptions.get(prevResult)[0]),
'To',
capitalize(self.results_descriptions.get(results)[0])),
capitalize(self.results_descriptions.get(build['results'])[0])),
'')

if (self.notify_for(required_notification_control_string)):
Expand All @@ -598,11 +582,11 @@ def notify_for_finished(self, build):
def watchedBuildFinished(self, build):
builder = yield self.getBuilder(builderid=build['builderid'])

# FIXME: NEED TO THINK ABOUT!
# only notify about builders we are interested in
# if (self.bot.tags is not None and
# not builder.matchesAnyTag(tags=self.bot.tags)):
# return
if (self.bot.tags is not None and
not self.builderMatchesAnyTag(builder.get('tags', []))):
log.msg('Not notifying for a build that does not match any tags')
return

builder_name = builder['name']
buildnum = build['number']
Expand Down Expand Up @@ -1158,6 +1142,9 @@ def __init__(self, nickname, password, channels, pm_to_nicks, tags, notify_event
self.useColors = useColors
self.allowShutdown = allowShutdown

if categories:
log.msg("WARNING: categories are deprecated and should be replaced with 'tags=[cat]'")

def __getstate__(self):
d = self.__dict__.copy()
del d['p']
Expand Down
49 changes: 6 additions & 43 deletions master/buildbot/test/unit/test_status_words.py
Expand Up @@ -442,6 +442,7 @@ def test_command_watch_builder0(self):
@defer.inlineCallbacks
def test_command_watch_builder0_get_notifications(self):
# (continue from the prior test)
self.bot.tags = None
yield self.test_command_watch_builder0()
del self.sent[:]

Expand Down Expand Up @@ -639,58 +640,20 @@ def test_unclosed_quote(self):
yield self.do_test_command('last', args='args\'', exp_UsageError=True)
yield self.do_test_command('help', args='args\'', exp_UsageError=True)

@defer.inlineCallbacks
def test_buildStarted(self):
class MockChange(object):

def __init__(self, revision):
self.revision = revision

def get_name():
return "dummy"

self.setupSomeBuilds()
self.patch_send()

build = mock.Mock()
build.getNumber = lambda: 42
build.getName = get_name

builder = mock.Mock()
builder.getName = get_name
build.getBuilder = lambda: builder
build = yield self.master.db.builds.getBuild(13)

self.bot.tags = None
self.contact.notify_for = lambda _: True
self.contact.useRevisions = False

# we have no information on included changes
build.getChanges = lambda: []
self.contact.buildStarted("dummy", build)
self.assertEqual(
self.sent.pop(),
"build #42 of dummy started")

# we have one change included
build.getChanges = lambda: [MockChange("1")]
self.contact.buildStarted("dummy", build)
self.assertEqual(
self.sent.pop(),
"build #42 of dummy started (including [1])")

# we have two changes included (all revisions are printed)
build.getChanges = lambda: [MockChange("1"), MockChange("2")]
self.contact.buildStarted("dummy", build)
self.assertEqual(
self.sent.pop(),
"build #42 of dummy started (including [1, 2])")

# we have three changes included (not all revisions are printed)
build.getChanges = lambda: [
MockChange("1"), MockChange("2"), MockChange("3")
]
self.contact.buildStarted("dummy", build)
self.contact.buildStarted(build)
self.assertEqual(
self.sent.pop(),
"build #42 of dummy started (including [1, 2] and 1 more)")
"build #3 of builder1 started")


class FakeContact(object):
Expand Down

0 comments on commit 3b8608e

Please sign in to comment.