2 # ex: set syntax=python:
4 c = BuildmasterConfig = {}
6 from buildbot.buildslave import BuildSlave
7 from buildbot.changes.pb import PBChangeSource
8 from buildbot.scheduler import AnyBranchScheduler, Triggerable
9 from buildbot.schedulers.filter import ChangeFilter
10 from buildbot.status import html
11 from buildbot.status.web.authz import Authz
12 from buildbot.process import buildstep, factory, properties
13 from buildbot.steps import master, shell, source, transfer, trigger
14 from buildbot.status.builder import SUCCESS, FAILURE, WARNINGS, SKIPPED
16 from twisted.internet import defer
23 from webkitpy.common.config import build as wkbuild
24 from webkitpy.common.net.buildbot import BuildBot as wkbuildbot
26 WithProperties = properties.WithProperties
28 class ConfigureBuild(buildstep.BuildStep):
29 name = "configure build"
30 description = ["configuring build"]
31 descriptionDone = ["configured build"]
32 def __init__(self, platform, configuration, architecture, buildOnly, features, *args, **kwargs):
33 buildstep.BuildStep.__init__(self, *args, **kwargs)
34 self.platform = platform.split('-', 1)[0]
35 self.fullPlatform = platform
36 self.configuration = configuration
37 self.architecture = architecture
38 self.buildOnly = buildOnly
39 self.features = features;
40 self.addFactoryArguments(platform=platform, configuration=configuration, architecture=architecture, buildOnly=buildOnly, features=features)
43 self.setProperty("platform", self.platform)
44 self.setProperty("fullPlatform", self.fullPlatform)
45 self.setProperty("configuration", self.configuration)
46 self.setProperty("architecture", self.architecture)
47 self.setProperty("buildOnly", self.buildOnly)
48 self.setProperty("features", self.features)
49 self.finished(SUCCESS)
50 return defer.succeed(None)
53 class CheckOutSource(source.SVN):
54 baseURL = "http://svn.webkit.org/repository/webkit/"
56 def __init__(self, *args, **kwargs):
57 source.SVN.__init__(self, baseURL=self.baseURL, defaultBranch="trunk", mode=self.mode, *args, **kwargs)
60 class InstallWin32Dependencies(shell.Compile):
61 description = ["installing dependencies"]
62 descriptionDone = ["installed dependencies"]
63 command = ["perl", "./Tools/Scripts/update-webkit-auxiliary-libs"]
65 class KillOldProcesses(shell.Compile):
66 name = "kill old processes"
67 description = ["killing old processes"]
68 descriptionDone = ["killed old processes"]
69 command = ["python", "./Tools/BuildSlaveSupport/kill-old-processes"]
71 class InstallGtkDependencies(shell.ShellCommand):
73 description = ["updating gtk dependencies"]
74 descriptionDone = ["updated gtk dependencies"]
75 command = ["perl", "./Tools/Scripts/update-webkitgtk-libs"]
78 class InstallChromiumDependencies(shell.ShellCommand):
80 description = ["updating chromium dependencies"]
81 descriptionDone = ["updated chromium dependencies"]
82 command = ["perl", "./Tools/Scripts/update-webkit-chromium", "--force"]
85 if self.getProperty('fullPlatform') == "chromium-android":
86 self.setCommand(self.command + ['--chromium-android'])
88 return shell.ShellCommand.start(self)
90 class CleanupChromiumCrashLogs(shell.ShellCommand):
91 name = "cleanup crash logs"
92 description = ["removing crash logs"]
93 descriptionDone = ["removed crash logs"]
94 command = ["python", "./Tools/BuildSlaveSupport/chromium/remove-crash-logs"]
98 def appendCustomBuildFlags(step, platform, fullPlatform="", useFullPlatformForChromiumCGMac=False):
99 if fullPlatform == "chromium-android":
100 step.setCommand(step.command + ['--chromium-android'])
101 elif useFullPlatformForChromiumCGMac and fullPlatform.find('-cg-mac') > 0:
102 step.setCommand(step.command + ['--platform', fullPlatform])
103 # Remove this code once Skia transition is done
104 elif platform in ('chromium', 'efl', 'gtk', 'qt', 'wincairo', 'wince', 'wx'):
105 step.setCommand(step.command + ['--' + platform])
108 class CompileWebKit(shell.Compile):
109 command = ["perl", "./Tools/Scripts/build-webkit", WithProperties("--%(configuration)s")]
111 name = "compile-webkit"
112 description = ["compiling"]
113 descriptionDone = ["compiled"]
114 warningPattern = ".*arning: .*"
117 platform = self.getProperty('platform')
118 buildOnly = self.getProperty('buildOnly')
119 if platform == 'mac' and buildOnly:
120 self.setCommand(self.command + ['DEBUG_INFORMATION_FORMAT=dwarf-with-dsym'])
122 appendCustomBuildFlags(self, platform, self.getProperty('fullPlatform'))
124 features = self.getProperty('features')
125 for feature in features:
126 self.setCommand(self.command + ['--' + feature])
128 return shell.Compile.start(self)
131 class ArchiveBuiltProduct(shell.ShellCommand):
132 command = ["python", "./Tools/BuildSlaveSupport/built-product-archive",
133 WithProperties("--platform=%(platform)s"), WithProperties("--%(configuration)s"), "archive"]
134 name = "archive-built-product"
135 description = ["archiving built product"]
136 descriptionDone = ["archived built product"]
140 class ExtractBuiltProduct(shell.ShellCommand):
141 command = ["python", "./Tools/BuildSlaveSupport/built-product-archive",
142 WithProperties("--platform=%(platform)s"), WithProperties("--%(configuration)s"), "extract"]
143 name = "extract-built-product"
144 description = ["extracting built product"]
145 descriptionDone = ["extracted built product"]
149 class UploadBuiltProduct(transfer.FileUpload):
150 slavesrc = WithProperties("WebKitBuild/%(configuration)s.zip")
151 masterdest = WithProperties("archives/%(fullPlatform)s-%(architecture)s-%(configuration)s%(extraFeatures)s/%(got_revision)s.zip",
152 extraFeatures=lambda properties: UploadBuiltProduct.determineExtraFeatures(properties))
156 transfer.FileUpload.__init__(self, self.slavesrc, self.masterdest, mode=0644)
159 def determineExtraFeatures(properties):
160 if not properties.has_key("features"):
162 features = properties.getProperty("features")
163 if not len(features):
165 result = '-with-' + '-and-'.join(features)
166 # Just to make sure no feature will add invalid chars, we allow only letters here.
167 result = re.sub('[^a-zA-Z]', '-', result)
171 class DownloadBuiltProduct(transfer.FileDownload):
172 slavedest = WithProperties("WebKitBuild/%(configuration)s.zip")
173 mastersrc = WithProperties("archives/%(fullPlatform)s-%(architecture)s-%(configuration)s/%(got_revision)s.zip")
175 flunkOnFailure = True
178 transfer.FileDownload.__init__(self, self.mastersrc, self.slavedest)
181 class RunJavaScriptCoreTests(shell.Test):
183 description = ["jscore-tests running"]
184 descriptionDone = ["jscore-tests"]
185 command = ["perl", "./Tools/Scripts/run-javascriptcore-tests", WithProperties("--%(configuration)s")]
186 logfiles = {'actual.html (source)': 'Source/JavaScriptCore/tests/mozilla/actual.html'}
188 def __init__(self, buildJSCTool=True, *args, **kwargs):
189 self.buildJSCTool = buildJSCTool
190 shell.Test.__init__(self, *args, **kwargs)
191 self.addFactoryArguments(buildJSCTool=buildJSCTool)
194 appendCustomBuildFlags(self, self.getProperty('platform'))
195 if not self.buildJSCTool:
196 self.setCommand(self.command + ['--no-build'])
197 return shell.Test.start(self)
199 def commandComplete(self, cmd):
200 shell.Test.commandComplete(self, cmd)
202 logText = cmd.logs['stdio'].getText()
203 statusLines = [line for line in logText.splitlines() if line.find('regression') >= 0 and line.find(' found.') >= 0]
204 if statusLines and statusLines[0].split()[0] != '0':
205 self.regressionLine = statusLines[0]
207 self.regressionLine = None
209 if 'actual.html (source)' in cmd.logs:
210 self.addHTMLLog('actual.html', cmd.logs['actual.html (source)'].getText())
212 def evaluateCommand(self, cmd):
213 if self.regressionLine:
221 def getText(self, cmd, results):
222 return self.getText2(cmd, results)
224 def getText2(self, cmd, results):
225 if results != SUCCESS and self.regressionLine:
226 return [self.name, self.regressionLine]
231 class RunWebKitTests(shell.Test):
233 description = ["layout-tests running"]
234 descriptionDone = ["layout-tests"]
235 command = ["perl", "./Tools/Scripts/run-webkit-tests",
236 "--no-launch-safari",
237 "--no-new-test-results",
238 "--no-sample-on-timeout",
239 "--results-directory", "layout-test-results",
240 "--use-remote-links-to-tests",
241 "--builder-name", WithProperties("%(buildername)s"),
242 "--build-number", WithProperties("%(buildnumber)s"),
243 "--master-name", "webkit.org",
244 "--test-results-server", "test-results.appspot.com",
245 WithProperties("--%(configuration)s"),
246 "--exit-after-n-crashes-or-timeouts", "20",
247 "--exit-after-n-failures", "500"]
249 def __init__(self, buildJSCTool=True, *args, **kwargs):
250 self.buildJSCTool = buildJSCTool
251 shell.Test.__init__(self, *args, **kwargs)
252 self.addFactoryArguments(buildJSCTool=buildJSCTool)
255 platform = self.getProperty('platform')
256 appendCustomBuildFlags(self, platform, self.getProperty('fullPlatform'), True)
257 if platform == "win":
258 rootArgument = ['--root=' + os.path.join("WebKitBuild", self.getProperty('configuration'), "bin")]
260 rootArgument = ['--root=WebKitBuild/bin']
261 if not self.buildJSCTool:
262 self.setCommand(self.command + rootArgument)
263 return shell.Test.start(self)
265 def _parseOldRunWebKitTestsOutput(self, logText):
266 incorrectLayoutLines = []
267 for line in logText.splitlines():
268 if line.find('had incorrect layout') >= 0 or line.find('were new') >= 0 or line.find('was new') >= 0:
269 incorrectLayoutLines.append(line)
270 elif line.find('test case') >= 0 and (line.find(' crashed') >= 0 or line.find(' timed out') >= 0):
271 incorrectLayoutLines.append(line)
272 elif line.startswith("WARNING:") and line.find(' leak') >= 0:
273 incorrectLayoutLines.append(line.replace('WARNING: ', ''))
274 elif line.find('Exiting early') >= 0:
275 incorrectLayoutLines.append(line)
277 # FIXME: Detect and summarize leaks of RefCounted objects
279 self.incorrectLayoutLines = incorrectLayoutLines
281 # FIXME: This will break if new-run-webkit-tests changes its default log formatter.
282 nrwt_log_message_regexp = re.compile(r'(?P<log_prefix>.*) (?P<log_level>DEBUG|INFO) (?P<message>.*)')
284 def _strip_python_logging_prefix(self, line):
285 match_object = self.nrwt_log_message_regexp.match(line)
287 return match_object.group('message')
290 def _parseNewRunWebKitTestsOutput(self, logText):
291 incorrectLayoutLines = []
293 ('flakes', re.compile(r'Unexpected flakiness.+:?\s*\((\d+)\)')),
294 ('new passes', re.compile(r'Expected to .+, but passed:\s+\((\d+)\)')),
295 ('missing results', re.compile(r'no expected results found\s*:\s+\((\d+)\)')),
296 ('failures', re.compile(r'Regressions: Unexpected.+:?\s*\((\d+)\)')),
300 for line in logText.splitlines():
301 if line.find('Exiting early') >= 0 or line.find('leaks found') >= 0:
302 incorrectLayoutLines.append(self._strip_python_logging_prefix(line))
304 for name, expression in expressions:
305 match = expression.search(line)
308 testFailures[name] = testFailures.get(name, 0) + int(match.group(1))
311 # FIXME: Parse file names and put them in results
313 for name in testFailures:
314 incorrectLayoutLines.append(str(testFailures[name]) + ' ' + name)
316 self.incorrectLayoutLines = incorrectLayoutLines
318 def commandComplete(self, cmd):
319 shell.Test.commandComplete(self, cmd)
321 logText = cmd.logs['stdio'].getText()
322 if logText.find("Collecting tests ...") >= 0:
323 self._parseNewRunWebKitTestsOutput(logText)
325 self._parseOldRunWebKitTestsOutput(logText)
327 def evaluateCommand(self, cmd):
330 if self.incorrectLayoutLines:
331 if len(self.incorrectLayoutLines) == 1:
332 line = self.incorrectLayoutLines[0]
333 if line.find('were new') >= 0 or line.find('was new') >= 0 or line.find(' leak') >= 0:
336 for line in self.incorrectLayoutLines:
337 if line.find('flakes') >= 0 or line.find('new passes') >= 0 or line.find('missing results') >= 0:
347 def getText(self, cmd, results):
348 return self.getText2(cmd, results)
350 def getText2(self, cmd, results):
351 if results != SUCCESS and self.incorrectLayoutLines:
352 return self.incorrectLayoutLines
357 class NewRunWebKitTests(RunWebKitTests):
358 command = ["python", "./Tools/Scripts/new-run-webkit-tests",
359 "--no-show-results", "--no-new-test-results",
360 "--verbose", "--results-directory", "layout-test-results",
361 "--builder-name", WithProperties("%(buildername)s"),
362 "--build-number", WithProperties("%(buildnumber)s"),
363 "--master-name", "webkit.org",
364 "--test-results-server", "test-results.appspot.com",
365 WithProperties("--%(configuration)s")]
367 def commandComplete(self, cmd):
368 shell.Test.commandComplete(self, cmd)
370 logText = cmd.logs['stdio'].getText()
371 self._parseNewRunWebKitTestsOutput(logText)
373 class RunUnitTests(shell.Test):
374 name = "run-api-tests"
375 description = ["unit tests running"]
376 descriptionDone = ["unit-tests"]
377 command = ["perl", "./Tools/Scripts/run-api-tests", WithProperties("--%(configuration)s"), "--verbose"]
380 platform = self.getProperty('platform')
381 if platform == 'win':
382 self.setCommand(self.command + ['--no-build'])
383 if platform.startswith('chromium'):
384 self.setCommand(self.command + ['--chromium'])
385 return shell.Test.start(self)
388 class TestWithFailureCount(shell.Test):
389 failedTestsFormatString = "%d tests failed"
391 def countFailures(self, cmd):
394 def commandComplete(self, cmd):
395 shell.Test.commandComplete(self, cmd)
396 self.failedTestCount = self.countFailures(cmd)
398 def evaluateCommand(self, cmd):
399 if self.failedTestCount:
407 def getText(self, cmd, results):
408 return self.getText2(cmd, results)
410 def getText2(self, cmd, results):
411 if results != SUCCESS and self.failedTestCount:
412 return [self.failedTestsFormatString % self.failedTestCount]
417 class RunPythonTests(TestWithFailureCount):
418 name = "webkitpy-test"
419 description = ["python-tests running"]
420 descriptionDone = ["python-tests"]
421 command = ["python", "./Tools/Scripts/test-webkitpy"]
422 failedTestsFormatString = "%d python tests failed"
424 def countFailures(self, cmd):
425 logText = cmd.logs['stdio'].getText()
426 # We're looking for the line that looks like this: FAILED (failures=2, errors=1)
427 regex = re.compile(r'^FAILED \((?P<counts>[^)]+)\)')
428 for line in logText.splitlines():
429 match = regex.match(line)
432 return sum(int(component.split('=')[1]) for component in match.group('counts').split(', '))
436 class RunPerlTests(TestWithFailureCount):
437 name = "webkitperl-test"
438 description = ["perl-tests running"]
439 descriptionDone = ["perl-tests"]
440 command = ["perl", "./Tools/Scripts/test-webkitperl"]
441 failedTestsFormatString = "%d perl tests failed"
443 def countFailures(self, cmd):
444 logText = cmd.logs['stdio'].getText()
445 # We're looking for the line that looks like this: Failed 2/19 test programs. 5/363 subtests failed.
446 regex = re.compile(r'^Failed \d+/\d+ test programs\. (?P<count>\d+)/\d+ subtests failed\.')
447 for line in logText.splitlines():
448 match = regex.match(line)
451 return int(match.group('count'))
455 class RunBindingsTests(shell.Test):
456 name = "bindings-generation-tests"
457 description = ["bindings-tests running"]
458 descriptionDone = ["bindings-tests"]
459 command = ["python", "./Tools/Scripts/run-bindings-tests"]
462 class RunGtkAPITests(shell.Test):
464 description = ["API tests running"]
465 descriptionDone = ["API tests"]
466 command = ["perl", "./Tools/Scripts/run-gtk-tests", WithProperties("--%(configuration)s")]
468 def commandComplete(self, cmd):
469 shell.Test.commandComplete(self, cmd)
471 logText = cmd.logs['stdio'].getText()
473 for line in logText.splitlines():
474 if line.startswith('ERROR'):
475 incorrectLines.append(line)
477 self.incorrectLines = incorrectLines
479 def evaluateCommand(self, cmd):
480 if self.incorrectLines:
488 def getText(self, cmd, results):
489 return self.getText2(cmd, results)
491 def getText2(self, cmd, results):
492 if results != SUCCESS and self.incorrectLines:
493 return ["%d API tests failed" % len(self.incorrectLines)]
497 class RunQtAPITests(shell.Test):
499 description = ["API tests running"]
500 descriptionDone = ["API tests"]
501 command = ["python", "./Tools/Scripts/run-qtwebkit-tests",
502 "--output-file=qt-unit-tests.html", "--do-not-open-results", "--timeout=120",
503 WithProperties("WebKitBuild/%(configuration_pretty)s/Source/WebKit/qt/tests/")]
506 self.setProperty("configuration_pretty", self.getProperty("configuration").title())
507 return shell.Test.start(self)
509 def commandComplete(self, cmd):
510 shell.Test.commandComplete(self, cmd)
512 logText = cmd.logs['stdio'].getText()
513 foundItems = re.findall("TOTALS: (?P<passed>\d+) passed, (?P<failed>\d+) failed, (?P<skipped>\d+) skipped", logText)
515 self.incorrectTests = 0
519 self.incorrectTests = int(foundItems[0][1])
520 if self.incorrectTests > 0:
522 "%s passed, %s failed, %s skipped" % (foundItems[0][0], foundItems[0][1], foundItems[0][2])
525 def evaluateCommand(self, cmd):
526 if self.incorrectTests:
534 def getText(self, cmd, results):
535 return self.getText2(cmd, results)
537 def getText2(self, cmd, results):
538 if results != SUCCESS and self.incorrectTests:
539 return self.statusLine
543 class RunWebKitLeakTests(RunWebKitTests):
544 warnOnWarnings = True
546 self.setCommand(self.command + ["--leaks"])
547 return RunWebKitTests.start(self)
550 class RunWebKit2Tests(RunWebKitTests):
552 self.setCommand(self.command + ["--webkit-test-runner"])
553 return RunWebKitTests.start(self)
556 class RunChromiumWebKitUnitTests(shell.Test):
557 name = "webkit-unit-tests"
558 description = ["webkit-unit-tests running"]
559 descriptionDone = ["webkit-unit-tests"]
560 command = ["perl", "./Tools/Scripts/run-chromium-webkit-unit-tests",
561 WithProperties("--%(configuration)s")]
564 class ArchiveTestResults(shell.ShellCommand):
565 command = ["python", "./Tools/BuildSlaveSupport/test-result-archive",
566 WithProperties("--platform=%(platform)s"), WithProperties("--%(configuration)s"), "archive"]
567 name = "archive-test-results"
568 description = ["archiving test results"]
569 descriptionDone = ["archived test results"]
573 class UploadTestResults(transfer.FileUpload):
574 slavesrc = "layout-test-results.zip"
575 masterdest = WithProperties("public_html/results/%(buildername)s/r%(got_revision)s (%(buildnumber)s).zip")
578 transfer.FileUpload.__init__(self, self.slavesrc, self.masterdest, mode=0644)
581 class ExtractTestResults(master.MasterShellCommand):
582 zipFile = WithProperties("public_html/results/%(buildername)s/r%(got_revision)s (%(buildnumber)s).zip")
583 resultDirectory = WithProperties("public_html/results/%(buildername)s/r%(got_revision)s (%(buildnumber)s)")
584 descriptionDone = ["uploaded results"]
587 master.MasterShellCommand.__init__(self, "")
589 def resultDirectoryURL(self):
590 return self.build.getProperties().render(self.resultDirectory).replace("public_html/", "/") + "/"
593 self.command = ["ditto", "-k", "-x", "-V", self.build.getProperties().render(self.zipFile), self.build.getProperties().render(self.resultDirectory)]
594 return master.MasterShellCommand.start(self)
596 def addCustomURLs(self):
597 url = self.resultDirectoryURL() + "results.html"
598 self.addURL("view results", url)
600 def finished(self, result):
602 return master.MasterShellCommand.finished(self, result)
605 class ExtractTestResultsAndLeaks(ExtractTestResults):
606 def addCustomURLs(self):
607 ExtractTestResults.addCustomURLs(self)
608 url = "/LeaksViewer/?url=" + urllib.quote(self.resultDirectoryURL(), safe="")
609 self.addURL("view leaks", url)
612 class Factory(factory.BuildFactory):
613 def __init__(self, platform, configuration, architectures, buildOnly, features=None, **kwargs):
614 factory.BuildFactory.__init__(self)
615 self.addStep(ConfigureBuild, platform=platform, configuration=configuration, architecture=" ".join(architectures), buildOnly=buildOnly, features=features)
616 self.addStep(CheckOutSource)
617 self.addStep(KillOldProcesses)
618 if platform == "win":
619 self.addStep(InstallWin32Dependencies)
620 if platform.startswith("chromium"):
621 self.addStep(InstallChromiumDependencies)
622 if platform == "gtk":
623 self.addStep(InstallGtkDependencies)
626 class BuildFactory(Factory):
627 def __init__(self, platform, configuration, architectures, triggers=None, upload=False, **kwargs):
628 Factory.__init__(self, platform, configuration, architectures, True, **kwargs)
629 self.addStep(CompileWebKit)
630 if triggers or upload:
631 self.addStep(ArchiveBuiltProduct)
632 self.addStep(UploadBuiltProduct)
634 self.addStep(trigger.Trigger, schedulerNames=triggers)
636 def unitTestsSupported(configuration, platform):
637 return (platform == 'win' or platform.startswith('mac')
638 or (platform.startswith('chromium') and platform != 'chromium-android'))
640 class TestFactory(Factory):
641 TestClass = RunWebKitTests
642 ExtractTestResultsClass = ExtractTestResults
643 def __init__(self, platform, configuration, architectures, **kwargs):
644 Factory.__init__(self, platform, configuration, architectures, False, **kwargs)
645 self.addStep(DownloadBuiltProduct)
646 self.addStep(ExtractBuiltProduct)
647 self.addStep(RunJavaScriptCoreTests, buildJSCTool=False)
648 self.addStep(self.TestClass, buildJSCTool=(platform != 'win'))
650 if unitTestsSupported(configuration, platform):
651 self.addStep(RunUnitTests)
652 self.addStep(RunPythonTests)
653 self.addStep(RunPerlTests)
654 self.addStep(RunBindingsTests)
655 self.addStep(ArchiveTestResults)
656 self.addStep(UploadTestResults)
657 self.addStep(self.ExtractTestResultsClass)
659 class BuildAndTestFactory(Factory):
660 TestClass = RunWebKitTests
661 ExtractTestResultsClass = ExtractTestResults
662 def __init__(self, platform, configuration, architectures, **kwargs):
663 Factory.__init__(self, platform, configuration, architectures, False, **kwargs)
664 if platform.startswith("chromium"):
665 self.addStep(CleanupChromiumCrashLogs)
666 self.addStep(CompileWebKit)
667 if not platform.startswith("chromium"):
668 self.addStep(RunJavaScriptCoreTests)
669 if platform.startswith("chromium"):
670 self.addStep(RunChromiumWebKitUnitTests)
671 self.addStep(self.TestClass)
672 if unitTestsSupported(configuration, platform):
673 self.addStep(RunUnitTests)
674 self.addStep(RunPythonTests)
675 # Chromium Win runs in non-Cygwin environment, which is not yet fit
676 # for running tests. This can be removed once bug 48166 is fixed.
677 if platform != "chromium-win":
678 self.addStep(RunPerlTests)
679 self.addStep(RunBindingsTests)
680 self.addStep(ArchiveTestResults)
681 self.addStep(UploadTestResults)
682 self.addStep(self.ExtractTestResultsClass)
683 if platform == "gtk":
684 self.addStep(RunGtkAPITests)
686 self.addStep(RunQtAPITests)
688 class BuildAndTestLeaksFactory(BuildAndTestFactory):
689 TestClass = RunWebKitLeakTests
690 ExtractTestResultsClass = ExtractTestResultsAndLeaks
692 class NewBuildAndTestFactory(BuildAndTestFactory):
693 TestClass = NewRunWebKitTests
695 class TestWebKit2Factory(TestFactory):
696 TestClass = RunWebKit2Tests
698 class PlatformSpecificScheduler(AnyBranchScheduler):
699 def __init__(self, platform, branch, **kwargs):
700 self.platform = platform
701 filter = ChangeFilter(branch=[branch, None], filter_fn=self.filter)
702 AnyBranchScheduler.__init__(self, name=platform, change_filter=filter, **kwargs)
704 def filter(self, change):
705 return wkbuild.should_build(self.platform, change.files)
707 trunk_filter = ChangeFilter(branch=["trunk", None])
709 def loadBuilderConfig(c):
710 # FIXME: These file handles are leaked.
711 passwords = simplejson.load(open('passwords.json'))
712 config = simplejson.load(open('config.json'))
714 # use webkitpy's buildbot module to test for core builders
717 c['slaves'] = [BuildSlave(slave['name'], passwords[slave['name']], max_builds=1) for slave in config['slaves']]
720 for scheduler in config['schedulers']:
721 if "change_filter" in scheduler:
722 scheduler["change_filter"] = globals()[scheduler["change_filter"]]
723 kls = globals()[scheduler.pop('type')]
724 # Python 2.6 can't handle unicode keys as keyword arguments:
725 # http://bugs.python.org/issue2646. Modern versions of simplejson return
726 # unicode strings from simplejson.load, so we map all keys to str objects.
727 scheduler = dict(map(lambda key_value_pair: (str(key_value_pair[0]), key_value_pair[1]), scheduler.items()))
729 # BaseScheduler asserts if given unicode objects instead of strs.
730 # http://trac.buildbot.net/ticket/2075
731 scheduler['builderNames'] = map(str, scheduler['builderNames'])
732 c['schedulers'].append(kls(**scheduler))
735 for builder in config['builders']:
736 for slaveName in builder['slavenames']:
737 for slave in config['slaves']:
738 if slave['name'] != slaveName or slave['platform'] == '*':
741 if slave['platform'] != builder['platform']:
742 raise Exception, "Builder %r is for platform %r but has slave %r for platform %r!" % (builder['name'], builder['platform'], slave['name'], slave['platform'])
746 factory = globals()["%sFactory" % builder.pop('type')]
748 for key in "platform", "configuration", "architectures", "triggers":
749 value = builder.pop(key, None)
751 factoryArgs.append(value)
754 "features": builder.pop("features", []),
755 "upload": builder.pop("upload", False)
758 builder["factory"] = factory(*factoryArgs, **factoryKwArgs)
760 builder["category"] = "noncore"
761 if wkbb._is_core_builder(builder['name']):
762 builder["category"] = "core"
764 c['builders'].append(builder)
768 c['change_source'] = PBChangeSource()
770 # permissions for WebStatus
773 forceAllBuilds=False,
775 gracefulShutdown=False,
778 cancelPendingBuild=True,
783 c['status'].append(html.WebStatus(http_port=8710,
784 revlink="http://trac.webkit.org/changeset/%s",
787 c['slavePortnum'] = 17000
788 c['projectName'] = "WebKit"
789 c['projectURL'] = "http://webkit.org"
790 c['buildbotURL'] = "http://build.webkit.org/"
792 c['buildHorizon'] = 1000
793 c['logHorizon'] = 500
794 c['eventHorizon'] = 200
795 c['buildCacheSize'] = 60