Skip to content

Commit

Permalink
data api for rebuild
Browse files Browse the repository at this point in the history
Signed-off-by: Pierre Tardy <tardyp@gmail.com>
  • Loading branch information
Pierre Tardy authored and tardyp committed Sep 13, 2015
1 parent dcc44bd commit f2107dd
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 8 deletions.
15 changes: 15 additions & 0 deletions master/buildbot/data/buildrequests.py
Expand Up @@ -243,3 +243,18 @@ def completeBuildRequests(self, brids, results, complete_at=None,
@defer.inlineCallbacks
def unclaimExpiredRequests(self, old, _reactor=reactor):
yield self.master.db.buildrequests.unclaimExpiredRequests(old, _reactor=_reactor)

@base.updateMethod
@defer.inlineCallbacks
def rebuildBuildrequest(self, buildrequest):

# goal is to make a copy of the original buildset
buildset = yield self.master.data.get(('buildsets', buildrequest['buildsetid']))
properties = yield self.master.data.get(('buildsets', buildrequest['buildsetid'], 'properties'))
ssids = [ss['ssid'] for ss in buildset['sourcestamps']]
res = yield self.master.data.updates.addBuildset(waited_for=False, scheduler=u'rebuild',
sourcestamps=ssids, reason=u'rebuild',
properties=properties, builderids=[buildrequest['builderid']], external_idstring=buildset['external_idstring'],
parent_buildid=buildset['parent_buildid'], parent_relationship=buildset['parent_relationship'],
)
defer.returnValue(res)
31 changes: 26 additions & 5 deletions master/buildbot/data/builds.py
Expand Up @@ -13,9 +13,11 @@
#
# Copyright Buildbot Team Members

from twisted.internet import defer

from buildbot.data import base
from buildbot.data import types
from twisted.internet import defer
from buildbot.data.resultspec import ResultSpec


class Db2DataMixin(object):
Expand Down Expand Up @@ -100,12 +102,31 @@ def startConsuming(self, callback, options, kwargs):
('builds', str(buildid), None))

def control(self, action, args, kwargs):
if action != "stop":
# we convert the action into a mixedCase method name
action_method = getattr(self, "action" + action[0].upper() + action[1:])
if action_method is None:
raise ValueError("action: {} is not supported".format(action))
return action_method(args, kwargs)

@defer.inlineCallbacks
def actionStop(self, args, kwargs):
buildid = kwargs.get('buildid')
if buildid is None:
bldr = kwargs['builderid']
num = kwargs['number']
dbdict = yield self.master.db.builds.getBuildByNumber(bldr, num)
buildid = dbdict['id']
self.master.mq.produce(("control", "builds",
str(kwargs['buildid']), 'stop'),
dict(reason=kwargs.get('reason', 'no reason')))
return defer.succeed(None)
str(buildid), 'stop'),
dict(reason=kwargs.get('reason', args.get('reason', 'no reason'))))

@defer.inlineCallbacks
def actionRebuild(self, args, kwargs):
# we use the self.get and not self.data.get to be able to support all the pathPatterns of this endpoint
build = yield self.get(ResultSpec(), kwargs)
buildrequest = yield self.master.data.get(('buildrequests', build['buildrequestid']))
res = yield self.master.data.updates.rebuildBuildrequest(buildrequest)
defer.returnValue(res)


class BuildsEndpoint(Db2DataMixin, base.Endpoint):
Expand Down
3 changes: 3 additions & 0 deletions master/buildbot/test/fake/fakedata.py
Expand Up @@ -225,6 +225,9 @@ def unclaimExpiredRequests(self, old, _reactor=reactor):
validation.verifyType(self.testcase, "old", old, validation.IntValidator())
return defer.succeed(None)

def rebuildBuildrequest(self, buildrequest):
return defer.succeed(None)

def updateBuilderList(self, masterid, builderNames):
self.testcase.assertEqual(masterid, self.master.masterid)
for n in builderNames:
Expand Down
38 changes: 38 additions & 0 deletions master/buildbot/test/unit/test_data_buildrequests.py
Expand Up @@ -494,3 +494,41 @@ def testUnclaimExpiredRequests(self):
methodkwargs=dict(_reactor=reactor),
expectedRes=None,
expectedException=None)

@defer.inlineCallbacks
def testRebuildBuildrequest(self):
self.master.db.insertTestData([
fakedb.Builder(id=77, name='builder'),
fakedb.Master(id=88),
fakedb.Buildslave(id=13, name='sl'),
fakedb.Buildset(id=8822),
fakedb.SourceStamp(id=234),
fakedb.BuildsetSourceStamp(buildsetid=8822, sourcestampid=234),
fakedb.BuildRequest(id=82, buildsetid=8822, builderid=77),
fakedb.BuildsetProperty(buildsetid=8822, property_name='prop1',
property_value='["one", "fake1"]'),
fakedb.BuildsetProperty(buildsetid=8822, property_name='prop2',
property_value='["two", "fake2"]'),
])
buildrequest = yield self.master.data.get(('buildrequests', 82))
new_bsid, brid_dict = yield self.rtype.rebuildBuildrequest(buildrequest)

self.assertEqual(brid_dict.keys(), [77])
buildrequest = yield self.master.data.get(('buildrequests', brid_dict[77]))
# submitted_at is the time of the test, so better not depend on it
self.assertIsNotNone(buildrequest['submitted_at'])
buildrequest['submitted_at'] = None
self.assertEqual(buildrequest, {'buildrequestid': 1001, 'complete': False, 'waited_for': False,
'claimed_at': None, 'results': -1, 'claimed': False,
'buildsetid': 200, 'complete_at': None, 'submitted_at': None,
'builderid': 77, 'claimed_by_masterid': None, 'priority': 0})
buildset = yield self.master.data.get(('buildsets', new_bsid))
oldbuildset = yield self.master.data.get(('buildsets', 8822))

# assert same sourcestamp
self.assertEqual(buildset['sourcestamps'], oldbuildset['sourcestamps'])
buildset['sourcestamps'] = None
self.assertIsNotNone(buildset['submitted_at'])
buildset['submitted_at'] = None
self.assertEqual(buildset, {'bsid': 200, 'complete_at': None, 'submitted_at': None,
'sourcestamps': None, 'parent_buildid': None, 'results': -1, 'parent_relationship': None, 'reason': u'rebuild', 'external_idstring': u'extid', 'complete': False})
22 changes: 21 additions & 1 deletion master/buildbot/test/unit/test_data_builds.py
Expand Up @@ -46,7 +46,7 @@ def setUp(self):
fakedb.Master(id=88),
fakedb.Buildslave(id=13, name='sl'),
fakedb.Buildset(id=8822),
fakedb.BuildRequest(id=82, buildsetid=8822),
fakedb.BuildRequest(id=82, buildsetid=8822, builderid=77),
fakedb.Build(id=13, builderid=77, masterid=88, buildslaveid=13,
buildrequestid=82, number=3),
fakedb.Build(id=14, builderid=77, masterid=88, buildslaveid=13,
Expand Down Expand Up @@ -92,6 +92,26 @@ def test_properties_injection(self):
self.validateData(build)
self.assertIn('properties', build)

@defer.inlineCallbacks
def test_action_stop(self):
yield self.callControl("stop", {}, ('builders', 77, 'builds', 5))
self.master.mq.assertProductions([(('control', 'builds', '15', 'stop'), {'reason': 'no reason'})])

@defer.inlineCallbacks
def test_action_stop_reason(self):
yield self.callControl("stop", {'reason': 'because'}, ('builders', 77, 'builds', 5))
self.master.mq.assertProductions([(('control', 'builds', '15', 'stop'), {'reason': 'because'})])

@defer.inlineCallbacks
def test_action_rebuild(self):
self.patch(self.master.data.updates, "rebuildBuildrequest",
mock.Mock(spec=self.master.data.updates.rebuildBuildrequest, return_value=(1, [2])))
r = yield self.callControl("rebuild", {}, ('builders', 77, 'builds', 5))
self.assertEqual(r, (1, [2]))

buildrequest = yield self.master.data.get(('buildrequests', 82))
self.master.data.updates.rebuildBuildrequest.assert_called_with(buildrequest)


class BuildsEndpoint(endpoint.EndpointMixin, unittest.TestCase):

Expand Down
6 changes: 4 additions & 2 deletions master/buildbot/test/util/endpoint.py
Expand Up @@ -100,8 +100,10 @@ def callStartConsuming(self, options, kwargs, expected_filter=None):
self.assertIdentical(qref.callback, cb)
self.assertEqual(qref.filter, expected_filter)

def callControl(self, action, args, kwargs):
self.assertIn(set(kwargs), self.pathArgs)
def callControl(self, action, args, path):
self.assertIsInstance(path, tuple)
endpoint, kwargs = self.matcher[path]
self.assertIdentical(endpoint, self.ep)
d = self.ep.control(action, args, kwargs)
self.assertIsInstance(d, defer.Deferred)
return d
Expand Down

0 comments on commit f2107dd

Please sign in to comment.