[pypy-commit] buildbot numpy-tests: merge default into branch
mattip
noreply at buildbot.pypy.org
Mon Nov 4 16:37:42 CET 2013
Author: Matti Picus <matti.picus at gmail.com>
Branch: numpy-tests
Changeset: r871:c4230f19bdf0
Date: 2013-11-04 09:51 +0200
http://bitbucket.org/pypy/buildbot/changeset/c4230f19bdf0/
Log: merge default into branch
diff too long, truncating to 2000 out of 2554 lines
diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -34,3 +34,5 @@
*-win-32
*-win-x86-32
*-win-x86-64
+slave/pypy-buildbot
+master/pypy-buildbot
diff --git a/README b/README
--- a/README
+++ b/README
@@ -1,7 +1,6 @@
.. -*- mode: rst -*-
-Everything has been tested with builbot 0.7.12. Not sure what happens with
-other versions :-)
+Everything has been tested with builbot 0.8.8.
How to hack the PyPy buildbot
==============================
@@ -24,12 +23,12 @@
If you want to run buildbot in production, you need to make sure that the
function ``pypybuildbot.util.we_are_debugging`` returns ``False`` in your
environment. At the moment of writing, debugging is enabled everywhere but on
-wyvern.
+cobra.
You still need to fill ``master/slaveinfo.py`` with the passwords of the
various slaves you want to use.
-Then, to start the buildbot master: ``cd master; make start``
+Then, to start the buildbot master: ``buildbot start <path-to pypy-buildbot/master>``
To restart the buildmaster
@@ -43,13 +42,13 @@
$ buildbot checkconfig
-$ make reconfig
+$ buildbot reconfig
OR
-$ make stop
+$ buildbot stop
-$ make start
+$ buildbot start
To run a buildslave
===================
diff --git a/bbhook/main.py b/bbhook/main.py
--- a/bbhook/main.py
+++ b/bbhook/main.py
@@ -38,8 +38,9 @@
@app.route('/', methods=['POST'])
def handle_payload():
- payload = json.loads(flask.request.form['payload'])
+ open('/tmp/payload', 'w').write(flask.request.form['payload'])
try:
+ payload = json.loads(flask.request.form['payload'])
from . import hook
hook.handle(payload, test=app.testing)
except:
diff --git a/bot2/pypybuildbot/arm_master.py b/bot2/pypybuildbot/arm_master.py
--- a/bot2/pypybuildbot/arm_master.py
+++ b/bot2/pypybuildbot/arm_master.py
@@ -56,7 +56,8 @@
+ crosstranslationjitargs),
platform='linux-armhf-raring',
interpreter='pypy',
- prefix=['schroot', '-c', 'raring'])
+ prefix=['schroot', '-c', 'raring'],
+ trigger='JITLINUXARMHF_RARING_scheduler')
pypyARMJITTranslatedTestFactory = pypybuilds.TranslatedTests(
translationArgs=(crosstranslationargs
@@ -89,7 +90,17 @@
app_tests=True,
platform='linux-armhf-raspbian',
)
+pypyARMHF_RARING_JITTranslatedTestFactory = pypybuilds.TranslatedTests(
+ translationArgs=(crosstranslationargs
+ + jit_translation_args
+ + crosstranslationjitargs),
+ lib_python=True,
+ pypyjit=True,
+ app_tests=True,
+ platform='linux-armhf-raring',
+ )
#
+LINUXARMHF = "own-linux-armhf"
APPLVLLINUXARM = "pypy-c-app-level-linux-armel"
APPLVLLINUXARMHF_v7 = "pypy-c-app-level-linux-armhf-v7"
APPLVLLINUXARMHF_RASPBIAN = "pypy-c-app-level-linux-armhf-raspbian"
@@ -97,6 +108,7 @@
JITLINUXARM = "pypy-c-jit-linux-armel"
JITLINUXARMHF_v7 = "pypy-c-jit-linux-armhf-v7"
JITLINUXARMHF_RASPBIAN = "pypy-c-jit-linux-armhf-raspbian"
+JITLINUXARMHF_RARING = "pypy-c-jit-linux-armhf-raring"
JITBACKENDONLYLINUXARMEL = "jitbackendonly-own-linux-armel"
JITBACKENDONLYLINUXARMHF = "jitbackendonly-own-linux-armhf"
@@ -109,6 +121,22 @@
BUILDJITLINUXARMHF_RASPBIAN = "build-pypy-c-jit-linux-armhf-raspbian"
BUILDJITLINUXARMHF_RARING = "build-pypy-c-jit-linux-armhf-raring"
+builderNames = [
+ LINUXARMHF,
+ APPLVLLINUXARM,
+ APPLVLLINUXARMHF_v7,
+ APPLVLLINUXARMHF_RASPBIAN,
+ JITLINUXARM,
+ JITLINUXARMHF_v7,
+ JITLINUXARMHF_RASPBIAN,
+ JITBACKENDONLYLINUXARMEL,
+ JITBACKENDONLYLINUXARMHF,
+ JITBACKENDONLYLINUXARMHF_v7,
+ BUILDLINUXARM,
+ BUILDJITLINUXARM,
+ BUILDLINUXARMHF_RASPBIAN,
+ BUILDJITLINUXARMHF_RASPBIAN,
+]
schedulers = [
Nightly("nighly-arm-0-00", [
@@ -119,6 +147,8 @@
BUILDLINUXARM, # on hhu-cross-armel, uses 1 core
BUILDLINUXARMHF_RASPBIAN, # on hhu-cross-raspbianhf, uses 1 core
+ LINUXARMHF, # onw tests on greenbox3-node0
+
JITBACKENDONLYLINUXARMEL, # on hhu-imx.53
JITBACKENDONLYLINUXARMHF,
JITBACKENDONLYLINUXARMHF_v7, # on cubieboard-bob
@@ -140,6 +170,10 @@
JITLINUXARMHF_RASPBIAN, # triggered by BUILDJITLINUXARMHF_RASPBIAN
JITLINUXARMHF_v7, # triggered by BUILDJITLINUXARMHF_RASPBIAN, on cubieboard-bob
]),
+
+ Triggerable("JITLINUXARMHF_RARING_scheduler", [
+ JITLINUXARMHF_RARING, # triggered by BUILDJITLINUXARMHF_RARING
+ ])
]
builders = [
@@ -163,6 +197,12 @@
"locks": [ARMBoardLock.access('counting')],
},
## armv7
+ {"name": LINUXARMHF,
+ "slavenames": ["greenbox3-node0"],
+ "builddir": LINUXARMHF,
+ "factory": pypyOwnTestFactoryARM,
+ "category": 'linux-armhf',
+ },
{"name": JITBACKENDONLYLINUXARMHF_v7,
"slavenames": ['cubieboard-bob'],
"builddir": JITBACKENDONLYLINUXARMHF_v7,
@@ -216,6 +256,12 @@
'category': 'linux-armhf',
"locks": [ARMBoardLock.access('counting')],
},
+ {"name": JITLINUXARMHF_RARING,
+ "slavenames": ["greenbox3-node0"],
+ 'builddir': JITLINUXARMHF_RARING,
+ 'factory': pypyARMHF_RARING_JITTranslatedTestFactory,
+ 'category': 'linux-armhf',
+ },
# Translation Builders for ARM
{"name": BUILDLINUXARM,
"slavenames": ['hhu-cross-armel'],
diff --git a/bot2/pypybuildbot/builds.py b/bot2/pypybuildbot/builds.py
--- a/bot2/pypybuildbot/builds.py
+++ b/bot2/pypybuildbot/builds.py
@@ -1,9 +1,12 @@
+from buildbot.steps.source.mercurial import Mercurial
+from buildbot.process.buildstep import BuildStep
from buildbot.process import factory
from buildbot.steps import shell, transfer
from buildbot.steps.trigger import Trigger
from buildbot.process.properties import WithProperties
from buildbot import locks
from pypybuildbot.util import symlink_force
+from buildbot.status.results import SKIPPED, SUCCESS
import os
# buildbot supports SlaveLocks, which can be used to limit the amout of builds
@@ -27,10 +30,7 @@
# while the boards can only run one job at the same time
ARMBoardLock = locks.SlaveLock('arm_boards', maxCount=1)
-
-# XXX monkey patch Trigger class, there are to issues with the list of renderables
-# original: Trigger.renderables = [ 'set_propetries', 'scheduler', 'sourceStamp' ]
-Trigger.renderables = [ 'set_properties', 'schedulerNames', 'sourceStamp' ]
+map_branch_name = lambda x: x if x not in ['', None, 'default'] else 'trunk'
class ShellCmd(shell.ShellCommand):
# our own version that can distinguish abort cases (rc == -1)
@@ -47,9 +47,7 @@
def start(self):
properties = self.build.getProperties()
- branch = properties['branch']
- if branch is None:
- branch = 'trunk'
+ branch = map_branch_name(properties['branch'])
#masterdest = properties.render(self.masterdest)
masterdest = os.path.expanduser(self.masterdest)
if branch.startswith('/'):
@@ -86,21 +84,18 @@
def start(self):
properties = self.build.getProperties()
- branch = properties['branch']
- revision = properties['revision']
-
- if branch is None:
- branch = 'trunk'
+ branch = map_branch_name(properties['branch'])
+ revision = properties['final_file_name']
mastersrc = os.path.expanduser(self.mastersrc)
if branch.startswith('/'):
branch = branch[1:]
mastersrc = os.path.join(mastersrc, branch)
- if revision is not None:
+ if revision:
basename = WithProperties(self.basename).getRenderingFor(self.build)
basename = basename.replace(':', '-')
else:
- basename = self.basename.replace('%(revision)s', 'latest')
+ basename = self.basename.replace('%(final_file_name)s', 'latest')
assert '%' not in basename
self.mastersrc = os.path.join(mastersrc, basename)
@@ -161,9 +156,7 @@
builder.summary_by_branch_and_revision = {}
try:
rev = properties['got_revision']
- branch = properties['branch']
- if branch is None:
- branch = 'trunk'
+ branch = map_branch_name(properties['branch'])
if branch.endswith('/'):
branch = branch[:-1]
except KeyError:
@@ -177,31 +170,21 @@
builder.saveYourself()
# _______________________________________________________________
-
-class UpdateCheckout(ShellCmd):
- description = 'hg update'
- command = 'UNKNOWN'
-
- def __init__(self, workdir=None, haltOnFailure=True, force_branch=None,
- **kwargs):
- ShellCmd.__init__(self, workdir=workdir, haltOnFailure=haltOnFailure,
- **kwargs)
- self.force_branch = force_branch
- self.addFactoryArguments(force_branch=force_branch)
-
- def start(self):
- if self.force_branch is not None:
- branch = self.force_branch
- # Note: We could add a warning to the output if we
- # ignore the branch set by the user.
- else:
- properties = self.build.getProperties()
- branch = properties['branch'] or 'default'
- command = ["hg", "update", "--clean", "-r", branch]
- self.setCommand(command)
- ShellCmd.start(self)
-
-
+# XXX Currently the build properties got_revision and final_file_name contain
+# the revision number and the changeset-id, CheckGotRevision takes care to set
+# the corresponding build properties
+# rev:changeset for got_revision
+# rev-changeset for final_file_name
+#
+# The rev part of got_revision and filename is used everywhere to sort the
+# builds, i.e. on the summary and download pages.
+#
+# The rev part is strictly local and needs to be removed from the SourceStamp,
+# at least for decoupled builds, which is what ParseRevision does.
+#
+# XXX in general it would be nice to drop the revision-number using only the
+# changeset-id for got_revision and final_file_name and sorting the builds
+# chronologically
class UpdateGitCheckout(ShellCmd):
description = 'git checkout'
command = 'UNKNOWN'
@@ -244,12 +227,51 @@
# ':' should not be part of filenames --- too many issues
self.build.setProperty('got_revision', got_revision,
'got_revision')
- self.build.setProperty('final_file_name', final_file_name,
- 'got_revision')
+ if not self.build.hasProperty('final_file_name'):
+ self.build.setProperty('final_file_name', final_file_name,
+ 'got_revision')
+class ParseRevision(BuildStep):
+ """Parse the revision property of the source stamp and extract the global
+ part of the revision
+ 123:3a34 -> 3a34"""
+ name = "parse_revision"
-def update_hg(platform, factory, repourl, workdir, use_branch,
- force_branch=None):
+ def __init__(self, *args, **kwargs):
+ BuildStep.__init__(self, *args, **kwargs)
+
+ @staticmethod
+ def hideStepIf(results, step):
+ return results==SKIPPED
+
+ @staticmethod
+ def doStepIf(step):
+ revision = step.build.getSourceStamp().revision
+ return isinstance(revision, (unicode, str)) and ':' in revision
+
+ def start(self):
+ stamp = self.build.getSourceStamp()
+ revision = stamp.revision if stamp.revision is not None else ''
+ #
+ if not isinstance(revision, (unicode, str)) or ":" not in revision:
+ self.finished(SKIPPED)
+ return
+ #
+ self.build.setProperty('original_revision', revision, 'parse_revision')
+ self.build.setProperty('final_file_name',
+ revision.replace(':', '-'), 'parse_revision')
+ #
+ parts = revision.split(':')
+ self.build.setProperty('revision', parts[1], 'parse_revision')
+ stamp.revision = parts[1]
+ self.finished(SUCCESS)
+
+
+def update_hg_old_method(platform, factory, repourl, workdir):
+ # baaaaaah. Seems that the Mercurial class doesn't support
+ # updating to a different branch than the one specified by
+ # the user (like "default"). This is nonsense if we need
+ # an auxiliary check-out :-( At least I didn't find how.
if platform == 'win32':
command = "if not exist .hg rmdir /q /s ."
else:
@@ -280,14 +302,27 @@
command="hg pull",
workdir=workdir))
#
- if use_branch or force_branch:
- factory.addStep(UpdateCheckout(workdir=workdir,
- haltOnFailure=True,
- force_branch=force_branch))
- else:
- factory.addStep(ShellCmd(description="hg update",
- command=WithProperties("hg update --clean %(revision)s"),
- workdir=workdir))
+ # here, update without caring about branches
+ factory.addStep(ShellCmd(description="hg update",
+ command=WithProperties("hg update --clean %(revision)s"),
+ workdir=workdir))
+
+def update_hg(platform, factory, repourl, workdir, use_branch,
+ force_branch=None):
+ if not use_branch:
+ assert force_branch is None
+ update_hg_old_method(platform, factory, repourl, workdir)
+ return
+ factory.addStep(
+ Mercurial(
+ repourl=repourl,
+ mode='full',
+ method='fresh',
+ defaultBranch=force_branch,
+ branchType='inrepo',
+ clobberOnBranchChange=False,
+ workdir=workdir,
+ logEnviron=False))
def update_git(platform, factory, repourl, workdir, use_branch,
force_branch=None):
@@ -340,11 +375,15 @@
# for debugging
repourl = '/home/antocuni/pypy/default'
#
+ factory.addStep(ParseRevision(hideStepIf=ParseRevision.hideStepIf,
+ doStepIf=ParseRevision.doStepIf))
+ #
update_hg(platform, factory, repourl, workdir, use_branch=True,
force_branch=force_branch)
#
factory.addStep(CheckGotRevision(workdir=workdir))
+
def build_name(platform, jit=False, flags=[], placeholder=None):
if placeholder is None:
placeholder = '%(final_file_name)s'
@@ -524,7 +563,7 @@
command=['rm', '-rf', 'pypy-c'],
workdir='.'))
extension = get_extension(platform)
- name = build_name(platform, pypyjit, translationArgs, placeholder='%(revision)s') + extension
+ name = build_name(platform, pypyjit, translationArgs, placeholder='%(final_file_name)s') + extension
self.addStep(PyPyDownload(
basename=name,
mastersrc='~/nightly',
@@ -538,22 +577,37 @@
self.addStep(ShellCmd(
description="decompress pypy-c",
command=['tar', '--extract', '--file=pypy_build'+ extension, '--strip-components=1', '--directory=.'],
- workdir='pypy-c'))
+ workdir='pypy-c',
+ haltOnFailure=True,
+ ))
+ self.addStep(ShellCmd(
+ description="reset permissions",
+ command=['chmod', 'u+rw', '-R', 'build/include'],
+ haltOnFailure=True,
+ workdir='.'))
# copy pypy-c to the expected location within the pypy source checkout
self.addStep(ShellCmd(
description="move pypy-c",
command=['cp', '-v', 'pypy-c/bin/pypy', 'build/pypy/goal/pypy-c'],
+ haltOnFailure=True,
workdir='.'))
# copy generated and copied header files to build/include
self.addStep(ShellCmd(
description="move header files",
command=['cp', '-vr', 'pypy-c/include', 'build'],
+ haltOnFailure=True,
workdir='.'))
# copy ctypes_resource_cache generated during translation
self.addStep(ShellCmd(
+ description="reset permissions",
+ command=['chmod', 'u+rw', '-R', 'build/lib_pypy'],
+ haltOnFailure=True,
+ workdir='.'))
+ self.addStep(ShellCmd(
description="move ctypes resource cache",
command=['cp', '-rv', 'pypy-c/lib_pypy/ctypes_config_cache', 'build/lib_pypy'],
+ haltOnFailure=True,
workdir='.'))
add_translated_tests(self, prefix, platform, app_tests, lib_python, pypyjit)
@@ -578,6 +632,7 @@
command=prefix + ["python", "pypy/tool/release/package.py",
".", WithProperties(name), 'pypy',
'.'],
+ haltOnFailure=True,
workdir='build'))
nightly = '~/nightly/'
extension = get_extension(platform)
@@ -587,7 +642,7 @@
basename=name + extension,
workdir='.',
blocksize=100 * 1024))
- if trigger: # if provided trigger schedulers that are depend on this one
+ if trigger: # if provided trigger schedulers that depend on this one
self.addStep(Trigger(schedulerNames=[trigger]))
@@ -595,10 +650,11 @@
def __init__(self, platform='linux', host='tannit', postfix=''):
factory.BuildFactory.__init__(self)
- setup_steps(platform, self)
#
repourl = 'https://bitbucket.org/pypy/benchmarks'
update_hg(platform, self, repourl, 'benchmarks', use_branch=False)
+ #
+ setup_steps(platform, self)
if host == 'tannit':
lock = TannitCPU
elif host == 'speed_python':
@@ -676,14 +732,14 @@
'''
factory.BuildFactory.__init__(self)
+ # check out and update benchmarks
+ repourl = 'https://bitbucket.org/pypy/benchmarks'
+ update_hg(platform, self, repourl, 'benchmarks', use_branch=False)
+
# checks out and updates the repo
setup_steps(platform, self, repourl='http://hg.python.org/cpython',
force_branch=branch)
- # check out and update benchmarks
- repourl = 'https://bitbucket.org/pypy/benchmarks'
- update_hg(platform, self, repourl, 'benchmarks', use_branch=False)
-
lock = SpeedPythonCPU
self.addStep(ShellCmd(
@@ -736,6 +792,39 @@
masterdest=WithProperties(resultfile),
workdir="."))
+class PyPyBuildbotTestFactory(factory.BuildFactory):
+ def __init__(self):
+ factory.BuildFactory.__init__(self)
+ # clone
+ self.addStep(
+ Mercurial(
+ repourl='https://bitbucket.org/pypy/buildbot',
+ mode='incremental',
+ method='fresh',
+ defaultBranch='default',
+ branchType='inrepo',
+ clobberOnBranchChange=False,
+ logEnviron=False))
+ # create a virtualenv
+ self.addStep(ShellCmd(
+ description='create virtualenv',
+ haltOnFailure=True,
+ command='virtualenv ../venv'))
+ # install deps
+ self.addStep(ShellCmd(
+ description="install dependencies",
+ haltOnFailure=True,
+ command=('../venv/bin/pip install -r requirements.txt').split()))
+ # run tests
+ self.addStep(PytestCmd(
+ description="pytest buildbot",
+ haltOnFailure=True,
+ command=["../venv/bin/py.test",
+ "--resultlog=testrun.log",
+ ],
+ logfiles={'pytestLog': 'testrun.log'}))
+
+
class NativeNumpyTests(factory.BuildFactory):
'''
Download a pypy nightly, install nose and numpy, and run the numpy test suite
diff --git a/bot2/pypybuildbot/ircbot.py b/bot2/pypybuildbot/ircbot.py
--- a/bot2/pypybuildbot/ircbot.py
+++ b/bot2/pypybuildbot/ircbot.py
@@ -7,54 +7,64 @@
the customized IRC messages.
"""
-import re
-from buildbot.status.words import Contact, IRC, log
+from buildbot.status.words import IRC, log, IRCContact
+# see http://www.mirc.com/colors.html
USE_COLOR_CODES = True
-GREEN = '\x033'
-RED = '\x034'
-AZURE = '\x0311'
-BLUE = '\x0312'
-PURPLE = '\x0313'
-GRAY = '\x0315'
-BOLD = '\x02'
-def color(code, s):
+BOLD = '\x02'
+COLORS = {
+ 'WHITE': '\x030',
+ 'BLACK': '\x031',
+ 'GREEN': '\x033',
+ 'RED': '\x034',
+ 'AZURE': '\x0311',
+ 'BLUE': '\x0312',
+ 'PURPLE': '\x0313',
+ 'GRAY': '\x0315',
+}
+
+
+def color(s, code=None, bold=False):
if USE_COLOR_CODES:
- return '%s%s\x0F' % (code, s)
+ c = BOLD if bold else ''
+ if code in COLORS:
+ c += COLORS[code]
+ return '%s%s\x0F' % (c, s)
return s
-def extract_username(build):
- regexp = r"The web-page 'force build' button was pressed by '(.*)': .*"
- match = re.match(regexp, build.getReason())
- if match:
- return match.group(1)
- return None
+
+def get_build_information(build):
+ owner = build.getProperty("owner")
+ reason = build.getProperty("reason")
+ return ": ".join(k for k in (owner, reason) if k)
def get_description_for_build(url, build):
- url = color(GRAY, url) # in gray
+ url = color(url, 'GRAY') # in gray
infos = []
- username = extract_username(build)
- if username:
- infos.append(color(BLUE, username)) # in blue
+ buildinfo = get_build_information(build)
+ if buildinfo:
+ infos.append(color(buildinfo, 'BLUE')) # in blue
#
- branch = build.source.branch
+ branch = build.getProperty('branch')
if branch:
- infos.append(color(BOLD, branch)) # in bold
+ infos.append(color(branch, bold=True)) # in bold
#
if infos:
return '%s [%s]' % (url, ', '.join(infos))
else:
return url
+
def buildStarted(self, builderName, build):
builder = build.getBuilder()
- log.msg('[Contact] Builder %r in category %s started' % (builder, builder.category))
+ log.msg('[Contact] Builder %r in category %s started' %
+ (builder, builder.category))
# only notify about builders we are interested in
- if (self.channel.categories != None and
- builder.category not in self.channel.categories):
+ if (self.bot.categories is not None and
+ builder.category not in self.bot.categories):
log.msg('Not notifying for a build in the wrong category')
return
@@ -62,7 +72,7 @@
log.msg('Not notifying for a build when started-notification disabled')
return
- buildurl = self.channel.status.getURLForThing(build)
+ buildurl = self.bot.status.getURLForThing(build)
descr = get_description_for_build(buildurl, build)
msg = "Started: %s" % descr
self.send(msg)
@@ -72,29 +82,28 @@
builder = build.getBuilder()
# only notify about builders we are interested in
- log.msg('[Contact] builder %r in category %s finished' % (builder, builder.category))
+ log.msg('[Contact] builder %r in category %s finished' %
+ (builder, builder.category))
- if (self.channel.categories != None and
- builder.category not in self.channel.categories):
+ if (self.bot.categories is not None and
+ builder.category not in self.bot.categories):
return
if not self.notify_for_finished(build):
return
- buildurl = self.channel.status.getURLForThing(build)
+ buildurl = self.bot.status.getURLForThing(build)
descr = get_description_for_build(buildurl, build)
- result = self.results_descriptions.get(build.getResults(), "Finished ??")
- if result == 'Success':
- result = color(BOLD+GREEN, result)
- elif result == 'Exception':
- result = color(BOLD+PURPLE, result)
- else:
- result = color(BOLD+RED, result)
+ result, c = self.results_descriptions.get(build.getResults(),
+ ("Finished ??", 'RED'))
+ if c not in COLORS:
+ c = 'RED'
+ result = color(result, c, bold=True)
msg = "%s: %s" % (result, descr)
self.send(msg)
-Contact.buildStarted = buildStarted
-Contact.buildFinished = buildFinished
+IRCContact.buildStarted = buildStarted
+IRCContact.buildFinished = buildFinished
## def send_message(message, test=False):
diff --git a/bot2/pypybuildbot/master.py b/bot2/pypybuildbot/master.py
--- a/bot2/pypybuildbot/master.py
+++ b/bot2/pypybuildbot/master.py
@@ -1,25 +1,22 @@
import os
-import getpass
-from buildbot.scheduler import Nightly, Triggerable
+from buildbot.scheduler import Nightly
+from buildbot.schedulers.forcesched import ForceScheduler
+from buildbot.schedulers.forcesched import ValidationError
from buildbot.buildslave import BuildSlave
from buildbot.status.html import WebStatus
-from buildbot.process.builder import Builder
#from buildbot import manhole
from pypybuildbot.pypylist import PyPyList, NumpyStatusList
-from pypybuildbot.ircbot import IRC # side effects
+from pypybuildbot.ircbot import IRC # side effects
from pypybuildbot.util import we_are_debugging
# Forbid "force build" with empty user name
-from buildbot.status.web.builder import StatusResourceBuilder
-def my_force(self, req, *args, **kwds):
- name = req.args.get("username", [""])[0]
- assert name, "Please write your name in the corresponding field."
- return _previous_force(self, req, *args, **kwds)
-_previous_force = StatusResourceBuilder.force
-if _previous_force.__name__ == 'force':
- StatusResourceBuilder.force = my_force
-# Done
+class CustomForceScheduler(ForceScheduler):
+ def force(self, owner, builder_name, **kwargs):
+ if not owner:
+ raise ValidationError, "Please write your name in the corresponding field."
+ return ForceScheduler.force(self, owner, builder_name, **kwargs)
+
if we_are_debugging():
channel = '#buildbot-test'
@@ -172,6 +169,7 @@
JITLINUX32 = "pypy-c-jit-linux-x86-32"
JITLINUX64 = "pypy-c-jit-linux-x86-64"
JITMACOSX64 = "pypy-c-jit-macosx-x86-64"
+JITMACOSX64_2 = "pypy-c-jit-macosx-x86-64-2"
JITWIN32 = "pypy-c-jit-win-x86-32"
JITWIN64 = "pypy-c-jit-win-x86-64"
JITFREEBSD764 = 'pypy-c-jit-freebsd-7-x86-64'
@@ -185,6 +183,8 @@
JITBENCH64_2 = 'jit-benchmark-linux-x86-64-2'
CPYTHON_64 = "cpython-2-benchmark-x86-64"
NUMPY_64 = "numpy-compatability-linux-x86-64"
+# buildbot builder
+PYPYBUILDBOT = 'pypy-buildbot'
extra_opts = {'xerxes': {'keepalive_interval': 15},
'aurora': {'max_builds': 1},
@@ -218,12 +218,14 @@
JITFREEBSD864, # on ananke
JITFREEBSD964, # on exarkun's freebsd
JITMACOSX64, # on xerxes
- ], branch=None, hour=0, minute=0),
+ # buildbot selftest
+ PYPYBUILDBOT # on cobra
+ ], branch='default', hour=0, minute=0),
Nightly("nightly-2-00", [
JITBENCH, # on tannit32, uses 1 core (in part exclusively)
JITBENCH64, # on tannit64, uses 1 core (in part exclusively)
- ], branch=None, hour=2, minute=0),
+ ], branch='default', hour=2, minute=0),
Nightly("nightly-2-00-py3k", [
LINUX64, # on allegro64, uses all cores
@@ -233,6 +235,38 @@
Nightly("nighly-ppc", [
JITONLYLINUXPPC64, # on gcc1
], branch='ppc-jit-backend', hour=1, minute=0),
+ CustomForceScheduler('Force Scheduler',
+ builderNames=[
+ PYPYBUILDBOT,
+ LINUX32,
+ LINUX64,
+ INDIANA32,
+
+ MACOSX32,
+ WIN32,
+ WIN64,
+ APPLVLLINUX32,
+ APPLVLLINUX64,
+ APPLVLWIN32,
+
+ LIBPYTHON_LINUX32,
+ LIBPYTHON_LINUX64,
+
+ JITLINUX32,
+ JITLINUX64,
+ JITMACOSX64,
+ JITMACOSX64_2,
+ JITWIN32,
+ JITWIN64,
+ JITFREEBSD764,
+ JITFREEBSD864,
+ JITFREEBSD964,
+ JITINDIANA32,
+
+ JITONLYLINUXPPC64,
+ JITBENCH,
+ JITBENCH64,
+ ] + ARM.builderNames, properties=[]),
] + ARM.schedulers,
'status': [status, ircbot],
@@ -322,11 +356,17 @@
"category": 'mac32'
},
{"name" : JITMACOSX64,
- "slavenames": ["xerxes"],
+ "slavenames": ["xerxes", "tosh"],
'builddir' : JITMACOSX64,
'factory' : pypyJITTranslatedTestFactoryOSX64,
'category' : 'mac64',
},
+ {"name" : JITMACOSX64_2,
+ "slavenames": ["xerxes", "tosh"],
+ 'builddir' : JITMACOSX64_2,
+ 'factory' : pypyJITTranslatedTestFactoryOSX64,
+ 'category' : 'mac64',
+ },
{"name": WIN32,
"slavenames": ["aurora", "SalsaSalsa"],
"builddir": WIN32,
@@ -401,6 +441,13 @@
'factory': pypyNumpyCompatability,
'category': 'numpy',
},
+ {'name': PYPYBUILDBOT,
+ 'slavenames': ['cobra'],
+ 'builddir': PYPYBUILDBOT,
+ 'factory': pypybuilds.PyPyBuildbotTestFactory(),
+ 'category': 'buildbot',
+ }
+
] + ARM.builders,
# http://readthedocs.org/docs/buildbot/en/latest/tour.html#debugging-with-manhole
diff --git a/bot2/pypybuildbot/summary.py b/bot2/pypybuildbot/summary.py
--- a/bot2/pypybuildbot/summary.py
+++ b/bot2/pypybuildbot/summary.py
@@ -374,7 +374,7 @@
def _start_cat_branch(self, cat_branch, fine=False):
category, branch = cat_branch
- branch = trunk_name(branch)
+ branch = meta_branch_name(branch)
category = category_name(category)
self.cur_cat_branch = (category, branch)
@@ -615,14 +615,19 @@
return lambda v: v in membs
def make_subst(v1, v2):
+ if not isinstance(v1, list):
+ v1 = [v1]
def subst(v):
- if v == v1:
+ if v in v1:
return v2
return v
return subst
-trunk_name = make_subst(None, "<trunk>")
-trunk_value = make_subst("<trunk>", None)
+# Map certain branch names from SourceStamps to a common name shown on the page
+meta_branch_name = make_subst(['default', '', None], '<trunk>')
+# map the meta-branch <trunk> to the actual branch entries from the
+# SourceStamp
+default_value = make_subst('<trunk>', ['default', '', None])
category_name = make_subst(None, '-')
nocat_value = make_subst("-", None)
@@ -661,8 +666,7 @@
def getTitle(self, request):
status = self.getStatus(request)
- return "%s: summaries of last %d revisions" % (status.getProjectName(),
- N)
+ return "%s: summaries of last %d revisions" % (status.getTitle(), N)
@staticmethod
def _prune_runs(runs, cutnum):
@@ -686,8 +690,10 @@
except KeyError:
pass
builder = status.botmaster.builders[builderName]
+ factory = builder.config.factory
branch = None
- for _, kw in builder.buildFactory.steps:
+ for step in factory.steps:
+ kw = step.kwargs
if 'defaultBranch' in kw:
if kw.get('explicitBranch'):
branch = kw['defaultBranch']
@@ -722,7 +728,6 @@
only_builder or only_branches)
cat_branches = {}
-
for builderName in status.getBuilderNames(only_categories):
if not test_builder(builderName):
continue
@@ -740,6 +745,8 @@
for build in builditer:
if prune_old and self._age(build) > 7:
continue
+ if self._age(build) > 60: # two months old: prune anyway
+ continue
branch = self._get_branch(status, build)
if not test_branch(branch):
continue
@@ -747,6 +754,7 @@
if not test_rev(got_rev):
continue
+ branch = meta_branch_name(branch)
cat_branch = (builderStatus.category, branch)
runs, no_revision_builds = cat_branches.setdefault(cat_branch,
@@ -825,7 +833,13 @@
only_branches = request.args.get('branch', None)
only_recentrevs = request.args.get('recentrev', None)
if only_branches is not None:
- only_branches = map(trunk_value, only_branches)
+ branches = []
+ for x in map(default_value, only_branches):
+ if isinstance(x, str):
+ branches.append(x)
+ else:
+ branches.extend(x)
+ only_branches = branches
only_builder = request.args.get('builder', None)
only_builds = None
if only_builder is not None:
@@ -861,16 +875,16 @@
outcome_set_cache.stats()))
if request.args:
- trunk_vs_any_text = "filter nothing"
- trunk_vs_any_query = ""
+ default_vs_any_text = "filter nothing"
+ default_vs_any_query = ""
else:
- trunk_vs_any_text = "all <trunk>"
- trunk_vs_any_query = "?branch=<trunk>"
+ default_vs_any_text = "all <trunk>"
+ default_vs_any_query = "?branch=<trunk>"
- trunk_vs_any_anchor = html.a(trunk_vs_any_text,
+ default_vs_any_anchor = html.a(default_vs_any_text,
href="/summary%s" %
- trunk_vs_any_query,
+ default_vs_any_query,
class_="failSummary trunkVsAny")
- trunk_vs_any = html.div(trunk_vs_any_anchor,
+ default_vs_any = html.div(default_vs_any_anchor,
style="position: absolute; right: 5%;")
- return trunk_vs_any.unicode() + page.render()
+ return default_vs_any.unicode() + page.render()
diff --git a/bot2/pypybuildbot/test/test_builds.py b/bot2/pypybuildbot/test/test_builds.py
--- a/bot2/pypybuildbot/test/test_builds.py
+++ b/bot2/pypybuildbot/test/test_builds.py
@@ -4,53 +4,83 @@
class FakeProperties(object):
- def __init__(self):
- from buildbot.process.properties import PropertyMap
- self.pmap = PropertyMap(self)
-
+ sources = {}
+
+ def __init__(self, properties=None):
+ if properties is None:
+ self.properties = {'branch':None, 'got_revision': 123,
+ 'final_file_name': '123-ea5ca8'}
+ else:
+ self.properties = properties
+
def __getitem__(self, item):
- if item == 'branch':
- return None
- if item == 'got_revision':
- return 123
- if item == 'final_file_name':
- return '123-ea5ca8'
-
+ return self.properties.get(item)
+
+ def __setitem__(self, name, value):
+ self.properties[name] = value
+
def render(self, x):
return x
+class FakeSourceStamp(object):
+ def __init__(self, properties=None):
+ self.properties = properties if properties is not None else {}
+
+ def __getattr__(self, name):
+ return self.properties.get(name)
+
+ def __setattribute__(self, name, value):
+ self.properties[name] = value
+
class FakeBuild(object):
slaveEnvironment = None
- def __init__(self):
- self.properties = FakeProperties()
-
+ def __init__(self, properties=None):
+ self.properties = FakeProperties(properties)
+ self.source_stamp = FakeSourceStamp(properties)
+
def getProperties(self):
return self.properties
+ def setProperty(self, name, value, source):
+ self.properties[name] = value
+ self.properties.sources[name] = source
+
def getSlaveCommandVersion(self, *args):
return 3
+ def getSourceStamp(self, *args):
+ return self.source_stamp
+
class FakeStepStatus(object):
def setText(self, *args):
pass
+ def stepFinished(self, results):
+ self.results = results
+
+ def setHidden(self, *args):
+ pass
+
class FakeDeferred(object):
+ def callback(*args):
+ pass
def addCallback(self, *args):
return FakeDeferred()
def addErrback(self, *args):
return FakeDeferred()
def test_Translate():
- expected = ['translate.py', '--batch', '-O0',
+ expected = ['pypy', '../../rpython/bin/rpython', '--batch', '-O0',
'targetpypystandalone', '--no-allworkingmodules']
translateInst = builds.Translate(['-O0'], ['--no-allworkingmodules'])
assert translateInst.command[-len(expected):] == expected
- translateFactory, kw = translateInst.factory
- rebuiltTranslate = translateFactory(**kw)
+ translateFactory = translateInst._getStepFactory().factory
+ args = translateInst._getStepFactory().args
+ rebuiltTranslate = translateFactory(*args)
assert rebuiltTranslate.command[-len(expected):] == expected
@@ -64,7 +94,8 @@
inst = builds.PyPyUpload(slavesrc='slavesrc', masterdest=str(pth.join('mstr')),
basename='base-%(final_file_name)s', workdir='.',
blocksize=100)
- factory, kw = inst.factory
+ factory = inst._getStepFactory().factory
+ kw = inst._getStepFactory().kwargs
rebuilt = factory(**kw)
rebuilt.build = FakeBuild()
rebuilt.step_status = FakeStepStatus()
@@ -145,3 +176,36 @@
step.commandComplete(cmd)
summary = builder.summary_by_branch_and_revision[('trunk', '123')]
assert summary.to_tuple() == (2, 2, 4, 0)
+
+
+class TestParseRevision(object):
+
+ def setup_method(self, mth):
+ inst = builds.ParseRevision()
+ factory = inst._getStepFactory().factory
+ kw = inst._getStepFactory().kwargs
+ self.rebuilt = factory(**kw)
+ self.rebuilt.step_status = FakeStepStatus()
+ self.rebuilt.deferred = FakeDeferred()
+
+ def test_has_revision(self):
+ self.rebuilt.build = FakeBuild({'revision':u'123:ea5ca8'})
+ self.rebuilt.start()
+ assert self.rebuilt.build.getProperties()['revision'] == 'ea5ca8'
+ assert self.rebuilt.build.getProperties()['original_revision'] == '123:ea5ca8'
+ assert self.rebuilt.build.getProperties()['final_file_name'] == '123-ea5ca8'
+
+ def test_no_revision(self):
+ self.rebuilt.build = FakeBuild()
+ self.rebuilt.start()
+ assert self.rebuilt.build.getProperties()['revision'] is None
+
+ def test_revision_no_local_part(self):
+ self.rebuilt.build = FakeBuild({'revision':u'ea5ca8'})
+ self.rebuilt.start()
+ assert self.rebuilt.build.getProperties()['revision'] == 'ea5ca8'
+
+ def test_empty_revision(self):
+ self.rebuilt.build = FakeBuild({'revision':u''})
+ self.rebuilt.start()
+ assert self.rebuilt.build.getProperties()['revision'] == ''
diff --git a/bot2/pypybuildbot/test/test_ircbot.py b/bot2/pypybuildbot/test/test_ircbot.py
--- a/bot2/pypybuildbot/test/test_ircbot.py
+++ b/bot2/pypybuildbot/test/test_ircbot.py
@@ -1,50 +1,48 @@
from pypybuildbot import ircbot
+
def setup_module(mod):
ircbot.USE_COLOR_CODES = False
+
def teardown_module(mod):
ircbot.USE_COLOR_CODES = True
+
class FakeBuild(object):
- def __init__(self, reason=None, source=None):
- self.reason = reason
- self.source = source
+ def __init__(self, reason=None, owner=None, branch=None):
+ self.properties = {'owner': owner, 'branch': branch, 'reason': reason}
- def getReason(self):
- return self.reason
+ def getProperty(self, name):
+ return self.properties.get(name, None)
- def getSourceStamp(self):
- return self.source
-class FakeSource(object):
-
- def __init__(self, branch):
- self.branch = branch
-
-def test_extract_username():
- a = FakeBuild("The web-page 'force build' button was pressed by 'antocuni': foo")
+def test_get_build_information():
+ a = FakeBuild(owner='antocuni',
+ reason="The web-page 'force build' button was pressed")
b = FakeBuild("The web-page 'force build' button was ...")
- assert ircbot.extract_username(a) == 'antocuni'
- assert ircbot.extract_username(b) is None
+ assert ircbot.get_build_information(a) == \
+ "antocuni: The web-page 'force build' button was pressed"
+ assert ircbot.get_build_information(b) == \
+ "The web-page 'force build' button was ..."
def test_get_description_for_build():
- a = FakeBuild('foobar', source=FakeSource(None))
+ a = FakeBuild()
msg = ircbot.get_description_for_build("http://myurl", a)
assert msg == "http://myurl"
- a = FakeBuild("The web-page 'force build' button was pressed by 'antocuni': foo",
- source=FakeSource(None))
+ a = FakeBuild(owner='antocuni',
+ reason="The web-page 'force build' button was pressed")
msg = ircbot.get_description_for_build("http://myurl", a)
- assert msg == "http://myurl [antocuni]"
+ assert msg == "http://myurl [antocuni: " \
+ + "The web-page 'force build' button was pressed]"
- a = FakeBuild('foobar', source=FakeSource('mybranch'))
+ a = FakeBuild(branch='mybranch')
msg = ircbot.get_description_for_build("http://myurl", a)
assert msg == "http://myurl [mybranch]"
- a = FakeBuild("The web-page 'force build' button was pressed by 'antocuni': foo",
- source=FakeSource('mybranch'))
+ a = FakeBuild(owner='antocuni', branch='mybranch')
msg = ircbot.get_description_for_build("http://myurl", a)
assert msg == "http://myurl [antocuni, mybranch]"
diff --git a/bot2/pypybuildbot/test/test_pypylist.py b/bot2/pypybuildbot/test/test_pypylist.py
--- a/bot2/pypybuildbot/test/test_pypylist.py
+++ b/bot2/pypybuildbot/test/test_pypylist.py
@@ -78,18 +78,20 @@
newdir.setmtime(oldtime + ascii * 10)
pypylist = PyPyList(tmpdir.strpath)
listener = pypylist.directoryListing()
- assert listener.dirs == ['trunk', 'mmmm', 'llll',
+ assert listener.dirs == ['trunk', 'llll',
'kkkk','jjjj','iiii','hhhh','gggg','ffff','eeee',
'dddd','cccc','bbbb','aaaa']
def load_BuildmasterConfig():
import os
- from pypybuildbot import summary, builds
+ from pypybuildbot import summary, builds, arm_master
def load(name):
if name == 'pypybuildbot.summary':
return summary
elif name == 'pypybuildbot.builds':
return builds
+ elif name == 'pypybuildbot.arm_master':
+ return arm_master
else:
assert False
diff --git a/bot2/pypybuildbot/test/test_summary.py b/bot2/pypybuildbot/test/test_summary.py
--- a/bot2/pypybuildbot/test/test_summary.py
+++ b/bot2/pypybuildbot/test/test_summary.py
@@ -27,7 +27,7 @@
s a/b.py:test_three
S a/c.py:test_four
""")
-
+
rev_outcome_set.populate(log)
assert rev_outcome_set.skipped == set([("a.b","test_three"),
@@ -67,7 +67,7 @@
x a/c.py:test_nine
x a/c.py:test_ten
""")
-
+
rev_outcome_set.populate(log)
sum = rev_outcome_set.get_summary()
assert sum.p == 1
@@ -80,7 +80,7 @@
rev_outcome_set = summary.RevisionOutcomeSet('0')
log = StringIO("")
rev_outcome_set.populate(log)
-
+
def test_populate_longrepr(self):
rev_outcome_set = summary.RevisionOutcomeSet('50000')
log = StringIO("""F a/b.py:test_one
@@ -90,7 +90,7 @@
s a/b.py:test_three
some skip
""")
-
+
rev_outcome_set.populate(log)
assert len(rev_outcome_set.skipped) == 1
@@ -115,7 +115,7 @@
F a/b.py:test_two
\xc3\xa5 bar
""")
-
+
rev_outcome_set.populate(log)
assert len(rev_outcome_set.failed) == 2
@@ -133,7 +133,7 @@
! <run>
! /a/b/c.py:92
""")
-
+
rev_outcome_set.populate(log)
assert rev_outcome_set.failed == set([
@@ -151,12 +151,12 @@
log = StringIO("""x a/b.py
EXC
""")
-
+
rev_outcome_set.populate(log)
assert rev_outcome_set.numxfailed == 1
-
-
+
+
def test_absent_outcome(self):
rev_outcome_set = summary.RevisionOutcomeSet('50000')
@@ -169,7 +169,7 @@
def load(x, y):
calls.append(y)
return y
-
+
cache._load_outcome_set = load
res = cache.get('status', 'a')
@@ -183,14 +183,14 @@
cache.get('status', 'b')
res = cache.get('status', 'c')
assert res == 'c'
-
+
assert calls == ['a', 'b', 'c']
calls = []
res = cache.get('status', 'd')
assert res == 'd'
assert cache.get('status', 'c') == 'c'
- assert cache.get('status', 'b') == 'b'
+ assert cache.get('status', 'b') == 'b'
assert calls == ['d']
res = cache.get('status', 'a')
@@ -208,18 +208,18 @@
s a/b.py:test_three
x a/b.py:test_four
""")
-
+
rev_outcome_set_foo.populate(log)
- key_bar = ('bar', 7)
+ key_bar = ('bar', 7)
rev_outcome_set_bar = summary.RevisionOutcomeSet('50000',
key_bar)
log = StringIO(""". a/b.py:test_one
. a/b.py:test_two
s a/b.py:test_three
""")
-
+
rev_outcome_set_bar.populate(log)
d = {'foo': rev_outcome_set_foo,
@@ -228,7 +228,7 @@
goutcome = summary.GatherOutcomeSet(d)
assert goutcome.revision == '50000'
-
+
assert goutcome.failed == set([('foo', 'a.b', 'test_one')])
assert goutcome.skipped == set([('foo', 'a.b', 'test_three'),
@@ -273,14 +273,14 @@
assert res == ' '
res = goutcome_top.get_longrepr(('what', 'foo', 'a.b', 'test_one'))
- assert res == ''
+ assert res == ''
def test_colsizes():
failed = [('a', 'abc', 'd'), ('ab', 'c', 'xy'),
('ab', '', 'cd')]
-
+
res = summary.colsizes(failed)
-
+
assert res == [2,3,2]
def test__prune_runs():
@@ -330,15 +330,15 @@
res = summary.show_elapsed(0.25)
assert res == "0.25s"
res = summary.show_elapsed(1.0)
- assert res == "1.00s"
+ assert res == "1.00s"
res = summary.show_elapsed(1.25)
- assert res == "1.25s"
+ assert res == "1.25s"
res = summary.show_elapsed(4.5)
assert res == "4.50s"
res = summary.show_elapsed(5.25)
assert res == "5s"
res = summary.show_elapsed(5.5)
- assert res == "6s"
+ assert res == "6s"
res = summary.show_elapsed(2*60+30)
assert res == "2m30"
res = summary.show_elapsed(4*60+30)
@@ -348,22 +348,33 @@
res = summary.show_elapsed(61*60)
assert res == "1h1"
res = summary.show_elapsed(90*60)
- assert res == "1h30"
+ assert res == "1h30"
-def _BuilderToStatus(status):
- setup = {'name': 'builder', 'builddir': 'BUILDDIR',
- 'slavebuilddir': 'SLAVEBUILDDIR',
- 'factory': process_factory.BuildFactory() }
- return process_builder.Builder(setup, status)
+class FakeMasterConfig(object):
+ buildbotURL = "http://buildbot/"
+ logCompressionLimit = 0
+ def __init__(self, builders=None):
+ self.builders = builders
+
+
+class FakeBuilderconfig(object):
+ validNames = 'name factory slavenames builddir slavebuilddir category ' \
+ 'nextSlave nextBuild canStartBuild locks env properties ' \
+ 'mergeRequests description'.split()
+
+ def __init__(self, **kwargs):
+ for kw, item in kwargs.iteritems():
+ assert kw in self.validNames
+ setattr(self, kw, item)
class FakeMaster(object):
basedir = None
- buildbotURL = "http://buildbot/"
def __init__(self, builders):
self.botmaster = FakeBotMaster(builders)
+ self.config = FakeMasterConfig()
def subscribeToBuildsetCompletions(self, callback):
pass
@@ -374,6 +385,7 @@
def subscribeToBuildRequests(self, callback):
pass
+
class FakeBotMaster(object):
def __init__(self, builders):
@@ -384,19 +396,22 @@
self.builderNames.append(name)
self.builders[name] = _BuilderToStatus(builder)
+
class FakeSite(object):
def __init__(self, status):
self.buildbot_service = FakeService(status)
+
class FakeService(object):
-
+
def __init__(self, status):
self.status = status
def getStatus(self):
return self.status
+
class FakeRequest(object):
def __init__(self, builders, args={}):
@@ -406,6 +421,14 @@
self.site = FakeSite(status)
+def _BuilderToStatus(status):
+ builder = process_builder.Builder(status.name)
+ builder.builder_status = status
+ builder.builder_status.basedir = 'BASEDIR'
+ builder.config = FakeBuilderconfig(factory=process_factory.BuildFactory())
+ return builder
+
+
def witness_cat_branch(summary):
ref = [None]
recentRuns = summary.recentRuns
@@ -414,7 +437,6 @@
ref[0] = cat_branch
return cat_branch
summary.recentRuns = witness
-
return lambda: ref[0]
class FakeLog(object):
@@ -424,7 +446,7 @@
self.step = step
self.name = name
self.cont = cont
-
+
def getStep(self):
return self.step
@@ -444,7 +466,7 @@
n = getattr(builder, 'nextBuildNumber', 0)
t = 1000
for rev, reslog in builds:
- build = status_builder.BuildStatus(builder, n)
+ build = status_builder.BuildStatus(builder, builder.master, n)
build.started = time.time()
build.setProperty('got_revision', str(rev), None)
step = build.addStepWithName('pytest')
@@ -453,16 +475,21 @@
step.started = t
step.finished = t + (n+1)*60
t = step.finished + 30
+ builder.buildCache.cache[build.number] = build
+ builder.buildStarted(build)
build.buildFinished()
- builder.touchBuildCache(build)
n += 1
builder.nextBuildNumber = n
-
+
+
+METABRANCH = '<trunk>'
+
class TestSummary(object):
def setup_method(self, meth):
summary.outcome_set_cache.clear()
+ self.master = FakeMaster([])
def test_sanity(self):
s = summary.Summary()
@@ -474,79 +501,78 @@
assert cat_branch == {}
def test_one_build_no_rev(self):
- builder = status_builder.BuilderStatus('builder0')
- build = status_builder.BuildStatus(builder, 0)
- build.started = time.time()
+ builder = status_builder.BuilderStatus('builder0', None, self.master, '')
+ build = status_builder.BuildStatus(builder, self.master, 0)
+ build.buildStarted(builder)
build.buildFinished()
- builder.touchBuildCache(build)
- builder.nextBuildNumber = len(builder.buildCache)
+ builder.nextBuildNumber = len(builder.buildCache.cache)
s = summary.Summary()
- res = witness_cat_branch(s)
+ res = witness_cat_branch(s)
req = FakeRequest([builder])
out = s.body(req)
cat_branch = res()
- assert cat_branch == {(None, None): ({}, [build])}
+ assert cat_branch == {(None, METABRANCH): ({}, [build])}
def test_one_build_no_logs(self):
- builder = status_builder.BuilderStatus('builder0')
- build = status_builder.BuildStatus(builder, 0)
- build.started = time.time()
+ builder = status_builder.BuilderStatus('builder0', None, self.master, '')
+ build = status_builder.BuildStatus(builder, self.master, 0)
+ build.started = time.time()
build.setProperty('got_revision', '50000', None)
build.buildFinished()
- builder.touchBuildCache(build)
- builder.nextBuildNumber = len(builder.buildCache)
+ builder.buildCache.cache[build.number] = build
+ builder.nextBuildNumber = len(builder.buildCache.cache)
s = summary.Summary()
- res = witness_cat_branch(s)
+ res = witness_cat_branch(s)
req = FakeRequest([builder])
out = s.body(req)
cat_branch = res()
-
- revs = cat_branch[(None, None)][0]
+
+ revs = cat_branch[(None, METABRANCH)][0]
assert revs.keys() == ['50000']
- assert '<run>' in out
+ assert 'success' in out
def test_one_build_no_logs_failure(self):
- builder = status_builder.BuilderStatus('builder0')
- build = status_builder.BuildStatus(builder, 0)
- build.started = time.time()
+ builder = status_builder.BuilderStatus('builder0', None, self.master, '')
+ build = status_builder.BuildStatus(builder, self.master, 0)
+ build.started = time.time()
build.setProperty('got_revision', '50000', None)
step = build.addStepWithName('step')
step.setText(['step', 'borken'])
step.stepFinished(summary.FAILURE)
step1 = build.addStepWithName('other')
step1.setText(['other', 'borken'])
- step1.stepFinished(summary.FAILURE)
+ step1.stepFinished(summary.FAILURE)
build.buildFinished()
- builder.touchBuildCache(build)
- builder.nextBuildNumber = len(builder.buildCache)
+ builder.buildCache.cache[build.number] = build
+ builder.nextBuildNumber = len(builder.buildCache.cache)
s = summary.Summary()
- res = witness_cat_branch(s)
- req = FakeRequest([builder])
- out = s.body(req)
- cat_branch = res()
-
- revs = cat_branch[(None, None)][0]
- assert revs.keys() == ['50000']
-
- assert 'step borken' in out
- assert 'other borken' not in out
-
- def test_one_build(self):
- builder = status_builder.BuilderStatus('builder0')
- add_builds(builder, [(60000, "F TEST1\n. b")])
-
- s = summary.Summary()
- res = witness_cat_branch(s)
+ res = witness_cat_branch(s)
req = FakeRequest([builder])
out = s.body(req)
cat_branch = res()
- revs = cat_branch[(None, None)][0]
+ revs = cat_branch[(None, METABRANCH)][0]
+ assert revs.keys() == ['50000']
+
+ assert 'step borken' in out
+ assert 'other borken' not in out
+
+ def test_one_build(self):
+ builder = status_builder.BuilderStatus('builder0', None, self.master, '')
+ add_builds(builder, [(60000, "F TEST1\n. b")])
+
+ s = summary.Summary()
+ res = witness_cat_branch(s)
+ req = FakeRequest([builder])
+ out = s.body(req)
+ cat_branch = res()
+
+ revs = cat_branch[(None, METABRANCH)][0]
assert revs.keys() == ['60000']
outcome = revs['60000']['builder0']
assert outcome.revision == '60000'
@@ -555,17 +581,17 @@
assert 'TEST1' in out
def test_two_builds(self):
- builder = status_builder.BuilderStatus('builder0')
+ builder = status_builder.BuilderStatus('builder0', None, self.master, '')
add_builds(builder, [('60000', "F TEST1\n. b"),
('60001', ". TEST1\n. b")])
s = summary.Summary()
- res = witness_cat_branch(s)
+ res = witness_cat_branch(s)
req = FakeRequest([builder])
out = s.body(req)
cat_branch = res()
- revs = cat_branch[(None, None)][0]
+ revs = cat_branch[(None, METABRANCH)][0]
assert sorted(revs.keys()) == ['60000', '60001']
outcome = revs['60000']['builder0']
assert outcome.revision == '60000'
@@ -582,20 +608,21 @@
assert 'TEST1' in out
assert ':-)' in out
- assert '\n <a class="failSummary failed" href="javascript:togglestate(1,1)" id="a1c1">-</a> <span class="failSummary success">+</span> success' in out
-
+ assert re.search(r'\n <a class="failSummary failed" href="javascript:'
+ r'togglestate\((\d+),(\d+)\)" id="a\1c\2">-</a> '
+ r'<span class="failSummary success">\+</span> success', out) is not None
def test_two_builds_samerev(self):
- builder = status_builder.BuilderStatus('builder0')
+ builder = status_builder.BuilderStatus('builder0', None, self.master, '')
add_builds(builder, [('60000', "F TEST1\n. b"),
- ('60000', "F TEST1\n. b")])
+ ('60000', "F TEST1\n. b")])
s = summary.Summary()
- res = witness_cat_branch(s)
+ res = witness_cat_branch(s)
req = FakeRequest([builder])
out = s.body(req)
cat_branch = res()
- revs = cat_branch[(None, None)][0]
+ revs = cat_branch[(None, METABRANCH)][0]
assert sorted(revs.keys()) == ['60000']
outcome = revs['60000']['builder0']
assert outcome.revision == '60000'
@@ -604,18 +631,18 @@
assert 'TEST1' in out
def test_two_builds_recentrev(self):
- builder = status_builder.BuilderStatus('builder0')
+ builder = status_builder.BuilderStatus('builder0', None, self.master, '')
add_builds(builder, [('60000', "F TEST1\n. b"),
('60001', "F TEST1\n. b")])
s = summary.Summary()
- res = witness_cat_branch(s)
+ res = witness_cat_branch(s)
req = FakeRequest([builder])
req.args = {'recentrev': ['60000']}
out = s.body(req)
cat_branch = res()
- revs = cat_branch[(None, None)][0]
+ revs = cat_branch[(None, METABRANCH)][0]
assert sorted(revs.keys()) == ['60000']
outcome = revs['60000']['builder0']
assert outcome.revision == '60000'
@@ -624,19 +651,19 @@
assert 'TEST1' in out
def test_many_builds_query_builder(self):
- builder = status_builder.BuilderStatus('builder0')
+ builder = status_builder.BuilderStatus('builder0', None, self.master, '')
add_builds(builder, [('60000', "F TEST1\n. b"),
('60000', ". a\n. b"),
- ('60001', "F TEST1\n. b")])
+ ('60001', "F TEST1\n. b")])
s = summary.Summary()
- res = witness_cat_branch(s)
+ res = witness_cat_branch(s)
req = FakeRequest([builder])
req.args={'builder': ['builder0']}
out = s.body(req)
cat_branch = res()
- runs = cat_branch[(None, None)][0]
+ runs = cat_branch[(None, METABRANCH)][0]
assert sorted(runs.keys()) == [(0, '60000'), (1, '60000'), (2, '60001')]
outcome = runs[(0, '60000')]['builder0']
assert outcome.revision == '60000'
@@ -660,20 +687,20 @@
def test_many_builds_query_builder_builds(self):
- builder = status_builder.BuilderStatus('builder0')
+ builder = status_builder.BuilderStatus('builder0', None, self.master, '')
add_builds(builder, [('60000', "F TEST1\n. b"),
('60000', ". a\n. b"),
- ('60001', "F TEST1\n. b")])
+ ('60001', "F TEST1\n. b")])
s = summary.Summary()
- res = witness_cat_branch(s)
+ res = witness_cat_branch(s)
req = FakeRequest([builder])
req.args={'builder': ['builder0'],
'builds': ['0','2-2', '7']}
out = s.body(req)
cat_branch = res()
- runs = cat_branch[(None, None)][0]
+ runs = cat_branch[(None, METABRANCH)][0]
assert sorted(runs.keys()) == [(0, '60000'), (2, '60001')]
outcome = runs[(0, '60000')]['builder0']
assert outcome.revision == '60000'
@@ -692,21 +719,21 @@
assert 'TEST1' in out
def test_many_pytestLogs(self):
- builder = status_builder.BuilderStatus('builder1')
- build = status_builder.BuildStatus(builder, 0)
+ builder = status_builder.BuilderStatus('builder1', '', self.master, '')
+ build = status_builder.BuildStatus(builder, self.master, 0)
build.started = time.time()
build.setProperty('got_revision', '70000', None)
step = build.addStepWithName('pytest')
step.logs.extend([FakeLog(step, 'pytestLog', "F TEST1")])
step.setText(["pytest", "failed"])
- step.stepFinished(summary.FAILURE)
+ step.stepFinished(summary.FAILURE)
step2 = build.addStepWithName('pytest2')
step2.logs.extend([FakeLog(step, 'pytestLog', ". x\nF TEST2")])
step2.setText(["pytest2", "aborted"])
step2.stepFinished(summary.EXCEPTION)
build.buildFinished()
- builder.touchBuildCache(build)
- builder.nextBuildNumber = 1
+ builder.buildCache.cache[build.number] = build
+ builder.nextBuildNumber = len(builder.buildCache.cache)
s = summary.Summary()
req = FakeRequest([builder])
@@ -719,23 +746,23 @@
assert 'pytest2 aborted' in out
def test_subtle_failures(self):
- builder = status_builder.BuilderStatus('builder1')
- build = status_builder.BuildStatus(builder, 0)
+ builder = status_builder.BuilderStatus('builder1', '', self.master, '')
+ build = status_builder.BuildStatus(builder, self.master, 0)
build.started = time.time()
build.setProperty('got_revision', '70000', None)
- step = build.addStepWithName('pytest')
+ step = build.addStepWithName('pytest')
step.logs.extend([FakeLog(step, 'pytestLog', ". TEST1")])
step.setText(["pytest", "failed slave lost"])
- step.stepFinished(summary.FAILURE)
+ step.stepFinished(summary.FAILURE)
build.buildFinished()
- builder.touchBuildCache(build)
- builder.nextBuildNumber = 1
+ builder.buildCache.cache[build.number] = build
+ builder.nextBuildNumber = len(builder.buildCache.cache)
s = summary.Summary()
req = FakeRequest([builder])
out = s.body(req)
- assert 'pytest failed slave lost' in out
+ assert 'pytest failed slave lost' in out
def test_category_branch_sorting_key(self):
@@ -764,19 +791,16 @@
assert res == (2, '', 2, 'release/1')
res = s._cat_branch_key(('', 'what'))
- assert res == (2, '', 4, 'what')
+ assert res == (2, '', 4, 'what')
def test_builders_with_categories(self):
- builder1 = status_builder.BuilderStatus('builder_foo')
- builder1.category = 'foo'
- builder2 = status_builder.BuilderStatus('builder_bar')
- builder2.category = 'bar'
- builder3 = status_builder.BuilderStatus('builder_')
- builder3.category = ''
+ builder1 = status_builder.BuilderStatus('builder_foo', 'foo', self.master, '')
+ builder2 = status_builder.BuilderStatus('builder_bar', 'bar', self.master, '')
+ builder3 = status_builder.BuilderStatus('builder_', '', self.master, '')
add_builds(builder1, [('60000', "F TEST1\n")])
add_builds(builder2, [('60000', "F TEST2\n")])
- add_builds(builder3, [('60000', "F TEST3\n")])
+ add_builds(builder3, [('60000', "F TEST3\n")])
s = summary.Summary(['foo', 'bar'])
req = FakeRequest([builder1, builder2, builder3])
@@ -792,7 +816,7 @@
assert "{bar}" in out
def test_two_builds_different_rev_digits(self):
- builder = status_builder.BuilderStatus('builder0')
+ builder = status_builder.BuilderStatus('builder0', '', self.master, '')
add_builds(builder, [(999, "F TEST1\n. b"),
(1000, "F TEST1\n. b")])
@@ -806,16 +830,16 @@
assert p999builder0-p999 == p1000builder0-p1000+1
def test_build_times_and_filtering(self):
- builder1 = status_builder.BuilderStatus('builder1')
- builder2 = status_builder.BuilderStatus('builder2')
-
+ builder1 = status_builder.BuilderStatus('builder1', '', self.master, '')
+ builder2 = status_builder.BuilderStatus('builder2', '', self.master, '')
+
add_builds(builder1, [('60000', "F TEST1\n")])
- add_builds(builder2, [('50000', ". TEST2\n")])
+ add_builds(builder2, [('50000', ". TEST2\n")])
add_builds(builder2, [('60000', "F TEST2\n")])
builder1.getBuild(0).started = 1228258800 # 3 Dec 2008
builder1.getBuild(0).finished = 1228258800 # 3 Dec 2008
- builder2.getBuild(1).started = 1228431600 # 5 Dec 2008
+ builder2.getBuild(1).started = 1228431600 # 5 Dec 2008
builder2.getBuild(1).finished = 1228431600 # 5 Dec 2008
builder2.getBuild(0).started = 1227913200 # 29 Nov 2008
diff --git a/bot2/pypybuildbot/util.py b/bot2/pypybuildbot/util.py
--- a/bot2/pypybuildbot/util.py
+++ b/bot2/pypybuildbot/util.py
@@ -2,7 +2,7 @@
import socket
def we_are_debugging():
- return socket.gethostname() not in ("wyvern", "cobra")
+ return socket.gethostname() != 'cobra'
def load(name):
mod = __import__(name, {}, {}, ['__all__'])
diff --git a/master/public_html/default.css b/master/public_html/default.css
--- a/master/public_html/default.css
+++ b/master/public_html/default.css
@@ -10,6 +10,22 @@
color: #333;
}
+.auth {
+position:absolute;
+top:5px;
+right:40px;
+}
+
+.alert {
+ color: #c30000;
+ background-color: #f2dcdc;
+ padding: 5px 5px 5px 25px;
+ margin-bottom: 20px;
+ border-top:1px solid #ccc;
+ border-bottom:1px solid #ccc;
+ border-color: #c30000;
+ font-size: 20px;
+}
a:link,a:visited,a:active {
color: #444;
}
@@ -197,14 +213,17 @@
font-weight: normal;
padding: 8px 8px 8px 8px;
color: #333333;
+ background-color: #eee;
+ text-align: left;
+}
+
+td.DevBottom {
border-bottom-right-radius: 5px;
-webkit-border-bottom-right-radius: 5px;
-moz-border-radius-bottomright: 5px;
border-bottom-left-radius: 5px;
-webkit-border-bottom-left-radius: 5px;
-moz-border-radius-bottomleft: 5px;
- background-color: #eee;
- text-align: left;
}
td.Alt {
@@ -212,9 +231,9 @@
}
.legend {
- border-radius: 5px;
- -webkit-border-radius: 5px;
- -moz-border-radius: 5px;
+ border-radius: 5px !important;
+ -webkit-border-radius: 5px !important;
+ -moz-border-radius: 5px !important;
width: 100px;
max-width: 100px;
text-align: center;
@@ -349,6 +368,12 @@
border-color: #A77272;
}
+.failure-again {
+ color: #000;
+ background-color: #eA9;
+ border-color: #A77272;
+}
+
.warnings {
color: #FFFFFF;
background-color: #fa3;
@@ -379,6 +404,12 @@
border-color: #C5C56D;
}
+.paused {
+ color: #FFFFFF;
+ background-color: #8080FF;
+ border-color: #dddddd;
+}
+
.offline,td.offline {
color: #FFFFFF;
background-color: #777777;
@@ -534,6 +565,10 @@
display: none;
}
+pre {
+ white-space: pre-wrap;
+}
+
/* change comments (use regular colors here) */
pre.comments>a:link,pre.comments>a:visited {
color: blue;
@@ -542,3 +577,27 @@
pre.comments>a:active {
color: purple;
}
+
+form.command_forcebuild {
+ border-top: 1px solid black;
+ padding: .5em;
+ margin: .5em;
+}
+
+form.command_forcebuild > .row {
+ border-top: 1px dotted gray;
+ padding: .5em 0;
+}
+
+form.command_forcebuild .force-textarea > .label {
+ display: block;
+}
+
+form.command_forcebuild .force-nested > .label {
+ font-weight: bold;
+ display: list-item;
+}
+
+form.command_forcebuild .force-any .force-text {
+ display: inline;
More information about the pypy-commit
mailing list