Home | History | Annotate | Download | only in build.webkit.org-config
      1 # -*- python -*-
      2 # ex: set syntax=python:
      3 
      4 c = BuildmasterConfig = {}
      5 
      6 from buildbot.buildslave import BuildSlave
      7 from buildbot.changes.pb import PBChangeSource
      8 from buildbot.scheduler import AnyBranchScheduler, Triggerable
      9 from buildbot.status import html
     10 from buildbot.process import buildstep, factory, properties
     11 from buildbot.steps import master, shell, source, transfer, trigger
     12 from buildbot.status.builder import SUCCESS, FAILURE, WARNINGS, SKIPPED
     13 
     14 from twisted.internet import defer
     15 
     16 import re
     17 import simplejson
     18 
     19 WithProperties = properties.WithProperties
     20 
     21 class ConfigureBuild(buildstep.BuildStep):
     22     name = "configure build"
     23     description = ["configuring build"]
     24     descriptionDone = ["configured build"]
     25     def __init__(self, platform, configuration, architecture, buildOnly, *args, **kwargs):
     26         buildstep.BuildStep.__init__(self, *args, **kwargs)
     27         self.platform = platform.split('-', 1)[0]
     28         self.fullPlatform = platform
     29         self.configuration = configuration
     30         self.architecture = architecture
     31         self.buildOnly = buildOnly
     32         self.addFactoryArguments(platform=platform, configuration=configuration, architecture=architecture, buildOnly=buildOnly)
     33 
     34     def start(self):
     35         self.setProperty("platform", self.platform)
     36         self.setProperty("fullPlatform", self.fullPlatform)
     37         self.setProperty("configuration", self.configuration)
     38         self.setProperty("architecture", self.architecture)
     39         self.setProperty("buildOnly", self.buildOnly)
     40         self.finished(SUCCESS)
     41         return defer.succeed(None)
     42 
     43 
     44 class CheckOutSource(source.SVN):
     45     baseURL = "http://svn.webkit.org/repository/webkit/"
     46     mode = "update"
     47     def __init__(self, *args, **kwargs):
     48         source.SVN.__init__(self, baseURL=self.baseURL, defaultBranch="trunk", mode=self.mode, *args, **kwargs)
     49 
     50 
     51 class InstallWin32Dependencies(shell.Compile):
     52     description = ["installing dependencies"]
     53     descriptionDone = ["installed dependencies"]
     54     command = ["perl", "./WebKitTools/Scripts/update-webkit-auxiliary-libs"]
     55 
     56 
     57 class InstallChromiumDependencies(shell.ShellCommand):
     58     name = "gclient"
     59     description = ["updating chromium dependencies"]
     60     descriptionDone = ["updated chromium dependencies"]
     61     command = ["perl", "./WebKitTools/Scripts/update-webkit-chromium"]
     62     haltOnFailure = True
     63 
     64 
     65 def appendCustomBuildFlags(step, platform):
     66     if platform in ('gtk', 'wx', 'qt', 'chromium'):
     67         step.setCommand(step.command + ['--' + platform])
     68 
     69 
     70 class CompileWebKit(shell.Compile):
     71     command = ["perl", "./WebKitTools/Scripts/build-webkit", WithProperties("--%(configuration)s")]
     72     env = {'MFLAGS':''}
     73     name = "compile-webkit"
     74     description = ["compiling"]
     75     descriptionDone = ["compiled"]
     76     warningPattern = ".*arning: .*"
     77 
     78     def start(self):
     79         platform = self.getProperty('platform')
     80         buildOnly = self.getProperty('buildOnly')
     81         if platform == 'mac' and buildOnly:
     82             self.setCommand(self.command + ['DEBUG_INFORMATION_FORMAT=dwarf-with-dsym'])
     83 
     84         appendCustomBuildFlags(self, platform)
     85         return shell.Compile.start(self)
     86 
     87 
     88 class ArchiveBuiltProduct(shell.ShellCommand):
     89     command = ["python", "./WebKitTools/BuildSlaveSupport/built-product-archive",
     90                WithProperties("--platform=%(platform)s"), WithProperties("--%(configuration)s"), "archive"]
     91     name = "archive-built-product"
     92     description = ["archiving built product"]
     93     descriptionDone = ["archived built product"]
     94     haltOnFailure = True
     95 
     96 
     97 class ExtractBuiltProduct(shell.ShellCommand):
     98     command = ["python", "./WebKitTools/BuildSlaveSupport/built-product-archive",
     99                WithProperties("--platform=%(platform)s"), WithProperties("--%(configuration)s"), "extract"]
    100     name = "extract-built-product"
    101     description = ["extracting built product"]
    102     descriptionDone = ["extracted built product"]
    103     haltOnFailure = True
    104 
    105 
    106 class UploadBuiltProduct(transfer.FileUpload):
    107     slavesrc = WithProperties("WebKitBuild/%(configuration)s.zip")
    108     masterdest = WithProperties("archives/%(fullPlatform)s-%(architecture)s-%(configuration)s/%(got_revision)s.zip")
    109     haltOnFailure = True
    110 
    111     def __init__(self):
    112         transfer.FileUpload.__init__(self, self.slavesrc, self.masterdest)
    113 
    114 
    115 class DownloadBuiltProduct(transfer.FileDownload):
    116     slavedest = WithProperties("WebKitBuild/%(configuration)s.zip")
    117     mastersrc = WithProperties("archives/%(fullPlatform)s-%(architecture)s-%(configuration)s/%(got_revision)s.zip")
    118     haltOnFailure = True
    119 
    120     def __init__(self):
    121         transfer.FileDownload.__init__(self, self.mastersrc, self.slavedest)
    122 
    123 
    124 class RunJavaScriptCoreTests(shell.Test):
    125     name = "jscore-test"
    126     description = ["jscore-tests running"]
    127     descriptionDone = ["jscore-tests"]
    128     command = ["perl", "./WebKitTools/Scripts/run-javascriptcore-tests", WithProperties("--%(configuration)s")]
    129     logfiles = {'results': 'JavaScriptCore/tests/mozilla/actual.html'}
    130 
    131     def __init__(self, skipBuild=False, *args, **kwargs):
    132         self.skipBuild = skipBuild
    133         shell.Test.__init__(self, *args, **kwargs)
    134         self.addFactoryArguments(skipBuild=skipBuild)
    135 
    136     def start(self):
    137         appendCustomBuildFlags(self, self.getProperty('platform'))
    138         if self.skipBuild:
    139             self.setCommand(self.command + ['--skip-build'])
    140         return shell.Test.start(self)
    141 
    142     def commandComplete(self, cmd):
    143         shell.Test.commandComplete(self, cmd)
    144 
    145         logText = cmd.logs['stdio'].getText()
    146         statusLines = [line for line in logText.splitlines() if line.find('regression') >= 0 and line.find(' found.') >= 0]
    147         if statusLines and statusLines[0].split()[0] != '0':
    148             self.regressionLine = statusLines[0]
    149         else:
    150             self.regressionLine = None
    151 
    152     def evaluateCommand(self, cmd):
    153         if self.regressionLine:
    154             return FAILURE
    155 
    156         if cmd.rc != 0:
    157             return FAILURE
    158 
    159         return SUCCESS
    160 
    161     def getText(self, cmd, results):
    162         return self.getText2(cmd, results)
    163 
    164     def getText2(self, cmd, results):
    165         if results != SUCCESS and self.regressionLine:
    166             return [self.name, self.regressionLine]
    167 
    168         return [self.name]
    169 
    170 
    171 class RunWebKitTests(shell.Test):
    172     name = "layout-test"
    173     description = ["layout-tests running"]
    174     descriptionDone = ["layout-tests"]
    175     command = ["perl", "./WebKitTools/Scripts/run-webkit-tests", "--no-launch-safari", "--no-new-test-results",
    176                "--no-sample-on-timeout", "--results-directory", "layout-test-results", "--use-remote-links-to-tests",
    177                WithProperties("--%(configuration)s"), "--exit-after-n-failures", "20"]
    178 
    179     def __init__(self, skipBuild=False, *args, **kwargs):
    180         self.skipBuild = skipBuild
    181         shell.Test.__init__(self, *args, **kwargs)
    182         self.addFactoryArguments(skipBuild=skipBuild)
    183 
    184     def start(self):
    185         appendCustomBuildFlags(self, self.getProperty('platform'))
    186         if self.skipBuild:
    187             self.setCommand(self.command + ['--root=WebKitBuild/bin'])
    188         return shell.Test.start(self)
    189 
    190     def commandComplete(self, cmd):
    191         shell.Test.commandComplete(self, cmd)
    192 
    193         logText = cmd.logs['stdio'].getText()
    194         incorrectLayoutLines = []
    195         for line in logText.splitlines():
    196             if line.find('had incorrect layout') >= 0 or line.find('were new') >= 0 or line.find('was new') >= 0:
    197                 incorrectLayoutLines.append(line)
    198             elif line.find('test case') >= 0 and (line.find(' crashed') >= 0 or line.find(' timed out') >= 0):
    199                 incorrectLayoutLines.append(line)
    200             elif line.startswith("WARNING:") and line.find(' leak') >= 0:
    201                 incorrectLayoutLines.append(line.replace('WARNING: ', ''))
    202             elif line.find('Exiting early') >= 0:
    203                 incorrectLayoutLines.append(line)
    204 
    205             # FIXME: Detect and summarize leaks of RefCounted objects
    206 
    207         self.incorrectLayoutLines = incorrectLayoutLines
    208 
    209     def evaluateCommand(self, cmd):
    210         if self.incorrectLayoutLines:
    211             if len(self.incorrectLayoutLines) == 1:
    212                 line = self.incorrectLayoutLines[0]
    213                 if line.find('were new') >= 0 or line.find('was new') >= 0 or line.find(' leak') >= 0:
    214                     return WARNINGS
    215 
    216             return FAILURE
    217 
    218         if cmd.rc != 0:
    219             return FAILURE
    220 
    221         return SUCCESS
    222 
    223     def getText(self, cmd, results):
    224         return self.getText2(cmd, results)
    225 
    226     def getText2(self, cmd, results):
    227         if results != SUCCESS and self.incorrectLayoutLines:
    228             return self.incorrectLayoutLines
    229 
    230         return [self.name]
    231 
    232 
    233 class RunWebKitLeakTests(RunWebKitTests):
    234     def start(self):
    235         self.setCommand(self.command + ["--leaks"])
    236         return RunWebKitTests.start(self)
    237 
    238 
    239 class ArchiveTestResults(shell.ShellCommand):
    240     command = ["python", "./WebKitTools/BuildSlaveSupport/test-result-archive",
    241                WithProperties("--platform=%(platform)s"), WithProperties("--%(configuration)s"), "archive"]
    242     name = "archive-test-results"
    243     description = ["archiving test results"]
    244     descriptionDone = ["archived test results"]
    245     haltOnFailure = True
    246 
    247 
    248 class UploadTestResults(transfer.FileUpload):
    249     slavesrc = "layout-test-results.zip"
    250     masterdest = WithProperties("public_html/results/%(buildername)s/r%(got_revision)s (%(buildnumber)s).zip")
    251 
    252     def __init__(self):
    253         transfer.FileUpload.__init__(self, self.slavesrc, self.masterdest)
    254 
    255 
    256 class ExtractTestResults(master.MasterShellCommand):
    257     zipFile = WithProperties("public_html/results/%(buildername)s/r%(got_revision)s (%(buildnumber)s).zip")
    258     resultDirectory = WithProperties("public_html/results/%(buildername)s/r%(got_revision)s (%(buildnumber)s)")
    259 
    260     def __init__(self):
    261         master.MasterShellCommand.__init__(self, "")
    262 
    263     def start(self):
    264         self.command = ["ditto", "-k", "-x", "-V", self.build.getProperties().render(self.zipFile), self.build.getProperties().render(self.resultDirectory)]
    265         return master.MasterShellCommand.start(self)
    266 
    267     def finished(self, result):
    268         url = self.build.getProperties().render(self.resultDirectory).replace("public_html/", "")
    269         self.addURL("view results", url)
    270         result = master.MasterShellCommand.finished(self, result)
    271         self.step_status.setText(["uploaded results"])
    272         return result
    273 
    274 
    275 class Factory(factory.BuildFactory):
    276     def __init__(self, platform, configuration, architectures, buildOnly):
    277         factory.BuildFactory.__init__(self)
    278         self.addStep(ConfigureBuild, platform=platform, configuration=configuration, architecture=" ".join(architectures), buildOnly=buildOnly)
    279         self.addStep(CheckOutSource)
    280         if platform == "win":
    281             self.addStep(InstallWin32Dependencies)
    282         if platform == "chromium":
    283             self.addStep(InstallChromiumDependencies)
    284 
    285 class BuildFactory(Factory):
    286     def __init__(self, platform, configuration, architectures, triggers=None):
    287         Factory.__init__(self, platform, configuration, architectures, True)
    288         self.addStep(CompileWebKit)
    289         if triggers:
    290             self.addStep(ArchiveBuiltProduct)
    291             self.addStep(UploadBuiltProduct)
    292             self.addStep(trigger.Trigger, schedulerNames=triggers)
    293 
    294 class TestFactory(Factory):
    295     def __init__(self, platform, configuration, architectures):
    296         Factory.__init__(self, platform, configuration, architectures, False)
    297         self.addStep(DownloadBuiltProduct)
    298         self.addStep(ExtractBuiltProduct)
    299         self.addStep(RunJavaScriptCoreTests, skipBuild=True)
    300         self.addStep(RunWebKitTests, skipBuild=(platform == 'win'))
    301         self.addStep(ArchiveTestResults)
    302         self.addStep(UploadTestResults)
    303         self.addStep(ExtractTestResults)
    304 
    305 class BuildAndTestFactory(Factory):
    306     TestClass = RunWebKitTests
    307     def __init__(self, platform, configuration, architectures):
    308         Factory.__init__(self, platform, configuration, architectures, False)
    309         self.addStep(CompileWebKit)
    310         self.addStep(RunJavaScriptCoreTests)
    311         self.addStep(self.TestClass)
    312         self.addStep(ArchiveTestResults)
    313         self.addStep(UploadTestResults)
    314         self.addStep(ExtractTestResults)
    315 
    316 class BuildAndTestLeaksFactory(BuildAndTestFactory):
    317     TestClass = RunWebKitLeakTests
    318 
    319 
    320 def loadBuilderConfig(c):
    321     passwords = simplejson.load(open('passwords.json'))
    322 
    323     config = simplejson.load(open('config.json'))
    324 
    325     c['slaves'] = [BuildSlave(slave['name'], passwords[slave['name']], max_builds=1) for slave in config['slaves']]
    326 
    327     c['schedulers'] = []
    328     for scheduler in config['schedulers']:
    329         kls = globals()[scheduler.pop('type')]
    330         c['schedulers'].append(kls(**scheduler))
    331 
    332     c['builders'] = []
    333     for builder in config['builders']:
    334         for slaveName in builder['slavenames']:
    335             for slave in config['slaves']:
    336                 if slave['name'] != slaveName or slave['platform'] == '*':
    337                     continue
    338 
    339                 if slave['platform'] != builder['platform']:
    340                     raise Exception, "Builder %r is for platform %r but has slave %r for platform %r!" % (builder['name'], builder['platform'], slave['name'], slave['platform'])
    341 
    342                 break
    343 
    344         factory = globals()["%sFactory" % builder.pop('type')]
    345         factoryArgs = []
    346         for key in "platform", "configuration", "architectures", "triggers":
    347             value = builder.pop(key, None)
    348             if value:
    349                 factoryArgs.append(value)
    350 
    351         builder["factory"] = factory(*factoryArgs)
    352 
    353         c['builders'].append(builder)
    354 
    355 loadBuilderConfig(c)
    356 
    357 c['change_source'] = PBChangeSource()
    358 
    359 c['status'] = []
    360 c['status'].append(html.WebStatus(http_port=8710, allowForce=True))
    361 
    362 c['slavePortnum'] = 17000
    363 c['projectName'] = "WebKit"
    364 c['projectURL'] = "http://webkit.org"
    365 c['buildbotURL'] = "http://build.webkit.org/"
    366