From b6d40c64b215ccecaa4083fc9bc673600a819765 Mon Sep 17 00:00:00 2001 From: "catlee%mozilla.com" Date: Fri, 23 Jan 2009 13:53:48 +0000 Subject: [PATCH] Bug 474343 - Upgrading staging talos to buildbot 0.7.9 r=anodelman git-svn-id: svn://10.0.0.236/trunk@255903 18797224-902f-48f8-a5cc-f745e15eee43 --- .../testing/talos/perf-staging/ftppoller.py | 167 ++++ .../testing/talos/perf-staging/master.cfg | 142 ++-- .../testing/talos/perf-staging/perfrunner.py | 715 ++++++++++++++++++ .../perf-staging/scripts/count_and_reboot.py | 60 ++ .../scripts/generate-tpcomponent.py | 83 ++ .../talos/perf-staging/scripts/installdmg.ex | 49 ++ .../talos/perf-staging/scripts/installdmg.sh | 6 + .../perf-staging/tinderboxmailnotifier.py | 13 + 8 files changed, 1168 insertions(+), 67 deletions(-) create mode 100644 mozilla/tools/buildbot-configs/testing/talos/perf-staging/ftppoller.py create mode 100644 mozilla/tools/buildbot-configs/testing/talos/perf-staging/perfrunner.py create mode 100644 mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/count_and_reboot.py create mode 100644 mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/generate-tpcomponent.py create mode 100755 mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/installdmg.ex create mode 100644 mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/installdmg.sh create mode 100644 mozilla/tools/buildbot-configs/testing/talos/perf-staging/tinderboxmailnotifier.py diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/ftppoller.py b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/ftppoller.py new file mode 100644 index 00000000000..5ec92447a73 --- /dev/null +++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/ftppoller.py @@ -0,0 +1,167 @@ +import time +import re + +from urllib2 import urlopen, unquote +from twisted.python import log, failure +from twisted.internet import defer, reactor +from twisted.internet.task import LoopingCall + +from buildbot.changes import base, changes + +class InvalidResultError(Exception): + def __init__(self, value="InvalidResultError"): + self.value = value + def __str__(self): + return repr(self.value) + +class EmptyResult(Exception): + pass + +class FtpParser: + """I parse the web page for possible builds to test""" + findBuildDirs = re.compile('^.*"(\d{10})\/".*$') + + def __init__(self, query, searchString): + url = query.geturl() + pageContents = query.read() + query.close() + self.dirs = [] + self.dates = [] + lines = pageContents.split('\n') + #for parsing lists of directories + for line in lines: + if line == "": continue + match = re.match(self.findBuildDirs, line) + if match: + self.dirs.append(match.group(1)) + #for parsing lists of files + findLastDate = re.compile('^.*"([^"]*' + searchString + ')".*(\d\d-[a-zA-Z]{3}-\d\d\d\d \d\d:\d\d).*$') + for line in lines: + match = re.match(findLastDate, line) + if match: + self.dates.append([match.group(1), url + match.group(1), time.mktime(time.strptime(match.group(2), "%d-%b-%Y %H:%M"))]) + + def getDirs(self): + return self.dirs + + def getDates(self): + return self.dates + + +class FtpPoller(base.ChangeSource): + """This source will poll an ftp directory for changes and submit + them to the change master.""" + + compare_attrs = ["ftpURLs", "pollInterval", "tree", "branch"] + + parent = None # filled in when we're added + loop = None + volatile = ['loop'] + working = 0 + + def __init__(self, branch="", tree="Firefox", pollInterval=30, ftpURLs=[], searchString=""): + """ + @type ftpURLs: list of strings + @param ftpURLs: The ftp directories to monitor + + @type tree: string + @param tree: The tree to look for changes in. + For example, Firefox trunk is 'Firefox' + @type branch: string + @param branch: The branch to look for changes in. This must + match the 'branch' option for the Scheduler. + @type pollInterval: int + @param pollInterval: The time (in seconds) between queries for + changes + @type searchString: string + @param searchString: file type of the build we are looking for + """ + + self.ftpURLs = ftpURLs + self.tree = tree + self.branch = branch + self.pollInterval = pollInterval + self.lastChanges = {} + for url in self.ftpURLs: + self.lastChanges[url] = time.time() - 3600 + self.searchString = searchString + + def startService(self): + self.loop = LoopingCall(self.poll) + base.ChangeSource.startService(self) + + reactor.callLater(0, self.loop.start, self.pollInterval) + + def stopService(self): + self.loop.stop() + return base.ChangeSource.stopService(self) + + def describe(self): + str = "" + str += "Getting changes from ftp directory %s " \ + % str(self.ftpURLs) + str += "
Using tree: %s, branch %s" % (self.tree, self.branch) + return str + + def poll(self): + if self.working > 0: + log.msg("Not polling Tinderbox because last poll is still working (%s)" % (str(self.working))) + else: + for url in self.ftpURLs: + self.working = self.working + 1 + d = self._get_changes(url) + d.addCallback(self._process_changes, 0) + d.addBoth(self._finished) + return + + def _finished(self, res): + self.working = self.working - 1 + + def _get_changes(self, url): + log.msg("Polling ftp dir %s" % url) + return defer.maybeDeferred(urlopen, url) + + def _process_changes(self, query, forceDate): + + try: + url = query.geturl() + parser = FtpParser(query, self.searchString) + dirList = parser.getDirs() + dateList = parser.getDates() + except InvalidResultError, e: + log.msg("Could not process Tinderbox query: " + e.value) + return + except EmptyResult: + return + + + #figure out if there is a new directory that needs searching + for dir in dirList: + buildDate = int(dir) + if self.lastChanges[url] >= buildDate: + # change too old + continue + self.lastChanges[url] = buildDate + self.working = self.working + 1 + d = self._get_changes(url + dir + '/') + d.addBoth(self._process_changes, buildDate) + d.addBoth(self._finished) + + #if we have a new browser to test, test it + for buildname, fullpath, buildDate in dateList: + if (url in self.lastChanges): + if (self.lastChanges[url] >= buildDate): + # change too old + continue + if forceDate > 0: + buildDate = forceDate + else: + self.lastChanges[url] = buildDate + c = changes.Change(who = url, + comments = "success", + files = [buildname,], + branch = self.branch, + when = buildDate, + links = fullpath) + self.parent.addChange(c) + log.msg("found a browser to test (%s)" % (fullpath)) diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/master.cfg b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/master.cfg index 3030c9cebb3..f95f5a14b25 100644 --- a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/master.cfg +++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/master.cfg @@ -8,6 +8,7 @@ import os.path # from buildbot.changes.freshcvs import FreshCVSSource +from buildbot.buildslave import BuildSlave from buildbot.process import factory from buildbot.scheduler import Scheduler, Periodic from buildbot.status import html @@ -49,22 +50,24 @@ c['slavePortnum'] = 9987 ## Slaves ## -c['bots'] = [("qm-pubuntu-stage01", "l1nux"), - ("qm-ptiger-stage01", "mac1nt0sh"), - ("qm-pxp-stage01", "w1nd3rs"), - ("qm-pvista-stage01", "w1nd3rs"), - ("qm-pleopard-stage01", "mac1nt0sh")] +c['slaves'] = [BuildSlave(name, password, max_builds=1) for (name, password) in [ + ("qm-pubuntu-stage01", "l1nux"), + ("qm-ptiger-stage01", "mac1nt0sh"), + ("qm-pxp-stage01", "w1nd3rs"), + ("qm-pvista-stage01", "w1nd3rs"), + ("qm-pleopard-stage01", "mac1nt0sh") + ]] ## ## Status ## c['status'] = [] -c['status'].append(html.Waterfall(http_port=2008, - css="/build/perf-staging/waterfall.css")) +c['status'].append(html.WebStatus(http_port=2008, allowForce=True)) from buildbot.status import tinderbox from buildbot.status.mail import MailNotifier +from tinderboxmailnotifier import TinderboxMailNotifier c['status'].append(MailNotifier( fromaddr="talos.buildbot@build.mozilla.org", @@ -80,16 +83,14 @@ c['status'].append(tinderbox.TinderboxMailNotifier( tree="MozillaTest", extraRecipients=["tinderbox-daemon@tinderbox.mozilla.org",], relayhost="smtp.mozilla.org", - builders=["Linux talos trunk stage", - "MacOSX Darwin 8.8.1 talos trunk stage", - "MacOSX Darwin 9.0.0 talos trunk stage", - "WINNT 5.1 talos trunk stage", - "WINNT 6.0 talos trunk stage"], + builders=["Linux talos mozilla-central stage", + "MacOSX Darwin 8.8.1 talos mozilla-central stage", + "MacOSX Darwin 9.0.0 talos mozilla-central stage", + "WINNT 5.1 talos mozilla-central stage", + "WINNT 6.0 talos mozilla-central stage"], # useChangeTime=True, logCompression="bzip2")) - - ## ## Sources ## @@ -98,9 +99,9 @@ import ftppoller reload(ftppoller) from ftppoller import FtpPoller -c['sources'] = [] +c['change_source'] = [] -c['sources'].append(FtpPoller( +c['change_source'].append(FtpPoller( tree = "Firefox", branch = "MOZ2-WIN32-CENTRAL", pollInterval = 2 * 60, @@ -108,15 +109,15 @@ c['sources'].append(FtpPoller( searchString = WIN32_SEARCHSTRING) ) -c['sources'].append(FtpPoller( +c['change_source'].append(FtpPoller( tree = "Firefox", branch = "MOZ2-LINUX-CENTRAL", pollInterval = 2 * 60, ftpURLs = LINUX_MOZ2_CENTRAL_BUILDDIRS, searchString = LINUX_SEARCHSTRING) ) - -c['sources'].append(FtpPoller( + +c['change_source'].append(FtpPoller( tree = "Firefox", branch = "MOZ2-MAC-CENTRAL", pollInterval = 2 * 60, @@ -129,25 +130,23 @@ c['sources'].append(FtpPoller( c['schedulers'] = [] -## WINDOWS -c['schedulers'].append(Scheduler(name="head perfrun scheduler", - branch="HEAD", +#mozilla-central +c['schedulers'].append(Scheduler(name="moz2 central win32 scheduler", + branch="MOZ2-WIN32-CENTRAL", treeStableTimer=5*60, - builderNames=["WINNT 5.1 talos trunk stage", - "WINNT 6.0 talos trunk stage"] + builderNames=["WINNT 5.1 talos mozilla-central stage", + "WINNT 6.0 talos mozilla-central stage"] )) -## LINUX -c['schedulers'].append(Scheduler(name="head perfrun linux scheduler", - branch="HEAD_LINUX", +c['schedulers'].append(Scheduler(name="moz2 central perfrun linux scheduler", + branch="MOZ2-LINUX-CENTRAL", treeStableTimer=5*60, - builderNames=["Linux talos trunk stage"] + builderNames=["Linux talos mozilla-central stage"] )) -## MAC -c['schedulers'].append(Scheduler(name="head perfrun scheduler mac", - branch="HEAD-MAC", +c['schedulers'].append(Scheduler(name="moz2 central perfrun mac scheduler", + branch="MOZ2-MAC-CENTRAL", treeStableTimer=5*60, - builderNames=["MacOSX Darwin 8.8.1 talos trunk stage", - "MacOSX Darwin 9.0.0 talos trunk stage"] + builderNames=["MacOSX Darwin 8.8.1 talos mozilla-central stage", + "MacOSX Darwin 9.0.0 talos mozilla-central stage"] )) # the 'builders' list defines the Builders. Each one is configured with a @@ -161,87 +160,96 @@ c['schedulers'].append(Scheduler(name="head perfrun scheduler mac", #STAGING MACHINES graphConfig = ['--resultsServer', 'graphs-stage.mozilla.org', '--resultsLink', '/server/bulk.cgi'] - -stageConfig = graphConfig + ['--activeTests', 'ts:tsspider:twinopen'] +stageConfig = graphConfig + ['--activeTests', 'tdhtml:ts:tsspider:tp'] +nochromeConfig = graphConfig + ['--activeTests', 'tdhtml:ts:tsspider', '--noChrome'] + +basicConfig = 'configs/production.sample.config' +branchConfig = 'configs/production.sample.config.nogfx' +#nochromeConfig = 'configs/production.sample.config.nochrome' +fastConfig = 'configs/fast.production.sample.config' +fastManifest = 'configs/historic_manifest.txt' +jssConfig = 'configs/jss.production.sample.config' basicTalosCmd = ['python', 'run_tests.py', '--noisy'] -win32_trunk_stage_steps = TalosFactory(OS = 'win', + +win32_moz2_stage_steps = TalosFactory(OS = 'win', envName='vc8perf', - buildBranch="1.9", + buildBranch="moz-central-stage", configOptions=stageConfig, buildPath="..\\firefox\\firefox.exe", talosCmd=basicTalosCmd) -vista_trunk_stage_steps = TalosFactory(OS = 'win', +vista_moz2_stage_steps = TalosFactory(OS = 'win', envName='vc8perf', - buildBranch="1.9", + buildBranch="moz-central-stage", configOptions=stageConfig, buildPath="..\\firefox\\firefox.exe", talosCmd=basicTalosCmd) -linux_trunk_stage_steps = TalosFactory(OS = 'linux', +linux_moz2_stage_steps = TalosFactory(OS = 'linux', envName='linux', - buildBranch="1.9", + buildBranch="moz-central-stage", configOptions=stageConfig, buildPath="../firefox/firefox", talosCmd=basicTalosCmd) -mac_trunk_stage_steps = TalosFactory(OS = 'tiger', +mac_moz2_stage_steps = TalosFactory(OS = 'tiger', envName='mac', - buildBranch="1.9", + buildBranch="moz-central-stage", configOptions=stageConfig, - buildPath="../GranParadiso.app/Contents/MacOS/firefox", + buildPath="../Minefield.app/Contents/MacOS/firefox", talosCmd=basicTalosCmd) -leopard_trunk_stage_steps = TalosFactory(OS = 'leopard', +leopard_moz2_stage_steps = TalosFactory(OS = 'leopard', envName='mac', - buildBranch="1.9", + buildBranch="moz-central-stage", configOptions=stageConfig, - buildPath="../GranParadiso.app/Contents/MacOS/firefox", + buildPath="../Minefield.app/Contents/MacOS/firefox", talosCmd=basicTalosCmd) + #STAGING -win32_trunk_stage_builder = { - 'name': "WINNT 5.1 talos trunk stage", +win32_moz2_stage_builder = { + 'name': "WINNT 5.1 talos mozilla-central stage", 'slavenames': ['qm-pxp-stage01'], 'builddir': "win32-trunk", - 'factory': win32_trunk_stage_steps, + 'factory': win32_moz2_stage_steps, 'category': "Firefox Trunk" } -vista_trunk_stage_builder = { - 'name': "WINNT 6.0 talos trunk stage", +vista_moz2_stage_builder = { + 'name': "WINNT 6.0 talos mozilla-central stage", 'slavenames': ['qm-pvista-stage01'], 'builddir': "vista-trunk", - 'factory': vista_trunk_stage_steps, + 'factory': vista_moz2_stage_steps, 'category': "Firefox Trunk" } -linux_trunk_stage_builder = { - 'name': "Linux talos trunk stage", +linux_moz2_stage_builder = { + 'name': "Linux talos mozilla-central stage", 'slavenames': ['qm-pubuntu-stage01'], 'builddir': "linux-trunk", - 'factory': linux_trunk_stage_steps, + 'factory': linux_moz2_stage_steps, 'category': "Firefox Trunk" } -mac_trunk_stage_builder = { - 'name': "MacOSX Darwin 8.8.1 talos trunk stage", +mac_moz2_stage_builder = { + 'name': "MacOSX Darwin 8.8.1 talos mozilla-central stage", 'slavenames': ['qm-ptiger-stage01'], 'builddir': "mac-trunk", - 'factory': mac_trunk_stage_steps, + 'factory': mac_moz2_stage_steps, 'category': "Firefox Trunk" } -leopard_trunk_stage_builder = { - 'name': "MacOSX Darwin 9.0.0 talos trunk stage", +leopard_moz2_stage_builder = { + 'name': "MacOSX Darwin 9.0.0 talos mozilla-central stage", 'slavenames': ['qm-pleopard-stage01'], 'builddir': "leopard-trunk", - 'factory': leopard_trunk_stage_steps, + 'factory': leopard_moz2_stage_steps, 'category': "Firefox Trunk" } c['builders'] = [] #STAGING -c['builders'].append(win32_trunk_stage_builder) -c['builders'].append(vista_trunk_stage_builder) -c['builders'].append(linux_trunk_stage_builder) -c['builders'].append(mac_trunk_stage_builder) -c['builders'].append(leopard_trunk_stage_builder) +c['builders'].append(win32_moz2_stage_builder) +c['builders'].append(vista_moz2_stage_builder) +c['builders'].append(linux_moz2_stage_builder) +c['builders'].append(mac_moz2_stage_builder) +c['builders'].append(leopard_moz2_stage_builder) diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/perfrunner.py b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/perfrunner.py new file mode 100644 index 00000000000..919879dadc3 --- /dev/null +++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/perfrunner.py @@ -0,0 +1,715 @@ +# -*- Python -*- + +from twisted.python import log +from buildbot import buildset +from buildbot.scheduler import Scheduler +from buildbot.process.buildstep import BuildStep +from buildbot.process.factory import BuildFactory +from buildbot.buildset import BuildSet +from buildbot.sourcestamp import SourceStamp +from buildbot.steps.shell import ShellCommand +from buildbot.steps.transfer import FileDownload +from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, SKIPPED, EXCEPTION +import re, urllib, sys, os +from time import strptime, strftime, localtime +from datetime import datetime +from os import path +import copy + +MozillaEnvironments = { } + +# platform SDK location. we can build both from one generic template. +# modified from vc8 environment +MozillaEnvironments['vc8perf'] = { + "MOZ_CRASHREPORTER_NO_REPORT": '1', + "MOZ_NO_REMOTE": '1', + "NO_EM_RESTART": '1', + "XPCOM_DEBUG_BREAK": 'warn', + "CYGWINBASE": 'C:\\cygwin', + "PATH": 'C:\\Python24;' + \ + 'C:\\Python24\\Scripts;' + \ + 'C:\\cygwin\\bin;' + \ + 'C:\\WINDOWS\\System32;' + \ + 'C:\\program files\\gnuwin32\\bin;' + \ + 'C:\\WINDOWS;' +} + +MozillaEnvironments['linux'] = { + "MOZ_CRASHREPORTER_NO_REPORT": '1', + "MOZ_NO_REMOTE": '1', + "NO_EM_RESTART": '1', + "XPCOM_DEBUG_BREAK": 'warn', + "DISPLAY": ":0", +} + +MozillaEnvironments['mac'] = { + "MOZ_NO_REMOTE": '1', + "NO_EM_RESTART": '1', + "XPCOM_DEBUG_BREAK": 'warn', + "MOZ_CRASHREPORTER_NO_REPORT": '1', + # for extracting dmg's + "PAGER": '/bin/cat', +} + +class MultiBuildScheduler(Scheduler): + """Trigger N (default three) build requests based upon the same change request""" + def __init__(self, numberOfBuildsToTrigger=3, **kwargs): + self.numberOfBuildsToTrigger = numberOfBuildsToTrigger + Scheduler.__init__(self, **kwargs) + + def fireTimer(self): + self.timer = None + self.nextBuildTime = None + changes = self.importantChanges + self.unimportantChanges + self.importantChanges = [] + self.unimportantChanges = [] + + # submit + for i in range(0, self.numberOfBuildsToTrigger): + ss = UnmergableSourceStamp(changes=changes) + bs = buildset.BuildSet(self.builderNames, ss) + self.submit(bs) + + +class LatestFileURL: + sortByDateString = "?C=M;O=A" + + def _retrievePageAtURL(self): + content = [] + try: + opener = urllib.URLopener() + page = opener.open(self.url + self.sortByDateString) + content = page.readlines() + opener.close() + except: + print "unable to retrieve page at: " + self.url + " dated: " + self.sortByDateString + return content + + def _populateDict(self): + '''Extract the latest filename from the given URL + * retrieve page at URL + * for each line + * grab filename URL + * if filename matches filenameSearchString + * grab datetime + * store date and filename URL in dictionary + * return latest filenameURL matching date''' + + reDatestamp = re.compile('\d\d-[a-zA-Z]{3,3}-\d\d\d\d \d\d:\d\d') + reHREF = re.compile('href\="((?:\w|[.-])*)"') + content = self._retrievePageAtURL() + for line in content: + matchHREF = re.search(reHREF, line) + if matchHREF: + if self.filenameSearchString in matchHREF.group(1): + datetimeMatch = re.search(reDatestamp, line) + if datetimeMatch: + dts = line[datetimeMatch.start():datetimeMatch.end()] + timestamp = datetime(*strptime(dts, '%d-%b-%Y %H:%M')[0:6]) + self.dateFileDict[timestamp] = matchHREF.group(1) + + + def _getDateKeys(self): + dbKeys = self.dateFileDict.keys() + if not dbKeys: + return [] + return dbKeys + + def getLatestFilename(self): + dateKeys = self._getDateKeys() + if not dateKeys: return "" + return self.dateFileDict[max(dateKeys)] + + def _printDictionary(self): + keys = self._getDateKeys() + for timestamp in keys: + print "%s : %s" % (timestamp, self.dateFileDict[timestamp]) + + def testrun(self): + self._populateDict() + self._printDictionary() + name = self.getLatestFilename() + print self.url + name + + def __init__(self, url, filenameSearchString): + self.url = url + self.filenameSearchString = filenameSearchString + self.dateFileDict = {} + self._populateDict() + +class MozillaWgetLatestDated(ShellCommand): + """Download built Firefox client from dated staging directory.""" + haltOnFailure = True + + def __init__(self, **kwargs): + self.branch = "HEAD" + if 'branch' in kwargs: + self.branch = kwargs['branch'] + if not 'command' in kwargs: + kwargs['command'] = ["wget"] + ShellCommand.__init__(self, **kwargs) + + def setBuild(self, build): + ShellCommand.setBuild(self, build) + self.changes = build.source.changes + #a full path is always provided by the poller + self.fileURL = self.changes[-1].links + self.filename = self.changes[-1].files[0] + + def getFilename(self): + return self.filename + + def describe(self, done=False): + return ["Wget Download"] + + def start(self): + #urlGetter = LatestFileURL(self.url, self.filenameSearchString) + #self.filename = urlGetter.getLatestFilename() + #self.fileURL = self.url + self.filename + if self.branch: + self.setProperty("fileURL", self.fileURL) + self.setProperty("filename", self.filename) + self.setCommand(["wget", "-nv", "-N", self.fileURL]) + ShellCommand.start(self) + + def evaluateCommand(self, cmd): + superResult = ShellCommand.evaluateCommand(self, cmd) + if SUCCESS != superResult: + return FAILURE + if None != re.search('ERROR', cmd.logs['stdio'].getText()): + return FAILURE + return SUCCESS + + +class MozillaWgetLatest(ShellCommand): + """Download built Firefox client from nightly staging directory.""" + haltOnFailure = True + + def __init__(self, **kwargs): + assert kwargs['url'] != "" + assert kwargs['filenameSearchString'] != "" + #if this change includes a link use it + if self.changes[-1].links: + self.url = self.changes[-1].links + else: + self.url = kwargs['url'] + self.filenameSearchString = kwargs['filenameSearchString'] + self.branch = "HEAD" + self.fileURL = "" + if 'branch' in kwargs: + self.branch = kwargs['branch'] + if not 'command' in kwargs: + kwargs['command'] = ["wget"] + ShellCommand.__init__(self, **kwargs) + + def getFilename(self): + return self.filename + + def describe(self, done=False): + return ["Wget Download"] + + def start(self): + urlGetter = LatestFileURL(self.url, self.filenameSearchString) + self.filename = urlGetter.getLatestFilename() + self.fileURL = self.url + self.filename + if self.branch: + self.setProperty("fileURL", self.fileURL) + self.setProperty("filename", self.filename) + self.setCommand(["wget", "-nv", "-N", self.fileURL]) + ShellCommand.start(self) + + def evaluateCommand(self, cmd): + superResult = ShellCommand.evaluateCommand(self, cmd) + if SUCCESS != superResult: + return FAILURE + if None != re.search('ERROR', cmd.logs['stdio'].getText()): + return FAILURE + return SUCCESS + + +class MozillaInstallZip(ShellCommand): + """Install given file, unzipping to executablePath""" + + def __init__(self, **kwargs): + self.filename = "" + self.branch = "" + if 'branch' in kwargs: + self.branch = kwargs['branch'] + if 'filename' in kwargs: + self.filename = kwargs['filename'] + if not 'command' in kwargs: + kwargs['command'] = ["unzip", "-o"] + ShellCommand.__init__(self, **kwargs) + + def describe(self, done=False): + return ["Install zip"] + + def start(self): + # removed the mkdir because this happens on the master, not the slave + if not self.filename: + if self.branch: + self.filename = self.getProperty("filename") + else: + return FAILURE + if self.filename: + self.command = self.command[:] + [self.filename] + ShellCommand.start(self) + + def evaluateCommand(self, cmd): + superResult = ShellCommand.evaluateCommand(self, cmd) + if SUCCESS != superResult: + return FAILURE + if None != re.search('ERROR', cmd.logs['stdio'].getText()): + return FAILURE + if None != re.search('Usage:', cmd.logs['stdio'].getText()): + return FAILURE + return SUCCESS + + +class MozillaUpdateConfig(ShellCommand): + """Configure YAML file for run_tests.py""" + + def __init__(self, **kwargs): + self.addOptions = [] + assert 'executablePath' in kwargs + assert 'branch' in kwargs + self.branch = kwargs['branch'] + self.exePath = kwargs['executablePath'] + if 'addOptions' in kwargs: + self.addOptions = kwargs['addOptions'] + ShellCommand.__init__(self, **kwargs) + + def setBuild(self, build): + ShellCommand.setBuild(self, build) + self.title = build.slavename + self.changes = build.source.changes + self.buildid = strftime("%Y%m%d%H%M", localtime(self.changes[-1].when)) + if not self.command: + self.setCommand(["python", "PerfConfigurator.py", "-v", "-e", self.exePath, "-t", self.title, "-b", self.branch, "-d", self.buildid] + self.addOptions) + + def describe(self, done=False): + return ["Update config"] + + def evaluateCommand(self, cmd): + superResult = ShellCommand.evaluateCommand(self, cmd) + if SUCCESS != superResult: + return FAILURE + stdioText = cmd.logs['stdio'].getText() + if None != re.search('ERROR', stdioText): + return FAILURE + if None != re.search('USAGE:', stdioText): + return FAILURE + configFileMatch = re.search('outputName\s*=\s*(\w*?.yml)', stdioText) + if not configFileMatch: + return FAILURE + else: + self.setProperty("configFile", configFileMatch.group(1)) + return SUCCESS + + +class MozillaRunPerfTests(ShellCommand): + """Run the performance tests""" + + def __init__(self, **kwargs): + if 'branch' in kwargs: + self.branch = kwargs['branch'] + if not 'command' in kwargs: + kwargs['command'] = ["python", "run_tests.py"] + ShellCommand.__init__(self, **kwargs) + + def describe(self, done=False): + return ["Run performance tests"] + + def createSummary(self, log): + summary = [] + for line in log.readlines(): + if "RETURN:" in line: + summary.append(line.replace("RETURN:", "TinderboxPrint:")) + if "FAIL:" in line: + summary.append(line.replace("FAIL:", "TinderboxPrint:FAIL:")) + self.addCompleteLog('summary', "\n".join(summary)) + + def start(self): + """docstring for start""" + self.command = copy.copy(self.command) + self.command.append(self.getProperty("configFile")) + ShellCommand.start(self) + + def evaluateCommand(self, cmd): + superResult = ShellCommand.evaluateCommand(self, cmd) + stdioText = cmd.logs['stdio'].getText() + if SUCCESS != superResult: + return FAILURE + if None != re.search('ERROR', stdioText): + return FAILURE + if None != re.search('USAGE:', stdioText): + return FAILURE + if None != re.search('FAIL:', stdioText): + return WARNINGS + return SUCCESS + +class MozillaInstallTarBz2(ShellCommand): + """Install given file, unzipping to executablePath""" + + def __init__(self, **kwargs): + self.filename = "" + self.branch = "" + if 'branch' in kwargs: + self.branch = kwargs['branch'] + if 'filename' in kwargs: + self.filename = kwargs['filename'] + if not 'command' in kwargs: + kwargs['command'] = ["tar", "-jvxf"] + ShellCommand.__init__(self, **kwargs) + + def describe(self, done=False): + return ["Install tar.bz2"] + + def start(self): + if not self.filename: + if self.branch: + self.filename = self.getProperty("filename") + else: + return FAILURE + if self.filename: + self.command = self.command[:] + [self.filename] + ShellCommand.start(self) + + def evaluateCommand(self, cmd): + superResult = ShellCommand.evaluateCommand(self, cmd) + if SUCCESS != superResult: + return FAILURE + return SUCCESS + +class MozillaInstallTarGz(ShellCommand): + """Install given file, unzipping to executablePath""" + + def __init__(self, **kwargs): + self.filename = "" + self.branch = "" + if 'branch' in kwargs: + self.branch = kwargs['branch'] + if 'filename' in kwargs: + self.filename = kwargs['filename'] + if not 'command' in kwargs: + kwargs['command'] = ["tar", "-zvxf"] + ShellCommand.__init__(self, **kwargs) + + def describe(self, done=False): + return ["Install tar.gz"] + + def start(self): + if not self.filename: + if self.branch: + self.filename = self.getProperty("filename") + else: + return FAILURE + if self.filename: + self.command = self.command[:] + [self.filename] + ShellCommand.start(self) + + def evaluateCommand(self, cmd): + superResult = ShellCommand.evaluateCommand(self, cmd) + if SUCCESS != superResult: + return FAILURE + return SUCCESS + +class MozillaWgetFromChange(ShellCommand): + """Download built Firefox client from current change's filenames.""" + haltOnFailure = True + + def __init__(self, **kwargs): + self.branch = "HEAD" + self.fileURL = "" + self.filename = "" + self.filenameSearchString = "en-US.win32.zip" + if 'filenameSearchString' in kwargs: + self.filenameSearchString = kwargs['filenameSearchString'] + if 'url' in kwargs: + self.url = kwargs['url'] + else: + self.url = kwargs['build'].source.changes[-1].files[0] + if 'branch' in kwargs: + self.branch = kwargs['branch'] + if not 'command' in kwargs: + kwargs['command'] = ["wget"] + ShellCommand.__init__(self, **kwargs) + + def getFilename(self): + return self.filename + + def describe(self, done=False): + return ["Wget Download"] + + def start(self): + urlGetter = LatestFileURL(self.url, self.filenameSearchString) + self.filename = urlGetter.getLatestFilename() + self.fileURL = self.url + self.filename + if self.branch: + self.setProperty("fileURL", self.fileURL) + self.setProperty("filename", self.filename) + self.setCommand(["wget", "-nv", "-N", self.fileURL]) + ShellCommand.start(self) + + def evaluateCommand(self, cmd): + superResult = ShellCommand.evaluateCommand(self, cmd) + if SUCCESS != superResult: + return FAILURE + if None != re.search('ERROR', cmd.logs['stdio'].getText()): + return FAILURE + return SUCCESS + +class MozillaUpdateConfigFromChange(ShellCommand): + """Configure YAML file for run_tests.py""" + + def __init__(self, **kwargs): + self.title = "default" + self.branch = "" + self.currentDate = "" + if 'build' in kwargs: + self.title = kwargs['build'].slavename + self.changes = kwargs['build'].source.changes + self.buildid = self.changes[-1].comments.split(',')[0] + if 'branch' in kwargs: + self.branch = kwargs['branch'] + assert 'configPath' in kwargs + assert 'executablePath' in kwargs + self.configPath = kwargs['configPath'] + self.exePath = kwargs['executablePath'] + if not 'command' in kwargs: + kwargs['command'] = ["python", "PerfConfigurator.py", "-v", "-e", + self.exePath, "-c", self.configPath, + "-t", self.title, "-b", self.branch, + "-d", self.buildid] + ShellCommand.__init__(self, **kwargs) + + def describe(self, done=False): + return ["Update config"] + + def evaluateCommand(self, cmd): + superResult = ShellCommand.evaluateCommand(self, cmd) + if SUCCESS != superResult: + return FAILURE + stdioText = cmd.logs['stdio'].getText() + if None != re.search('ERROR', stdioText): + return FAILURE + if None != re.search('USAGE:', stdioText): + return FAILURE + configFileMatch = re.search('outputName\s*=\s*(\w*?.yml)', stdioText) + if not configFileMatch: + return FAILURE + else: + self.setProperty("configFile", configFileMatch.group(1)) + return SUCCESS + +class MozillaInstallDmg(ShellCommand): + """Install given file, copying to workdir""" + + def __init__(self, **kwargs): + self.filename = "" + self.branch = "" + if 'branch' in kwargs: + self.branch = kwargs['branch'] + if 'filename' in kwargs: + self.filename = kwargs['filename'] + if not 'command' in kwargs: + kwargs['command'] = ["bash", "installdmg.sh", "$FILENAME"] + ShellCommand.__init__(self, **kwargs) + + def describe(self, done=False): + return ["Install dmg"] + + def start(self): + if not self.filename: + if self.branch: + self.filename = self.getProperty("filename") + else: + return FAILURE + + for i in range(len(self.command)): + if self.command[i] == "$FILENAME": + self.command[i] = self.filename + ShellCommand.start(self) + + def evaluateCommand(self, cmd): + superResult = ShellCommand.evaluateCommand(self, cmd) + if SUCCESS != superResult: + return FAILURE + return SUCCESS + +class MozillaInstallDmgEx(ShellCommand): + """Install given file, copying to workdir""" + #This is a temporary class to test the new InstallDmg script without affecting the production mac machines + # if this works everything should be switched over the using it + + def __init__(self, **kwargs): + self.filename = "" + self.branch = "" + if 'branch' in kwargs: + self.branch = kwargs['branch'] + if 'filename' in kwargs: + self.filename = kwargs['filename'] + if not 'command' in kwargs: + kwargs['command'] = ["expect", "installdmg.ex", "$FILENAME"] + ShellCommand.__init__(self, **kwargs) + + def describe(self, done=False): + return ["Install dmg"] + + def start(self): + if not self.filename: + if self.branch: + self.filename = self.getProperty("filename") + else: + return FAILURE + + for i in range(len(self.command)): + if self.command[i] == "$FILENAME": + self.command[i] = self.filename + ShellCommand.start(self) + + def evaluateCommand(self, cmd): + superResult = ShellCommand.evaluateCommand(self, cmd) + if SUCCESS != superResult: + return FAILURE + return SUCCESS + +class TalosFactory(BuildFactory): + + winClean = ["touch temp.zip &", "rm", "-rf", "*.zip", "talos/", "firefox/"] + macClean = "rm -vrf *" + linuxClean = "rm -vrf *" + + def __init__(self, OS, envName, buildBranch, configOptions, buildPath, talosCmd, customManifest='', cvsRoot=":pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot"): + BuildFactory.__init__(self) + if OS in ('linux', 'linuxbranch',): + cleanCmd = self.linuxClean + elif OS in ('win',): + cleanCmd = self.winClean + else: + cleanCmd = self.macClean + self.addStep(ShellCommand( + workdir=".", + description="Cleanup", + command=cleanCmd, + env=MozillaEnvironments[envName])) +#self.addStep(ShellCommand, +# command=["cvs", "-d", cvsRoot, "co", "-d", "talos", +# "mozilla/testing/performance/talos"], +# workdir=".", +# description="checking out talos", +# haltOnFailure=True, +# flunkOnFailure=True, +# env=MozillaEnvironments[envName]) + self.addStep(FileDownload( + mastersrc="talos.zip", + slavedest="talos.zip", + workdir=".")) + self.addStep(FileDownload, + mastersrc="scripts/count_and_reboot.py", + slavedest="count_and_reboot.py", + workdir=".") + self.addStep(MozillaInstallZip( + workdir=".", + branch=buildBranch, + haltOnFailure=True, + env=MozillaEnvironments[envName], + filename="talos.zip")) + self.addStep(FileDownload( + mastersrc="scripts/generate-tpcomponent.py", + slavedest="generate-tpcomponent.py", + workdir="talos/page_load_test")) + if customManifest != '': + self.addStep(FileDownload( + mastersrc=customManifest, + slavedest="manifest.txt", + workdir="talos/page_load_test")) + self.addStep(ShellCommand( + command=["python", "generate-tpcomponent.py"], + workdir="talos/page_load_test", + description="setting up pageloader", + haltOnFailure=True, + flunkOnFailure=True, + env=MozillaEnvironments[envName])) + self.addStep(MozillaWgetLatestDated( + workdir=".", + branch=buildBranch, + env=MozillaEnvironments[envName])) + #install the browser, differs based upon platform + if OS == 'linux': + self.addStep(MozillaInstallTarBz2( + workdir=".", + branch=buildBranch, + haltOnFailure=True, + env=MozillaEnvironments[envName])) + elif OS == 'linuxbranch': #special case for old linux builds + self.addStep(MozillaInstallTarGz( + workdir=".", + branch=buildBranch, + haltOnFailure=True, + env=MozillaEnvironments[envName])) + elif OS == 'win': + self.addStep(MozillaInstallZip( + workdir=".", + branch="1.9", + haltOnFailure=True, + env=MozillaEnvironments[envName])) + self.addStep(ShellCommand( + workdir="firefox/", + flunkOnFailure=False, + warnOnFailure=False, + description="chmod files (see msys bug)", + command=["chmod", "-v", "-R", "a+x", "."], + env=MozillaEnvironments[envName])) + elif OS == 'tiger': + self.addStep(FileDownload( + mastersrc="scripts/installdmg.sh", + slavedest="installdmg.sh", + workdir=".")) + self.addStep(MozillaInstallDmg( + workdir=".", + branch=buildBranch, + haltOnFailure=True, + env=MozillaEnvironments[envName])) + else: #leopard + self.addStep(FileDownload( + mastersrc="scripts/installdmg.ex", + slavedest="installdmg.ex", + workdir=".")) + self.addStep(MozillaInstallDmgEx( + workdir=".", + branch=buildBranch, + haltOnFailure=True, + env=MozillaEnvironments[envName])) + self.addStep(MozillaUpdateConfig( + workdir="talos/", + branch=buildBranch, + haltOnFailure=True, + executablePath=buildPath, + addOptions=configOptions, + env=MozillaEnvironments[envName])) + self.addStep(MozillaRunPerfTests( + warnOnWarnings=True, + workdir="talos/", + branch=buildBranch, + timeout=21600, + haltOnFailure=True, + command=talosCmd, + env=MozillaEnvironments[envName])) + self.addStep(ShellCommand( + flunkOnFailure=False, + warnOnFailure=False, + workdir='.', + description="reboot after 5 test runs", + command=["python", "count_and_reboot.py", "-f", "../talos_count.txt", "-n", "5", "-z"], + env=MozillaEnvironments[envName])) + +def main(argv=None): + if argv is None: + argv = sys.argv + tester = LatestFileURL('http://ftp.mozilla.org/pub/mozilla.org/firefox/tinderbox-builds/mozilla-central-linux/1222921630/ ', "en-US.linux-i686.tar.bz2") + tester.testrun() + return 0 + +if __name__ == '__main__': + main() diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/count_and_reboot.py b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/count_and_reboot.py new file mode 100644 index 00000000000..3b0dc2baa18 --- /dev/null +++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/count_and_reboot.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# encoding: utf-8 +# Created by Chris AtLee on 2008-11-04 +"""count_and_reboot.py [-n maxcount] -f countfile + +Increments the value in countfile, and reboots the machine once the count +reaches or exceeds maxcount.""" + +import os, sys, time + +if sys.platform in ('darwin', 'linux2'): + def reboot(): + # -S means to accept password from stdin, which we then redirect from + # /dev/null + # This results in sudo not waiting forever for a password. If sudoers + # isn't set up properly, this will fail immediately + os.system("sudo -S reboot < /dev/null") + # After starting the shutdown, we go to sleep since the system can + # take a few minutes to shut everything down and reboot + time.sleep(600) + +elif sys.platform == "win32": + # Windows + def reboot(): + os.system("shutdown -r") + # After starting the shutdown, we go to sleep since the system can + # take a few minutes to shut everything down and reboot + time.sleep(600) + +def increment_count(fname): + try: + current_count = int(open(fname).read()) + except: + current_count = 0 + current_count += 1 + open(fname, "w").write("%i\n" % current_count) + return current_count + +if __name__ == '__main__': + from optparse import OptionParser + + parser = OptionParser(__doc__) + parser.add_option("-n", "--max-count", dest="maxcount", default=10, + help="reboot after runs", type="int") + parser.add_option("-f", "--count-file", dest="countfile", default=None, + help="file to record count in") + parser.add_option("-z", "--zero-count", dest="zero", default=False, + action="store_true", help="zero out the counter before rebooting") + + options, args = parser.parse_args() + + if not options.countfile: + parser.error("countfile is required") + + if increment_count(options.countfile) >= options.maxcount: + if options.zero: + open(options.countfile, "w").write("0\n") + print "Reached max number of runs before reboot required, restarting machine..." + sys.stdout.flush() + reboot() diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/generate-tpcomponent.py b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/generate-tpcomponent.py new file mode 100644 index 00000000000..06c7c0555c4 --- /dev/null +++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/generate-tpcomponent.py @@ -0,0 +1,83 @@ +# Generates the proper chrome/ and component/ directories that can be dropped +# into a profile to enable the pageloader +# Original Author: Alice Nodelman (anodelman@mozilla.com) +# Modified by: Ben Hearsum (bhearsum@mozilla.com) + +import os +import sys +import zipfile +import shutil +import tempfile + +# create the temp directory +tmp_dir = tempfile.mkdtemp() +pageloader_dir = os.path.join(tmp_dir, "pageloader") +# where the chrome/ and component/ directories will be put +working_dir = "." +chrome_dir = os.path.join(working_dir, 'chrome') +components_dir = os.path.join(working_dir, 'components') +# where the pageloader will be checked out from +cvsroot = ":pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot" +module = "mozilla/layout/tools/pageloader" + +def removedir(rdir): + if os.path.isdir(rdir): + for root, dirs, files in os.walk(rdir, topdown=False): + for name in files: + os.remove(os.path.join(root, name)) + for name in dirs: + os.rmdir(os.path.join(root, name)) + os.rmdir(rdir) + +def zipdir(zip, zdir): + if os.path.isdir(zdir): + for root, dirs, files in os.walk(zdir, topdown=False): + for name in files: + zip.write(os.path.join(root, name), os.path.join(os.path.basename(zdir), name)) + else: + zip.write(zdir) + + +# bail if the directories already exist +if os.path.exists(chrome_dir): + print "chrome/ directory exists, bailing out" + sys.exit(1) +if os.path.exists(components_dir): + print "components/ directory exists, bailing out" + sys.exit(1) + +oldcwd = os.getcwd() +os.chdir(tmp_dir) +# exit if cvs throws an error +if os.system("cvs -d%s co -d pageloader %s" % (cvsroot, module)): + print "could not retrieve pageloader, bailing out" + sys.exit(1) +os.chdir(oldcwd) + +#create the directory structure in the working_dir +os.mkdir(chrome_dir) +os.mkdir(os.path.join(chrome_dir, 'content')) +os.mkdir(components_dir) + +#create the pageloader.manifest file +f = open(os.path.join(chrome_dir, 'pageloader.manifest'), 'w') +f.write('content pageloader jar:pageloader.jar!/content/\n') +f.close() + +shutil.copy(os.path.join(pageloader_dir, 'pageloader.xul'), os.path.join(chrome_dir, 'content', 'pageloader.xul')) +shutil.copy(os.path.join(pageloader_dir, 'quit.js'), os.path.join(chrome_dir, 'content', 'quit.js')) +shutil.copy(os.path.join(pageloader_dir, 'pageloader.js'), os.path.join(chrome_dir, 'content', 'pageloader.js')) +shutil.copy(os.path.join(pageloader_dir, 'report.js'), os.path.join(chrome_dir, 'content', 'report.js')) + +# create pageloader.jar +jar = zipfile.ZipFile(os.path.join(chrome_dir, 'pageloader.jar'), 'w') +zipdir(jar, os.path.join(chrome_dir, 'content')) +jar.close() + +removedir(os.path.join(chrome_dir, 'content')) + +shutil.copy(os.path.join(pageloader_dir, 'tp-cmdline.js'), os.path.join(components_dir, 'tp-cmdline.js')) + +#get rid of the temporary directory +removedir(tmp_dir) + diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/installdmg.ex b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/installdmg.ex new file mode 100755 index 00000000000..1bc610c69b8 --- /dev/null +++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/installdmg.ex @@ -0,0 +1,49 @@ +#!/usr/bin/expect +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Corporation Code. +# +# The Initial Developer of the Original Code is +# Bob Clary. +# Portions created by the Initial Developer are Copyright (C) 2007 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Bob Clary +# Clint Talbert +# Alice Nodelman +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +system mkdir -p mnt +spawn hdiutil attach -verbose -noautoopen -mountpoint ./mnt $argv +expect { +"byte" {send "G"; exp_continue} +"END" {send "\r"; exp_continue} +"Y/N?" {send "Y\r"; exp_continue} +} +system rsync -a ./mnt/* . +system hdiutil detach mnt +system rm -rdf ./mnt diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/installdmg.sh b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/installdmg.sh new file mode 100644 index 00000000000..830fd52490b --- /dev/null +++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/scripts/installdmg.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +mkdir -p mnt +echo "y" | PAGER="/bin/cat" hdiutil attach -verbose -noautoopen -mountpoint ./mnt $1 +rsync -a ./mnt/* . +hdiutil detach mnt diff --git a/mozilla/tools/buildbot-configs/testing/talos/perf-staging/tinderboxmailnotifier.py b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/tinderboxmailnotifier.py new file mode 100644 index 00000000000..d14c9030a6a --- /dev/null +++ b/mozilla/tools/buildbot-configs/testing/talos/perf-staging/tinderboxmailnotifier.py @@ -0,0 +1,13 @@ +from buildbot.status import tinderbox + +class TinderboxMailNotifier(tinderbox.TinderboxMailNotifier): + """ + Subclass TinderboxMailNotifier to add the slave name to the build. + This makes tinderbox happy if we have more than one slave working + on one builder. + """ + def buildMessage(self, name, build, results): + return tinderbox.TinderboxMailNotifier.buildMessage(self, + name + ' ' + + build.getSlavename(), + build, results)