Merge lp:~michael.nelson/launchpad/587113-buildbase-handleStatus into lp:launchpad

Proposed by Michael Nelson
Status: Merged
Approved by: Graham Binns
Approved revision: no longer in the source branch.
Merged at revision: 10970
Proposed branch: lp:~michael.nelson/launchpad/587113-buildbase-handleStatus
Merge into: lp:launchpad
Diff against target: 531 lines (+198/-69)
10 files modified
lib/canonical/launchpad/webapp/configure.zcml (+1/-1)
lib/canonical/launchpad/webapp/tales.py (+2/-2)
lib/lp/buildmaster/interfaces/buildbase.py (+27/-12)
lib/lp/buildmaster/model/buildbase.py (+24/-13)
lib/lp/buildmaster/model/packagebuild.py (+2/-2)
lib/lp/buildmaster/tests/test_buildbase.py (+76/-35)
lib/lp/code/model/sourcepackagerecipebuild.py (+7/-1)
lib/lp/code/model/tests/test_sourcepackagerecipebuild.py (+31/-1)
lib/lp/soyuz/tests/test_binarypackagebuild.py (+23/-0)
lib/lp/testing/factory.py (+5/-2)
To merge this branch: bzr merge lp:~michael.nelson/launchpad/587113-buildbase-handleStatus
Reviewer Review Type Date Requested Status
Graham Binns (community) code Approve
Review via email: mp+27022@code.launchpad.net

Description of the change

This branch fixes the core issue of bug 587113.

It refactors the tests so that handleStatus() is called for both BinaryPackageBuilds and SourcePackageRecipeBuilds.

It also adds other tests to ensure log files and other attributes are correctly added for both build types.

To enable the shared implementation to work for both classes (until SourcePackageRecipeBuild is also updated to use the new table structure) I had to alias 3 attributes of IBuildBase.

To test:
bin/test -vv -m test_sourcepackagerecipebuild -m test_binarypackagebuild

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/webapp/configure.zcml'
2--- lib/canonical/launchpad/webapp/configure.zcml 2010-06-05 05:05:43 +0000
3+++ lib/canonical/launchpad/webapp/configure.zcml 2010-06-08 16:04:27 +0000
4@@ -421,7 +421,7 @@
5 <adapter
6 for="lp.buildmaster.interfaces.packagebuild.IPackageBuild"
7 provides="zope.traversing.interfaces.IPathAdapter"
8- factory="canonical.launchpad.webapp.tales.BuildBaseFormatterAPI"
9+ factory="canonical.launchpad.webapp.tales.PackageBuildFormatterAPI"
10 name="fmt"
11 />
12
13
14=== modified file 'lib/canonical/launchpad/webapp/tales.py'
15--- lib/canonical/launchpad/webapp/tales.py 2010-06-05 05:05:43 +0000
16+++ lib/canonical/launchpad/webapp/tales.py 2010-06-08 16:04:27 +0000
17@@ -1515,8 +1515,8 @@
18 return url
19
20
21-class BuildBaseFormatterAPI(ObjectFormatterAPI):
22- """Adapter providing fmt support for `IBuildBase` objects."""
23+class PackageBuildFormatterAPI(ObjectFormatterAPI):
24+ """Adapter providing fmt support for `IPackageBuild` objects."""
25 def _composeArchiveReference(self, archive):
26 if archive.is_ppa:
27 return " [%s/%s]" % (
28
29=== modified file 'lib/lp/buildmaster/interfaces/buildbase.py'
30--- lib/lp/buildmaster/interfaces/buildbase.py 2010-05-19 15:39:52 +0000
31+++ lib/lp/buildmaster/interfaces/buildbase.py 2010-06-08 16:04:27 +0000
32@@ -116,7 +116,22 @@
33 """Common interface shared by farm jobs that build a package."""
34 # XXX 2010-04-21 michael.nelson bug=567922. This interface
35 # can be removed once all *Build classes inherit from
36- # IBuildFarmJob/IPackageBuild.
37+ # IBuildFarmJob/IPackageBuild. Until that time, to allow the shared
38+ # implementation of handling build status, IBuildBase needs to
39+ # provide aliases for buildstate, buildlog and datebuilt as follows:
40+ # status => buildstate
41+ # log => buildlog
42+ # date_finished => datebuilt
43+ status = Choice(
44+ title=_('State'), required=True, vocabulary=BuildStatus,
45+ description=_("The current build state."))
46+ log = Object(
47+ schema=ILibraryFileAlias, required=False,
48+ title=_("The LibraryFileAlias containing the entire buildlog."))
49+ date_finished = Datetime(
50+ title=_('Date built'), required=False,
51+ description=_("The time when the build result got collected."))
52+
53
54 build_farm_job_type = Choice(
55 title=_("Job type"), required=True, readonly=True,
56@@ -130,10 +145,7 @@
57 title=_('Date created'), required=True, readonly=True,
58 description=_("The time when the build request was created.")))
59
60- buildstate = exported(
61- Choice(
62- title=_('State'), required=True, vocabulary=BuildStatus,
63- description=_("The current build state.")))
64+ buildstate = exported(status)
65
66 date_first_dispatched = exported(
67 Datetime(
68@@ -146,19 +158,14 @@
69 title=_("Builder"), schema=IBuilder, required=False,
70 description=_("The Builder which address this build request."))
71
72- datebuilt = exported(
73- Datetime(
74- title=_('Date built'), required=False,
75- description=_("The time when the build result got collected.")))
76+ datebuilt = exported(date_finished)
77
78 buildduration = Timedelta(
79 title=_("Build Duration"), required=False,
80 description=_("Build duration interval, calculated when the "
81 "build result gets collected."))
82
83- buildlog = Object(
84- schema=ILibraryFileAlias, required=False,
85- title=_("The LibraryFileAlias containing the entire buildlog."))
86+ buildlog = log
87
88 build_log_url = exported(
89 TextLine(
90@@ -225,6 +232,14 @@
91 executable.
92 """
93
94+ def getUploadLogContent(root, leaf):
95+ """Retrieve the upload log contents.
96+
97+ :param root: Root directory for the uploads
98+ :param leaf: Leaf for this particular upload
99+ :return: Contents of log file or message saying no log file was found.
100+ """
101+
102 def handleStatus(build, status, librarian, slave_status):
103 """Handle a finished build status from a slave.
104
105
106=== modified file 'lib/lp/buildmaster/model/buildbase.py'
107--- lib/lp/buildmaster/model/buildbase.py 2010-05-21 09:42:21 +0000
108+++ lib/lp/buildmaster/model/buildbase.py 2010-06-08 16:04:27 +0000
109@@ -9,7 +9,10 @@
110
111 __metaclass__ = type
112
113-__all__ = ['BuildBase']
114+__all__ = [
115+ 'handle_status_for_build',
116+ 'BuildBase',
117+ ]
118
119 import datetime
120 import logging
121@@ -37,6 +40,24 @@
122 UPLOAD_LOG_FILENAME = 'uploader.log'
123
124
125+def handle_status_for_build(build, status, librarian, slave_status):
126+ """Find and call the correct method for handling the build status.
127+
128+ This is extracted from build base so that the implementation
129+ can be shared by the newer IPackageBuild class.
130+ """
131+ logger = logging.getLogger(BUILDD_MANAGER_LOG_NAME)
132+
133+ method = getattr(BuildBase, '_handleStatus_' + status, None)
134+
135+ if method is None:
136+ logger.critical("Unknown BuildStatus '%s' for builder '%s'"
137+ % (status, build.buildqueue_record.builder.url))
138+ return
139+
140+ method(build, librarian, slave_status, logger)
141+
142+
143 class BuildBase:
144 """A mixin class providing functionality for farm jobs that build a
145 package.
146@@ -127,19 +148,9 @@
147 return None
148 return self._getProxiedFileURL(self.upload_log)
149
150- @staticmethod
151- def handleStatus(build, status, librarian, slave_status):
152+ def handleStatus(self, status, librarian, slave_status):
153 """See `IBuildBase`."""
154- logger = logging.getLogger(BUILDD_MANAGER_LOG_NAME)
155-
156- method = getattr(build, '_handleStatus_' + status, None)
157-
158- if method is None:
159- logger.critical("Unknown BuildStatus '%s' for builder '%s'"
160- % (status, build.buildqueue_record.builder.url))
161- return
162-
163- method(librarian, slave_status, logger)
164+ return handle_status_for_build(self, status, librarian, slave_status)
165
166 @staticmethod
167 def _handleStatus_OK(build, librarian, slave_status, logger):
168
169=== modified file 'lib/lp/buildmaster/model/packagebuild.py'
170--- lib/lp/buildmaster/model/packagebuild.py 2010-05-21 09:42:21 +0000
171+++ lib/lp/buildmaster/model/packagebuild.py 2010-06-08 16:04:27 +0000
172@@ -24,7 +24,7 @@
173 from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSource
174 from lp.buildmaster.interfaces.packagebuild import (
175 IPackageBuild, IPackageBuildSource)
176-from lp.buildmaster.model.buildbase import BuildBase
177+from lp.buildmaster.model.buildbase import handle_status_for_build, BuildBase
178 from lp.buildmaster.model.buildfarmjob import BuildFarmJobDerived
179 from lp.registry.interfaces.pocket import PackagePublishingPocket
180 from lp.soyuz.adapters.archivedependencies import (
181@@ -185,7 +185,7 @@
182
183 def handleStatus(self, status, librarian, slave_status):
184 """See `IPackageBuild`."""
185- return BuildBase.handleStatus(self, status, librarian, slave_status)
186+ return handle_status_for_build(self, status, librarian, slave_status)
187
188 # The following private handlers currently re-use the BuildBase
189 # implementation until it is no longer in use. If we find in the
190
191=== modified file 'lib/lp/buildmaster/tests/test_buildbase.py'
192--- lib/lp/buildmaster/tests/test_buildbase.py 2010-05-21 09:42:21 +0000
193+++ lib/lp/buildmaster/tests/test_buildbase.py 2010-06-08 16:04:27 +0000
194@@ -15,17 +15,16 @@
195 from datetime import datetime
196 import os
197 import unittest
198+from zope.security.proxy import removeSecurityProxy
199
200 from canonical.config import config
201 from canonical.database.constants import UTC_NOW
202-from canonical.testing.layers import (
203- DatabaseFunctionalLayer, LaunchpadZopelessLayer)
204+from canonical.testing.layers import LaunchpadZopelessLayer
205 from lp.buildmaster.interfaces.buildbase import BuildStatus
206 from lp.buildmaster.model.buildbase import BuildBase
207 from lp.registry.interfaces.pocket import pocketsuffix
208 from lp.soyuz.tests.soyuzbuilddhelpers import WaitingSlave
209-from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
210-from lp.testing import TestCase, TestCaseWithFactory
211+from lp.testing import TestCase
212 from lp.testing.fakemethod import FakeMethod
213
214
215@@ -62,27 +61,41 @@
216 self.package_build = BuildBase()
217
218
219-class TestBuildBaseWithDatabase(TestCaseWithFactory):
220+class TestGetUploadMethodsMixin:
221 """Tests for `IBuildBase` that need objects from the rest of Launchpad."""
222
223- layer = DatabaseFunctionalLayer
224+ layer = LaunchpadZopelessLayer
225+
226+ def makeBuild(self):
227+ """Allow classes to override the build with which the test runs.
228+
229+ XXX michaeln 2010-06-03 bug=567922
230+ Until buildbase is removed, we need to ensure these tests
231+ run against new IPackageBuild builds (BinaryPackageBuild)
232+ and the IBuildBase builds (SPRecipeBuild). They assume the build
233+ is successfully built and check that incorrect upload paths will
234+ set the status to FAILEDTOUPLOAD.
235+ """
236+ raise NotImplemented
237+
238+ def setUp(self):
239+ super(TestGetUploadMethodsMixin, self).setUp()
240+ self.build = self.makeBuild()
241
242 def test_getUploadLogContent_nolog(self):
243 """If there is no log file there, a string explanation is returned.
244 """
245 self.useTempDir()
246- build_base = BuildBase()
247 self.assertEquals('Could not find upload log file',
248- build_base.getUploadLogContent(os.getcwd(), "myleaf"))
249+ self.build.getUploadLogContent(os.getcwd(), "myleaf"))
250
251 def test_getUploadLogContent_only_dir(self):
252 """If there is a directory but no log file, expect the error string,
253 not an exception."""
254 self.useTempDir()
255 os.makedirs("accepted/myleaf")
256- build_base = BuildBase()
257 self.assertEquals('Could not find upload log file',
258- build_base.getUploadLogContent(os.getcwd(), "myleaf"))
259+ self.build.getUploadLogContent(os.getcwd(), "myleaf"))
260
261 def test_getUploadLogContent_readsfile(self):
262 """If there is a log file, return its contents."""
263@@ -90,47 +103,53 @@
264 os.makedirs("accepted/myleaf")
265 with open('accepted/myleaf/uploader.log', 'w') as f:
266 f.write('foo')
267- build_base = BuildBase()
268 self.assertEquals('foo',
269- build_base.getUploadLogContent(os.getcwd(), "myleaf"))
270+ self.build.getUploadLogContent(os.getcwd(), "myleaf"))
271
272 def test_getUploaderCommand(self):
273- build_base = BuildBase()
274 upload_leaf = self.factory.getUniqueString('upload-leaf')
275- build_base.distro_series = self.factory.makeDistroSeries()
276- build_base.distribution = build_base.distro_series.distribution
277- build_base.pocket = self.factory.getAnyPocket()
278- build_base.id = self.factory.getUniqueInteger()
279- build_base.policy_name = self.factory.getUniqueString('policy-name')
280 config_args = list(config.builddmaster.uploader.split())
281 log_file = self.factory.getUniqueString('logfile')
282 config_args.extend(
283 ['--log-file', log_file,
284- '-d', build_base.distribution.name,
285- '-s', (build_base.distro_series.name
286- + pocketsuffix[build_base.pocket]),
287- '-b', str(build_base.id),
288+ '-d', self.build.distribution.name,
289+ '-s', (self.build.distro_series.name
290+ + pocketsuffix[self.build.pocket]),
291+ '-b', str(self.build.id),
292 '-J', upload_leaf,
293- '--context=%s' % build_base.policy_name,
294+ '--context=%s' % self.build.policy_name,
295 os.path.abspath(config.builddmaster.root),
296 ])
297- uploader_command = build_base.getUploaderCommand(
298- build_base, upload_leaf, log_file)
299+ uploader_command = self.build.getUploaderCommand(
300+ self.build, upload_leaf, log_file)
301 self.assertEqual(config_args, uploader_command)
302
303
304-class TestBuildBaseHandleStatus(TestCaseWithFactory):
305- """Tests for `IBuildBase`s handleStatus method."""
306+class TestHandleStatusMixin:
307+ """Tests for `IBuildBase`s handleStatus method.
308+
309+ Note: these tests do *not* test the updating of the build
310+ status to FULLYBUILT as this happens during the upload which
311+ is stubbed out by a mock function.
312+ """
313
314 layer = LaunchpadZopelessLayer
315
316+ def makeBuild(self):
317+ """Allow classes to override the build with which the test runs.
318+
319+ XXX michaeln 2010-06-03 bug=567922
320+ Until buildbase is removed, we need to ensure these tests
321+ run against new IPackageBuild builds (BinaryPackageBuild)
322+ and the IBuildBase builds (SPRecipeBuild). They assume the build
323+ is successfully built and check that incorrect upload paths will
324+ set the status to FAILEDTOUPLOAD.
325+ """
326+ raise NotImplementedError
327+
328 def setUp(self):
329- super(TestBuildBaseHandleStatus, self).setUp()
330- test_publisher = SoyuzTestPublisher()
331- test_publisher.prepareBreezyAutotest()
332- binaries = test_publisher.getPubBinaries()
333- self.build = binaries[0].binarypackagerelease.build
334-
335+ super(TestHandleStatusMixin, self).setUp()
336+ self.build = self.makeBuild()
337 # For the moment, we require a builder for the build so that
338 # handleStatus_OK can get a reference to the slave.
339 builder = self.factory.makeBuilder()
340@@ -149,10 +168,14 @@
341 config.push('tmp_builddmaster_root', tmp_builddmaster_root)
342
343 # We stub out our builds getUploaderCommand() method so
344- # we can check whether it was called.
345+ # we can check whether it was called as well as
346+ # verifySuccessfulUpload().
347 self.fake_getUploaderCommand = FakeMethod(
348 result=['echo', 'noop'])
349- self.build.getUploaderCommand = self.fake_getUploaderCommand
350+ removeSecurityProxy(self.build).getUploaderCommand = (
351+ self.fake_getUploaderCommand)
352+ removeSecurityProxy(self.build).verifySuccessfulUpload = FakeMethod(
353+ result=True)
354
355 def test_handleStatus_OK_normal_file(self):
356 # A filemap with plain filenames should not cause a problem.
357@@ -183,6 +206,24 @@
358 self.assertEqual(BuildStatus.FAILEDTOUPLOAD, self.build.status)
359 self.assertEqual(0, self.fake_getUploaderCommand.call_count)
360
361+ def test_handleStatus_OK_sets_build_log(self):
362+ # The build log is set during handleStatus.
363+ removeSecurityProxy(self.build).log = None
364+ self.assertEqual(None, self.build.log)
365+ self.build.handleStatus('OK', None, {
366+ 'filemap': { 'myfile.py': 'test_file_hash'},
367+ })
368+ self.assertNotEqual(None, self.build.log)
369+
370+ def test_date_finished_set(self):
371+ # The date finished is updated during handleStatus_OK.
372+ removeSecurityProxy(self.build).date_finished = None
373+ self.assertEqual(None, self.build.date_finished)
374+ self.build.handleStatus('OK', None, {
375+ 'filemap': { 'myfile.py': 'test_file_hash'},
376+ })
377+ self.assertNotEqual(None, self.build.date_finished)
378+
379
380 def test_suite():
381 return unittest.TestLoader().loadTestsFromName(__name__)
382
383=== modified file 'lib/lp/code/model/sourcepackagerecipebuild.py'
384--- lib/lp/code/model/sourcepackagerecipebuild.py 2010-05-27 22:18:16 +0000
385+++ lib/lp/code/model/sourcepackagerecipebuild.py 2010-06-08 16:04:27 +0000
386@@ -75,7 +75,6 @@
387 buildlog = Reference(buildlog_id, 'LibraryFileAlias.id')
388
389 buildstate = DBEnum(enum=BuildStatus, name='build_state')
390-
391 dependencies = Unicode(allow_none=True)
392
393 upload_log_id = Int(name='upload_log', allow_none=True)
394@@ -88,6 +87,13 @@
395 datecreated = UtcDateTimeCol(notNull=True, dbName='date_created')
396 datebuilt = UtcDateTimeCol(notNull=False, dbName='date_built')
397
398+ # See `IBuildBase` - the following attributes are aliased
399+ # to allow a shared implementation of the handleStatus methods
400+ # until IBuildBase is removed.
401+ status = buildstate
402+ date_finished = datebuilt
403+ log = buildlog
404+
405 @property
406 def datestarted(self):
407 """See `IBuild`."""
408
409=== modified file 'lib/lp/code/model/tests/test_sourcepackagerecipebuild.py'
410--- lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2010-05-27 22:18:16 +0000
411+++ lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2010-06-08 16:04:27 +0000
412@@ -20,11 +20,14 @@
413
414 from canonical.launchpad.interfaces.launchpad import NotFoundError
415 from canonical.launchpad.webapp.authorization import check_permission
416-from lp.buildmaster.interfaces.buildbase import IBuildBase
417+from lp.buildmaster.interfaces.buildbase import BuildStatus, IBuildBase
418 from lp.buildmaster.interfaces.buildqueue import IBuildQueue
419+from lp.buildmaster.tests.test_buildbase import (
420+ TestGetUploadMethodsMixin, TestHandleStatusMixin)
421 from lp.code.interfaces.sourcepackagerecipebuild import (
422 ISourcePackageRecipeBuildJob, ISourcePackageRecipeBuild,
423 ISourcePackageRecipeBuildSource)
424+from lp.soyuz.interfaces.processor import IProcessorFamilySet
425 from lp.soyuz.model.processor import ProcessorFamily
426 from lp.testing import ANONYMOUS, login, person_logged_in, TestCaseWithFactory
427
428@@ -193,6 +196,33 @@
429 self.assertEqual([binary], list(spb.binary_builds))
430
431
432+class MakeSPRecipeBuildMixin:
433+ """Provide the common makeBuild method returning a queued build."""
434+
435+ def makeBuild(self):
436+ person = self.factory.makePerson()
437+ distroseries = self.factory.makeDistroSeries()
438+ processor_fam = getUtility(IProcessorFamilySet).getByName('x86')
439+ distroseries_i386 = distroseries.newArch(
440+ 'i386', processor_fam, False, person,
441+ supports_virtualized=True)
442+ distroseries.nominatedarchindep = distroseries_i386
443+ build = self.factory.makeSourcePackageRecipeBuild(
444+ distroseries=distroseries,
445+ status=BuildStatus.FULLYBUILT)
446+ build.queueBuild(build)
447+ return build
448+
449+
450+class TestGetUploadMethodsForSPRecipeBuild(
451+ MakeSPRecipeBuildMixin, TestGetUploadMethodsMixin, TestCaseWithFactory):
452+ """IBuildBase.getUpload-related methods work with SPRecipe builds."""
453+
454+
455+class TestHandleStatusForSPRBuild(
456+ MakeSPRecipeBuildMixin, TestHandleStatusMixin, TestCaseWithFactory):
457+ """IBuildBase.handleStatus works with SPRecipe builds."""
458+
459
460 def test_suite():
461 return unittest.TestLoader().loadTestsFromName(__name__)
462
463=== modified file 'lib/lp/soyuz/tests/test_binarypackagebuild.py'
464--- lib/lp/soyuz/tests/test_binarypackagebuild.py 2010-06-07 20:21:02 +0000
465+++ lib/lp/soyuz/tests/test_binarypackagebuild.py 2010-06-08 16:04:27 +0000
466@@ -17,6 +17,8 @@
467 from lp.buildmaster.interfaces.buildqueue import IBuildQueue
468 from lp.buildmaster.interfaces.packagebuild import IPackageBuild
469 from lp.buildmaster.model.buildqueue import BuildQueue
470+from lp.buildmaster.tests.test_buildbase import (
471+ TestGetUploadMethodsMixin, TestHandleStatusMixin)
472 from lp.soyuz.interfaces.binarypackagebuild import (
473 IBinaryPackageBuild, IBinaryPackageBuildSet)
474 from lp.soyuz.interfaces.buildpackagejob import IBuildPackageJob
475@@ -345,5 +347,26 @@
476 self.assertIsNot(None, self.build.date_finished)
477
478
479+class MakeBinaryPackageBuildMixin:
480+ """Provide the makeBuild method returning a queud build."""
481+
482+ def makeBuild(self):
483+ test_publisher = SoyuzTestPublisher()
484+ test_publisher.prepareBreezyAutotest()
485+ binaries = test_publisher.getPubBinaries()
486+ return binaries[0].binarypackagerelease.build
487+
488+
489+class TestGetUploadMethodsForBinaryPackageBuild(
490+ MakeBinaryPackageBuildMixin, TestGetUploadMethodsMixin,
491+ TestCaseWithFactory):
492+ """IBuildBase.getUpload-related methods work with binary builds."""
493+
494+
495+class TestHandleStatusForBinaryPackageBuild(
496+ MakeBinaryPackageBuildMixin, TestHandleStatusMixin, TestCaseWithFactory):
497+ """IBuildBase.handleStatus works with binary builds."""
498+
499+
500 def test_suite():
501 return unittest.TestLoader().loadTestsFromName(__name__)
502
503=== modified file 'lib/lp/testing/factory.py'
504--- lib/lp/testing/factory.py 2010-05-30 04:06:48 +0000
505+++ lib/lp/testing/factory.py 2010-06-08 16:04:27 +0000
506@@ -1789,7 +1789,8 @@
507 def makeSourcePackageRecipeBuild(self, sourcepackage=None, recipe=None,
508 requester=None, archive=None,
509 sourcename=None, distroseries=None,
510- pocket=None):
511+ pocket=None,
512+ status=BuildStatus.NEEDSBUILD):
513 """Make a new SourcePackageRecipeBuild."""
514 if recipe is None:
515 recipe = self.makeSourcePackageRecipe(name=sourcename)
516@@ -1800,12 +1801,14 @@
517 distribution=archive.distribution)
518 if requester is None:
519 requester = self.makePerson()
520- return getUtility(ISourcePackageRecipeBuildSource).new(
521+ spr_build = getUtility(ISourcePackageRecipeBuildSource).new(
522 distroseries=distroseries,
523 recipe=recipe,
524 archive=archive,
525 requester=requester,
526 pocket=pocket)
527+ removeSecurityProxy(spr_build).buildstate = status
528+ return spr_build
529
530 def makeSourcePackageRecipeBuildJob(
531 self, score=9876, virtualized=True, estimated_duration=64,