Merge lp:~abentley/launchpad/daily-builds into lp:launchpad

Proposed by Aaron Bentley
Status: Merged
Approved by: Aaron Bentley
Approved revision: no longer in the source branch.
Merged at revision: 11004
Proposed branch: lp:~abentley/launchpad/daily-builds
Merge into: lp:launchpad
Diff against target: 502 lines (+250/-14) (has conflicts)
14 files modified
configs/testrunner/launchpad-lazr.conf (+4/-0)
cronscripts/request_daily_builds.py (+44/-0)
database/schema/security.cfg (+21/-0)
lib/canonical/config/schema-lazr.conf (+5/-0)
lib/lp/code/browser/sourcepackagerecipe.py (+6/-0)
lib/lp/code/browser/tests/test_sourcepackagerecipe.py (+2/-1)
lib/lp/code/interfaces/sourcepackagerecipebuild.py (+4/-1)
lib/lp/code/model/sourcepackagerecipe.py (+32/-5)
lib/lp/code/model/sourcepackagerecipebuild.py (+21/-0)
lib/lp/code/model/tests/test_sourcepackagerecipe.py (+34/-3)
lib/lp/code/model/tests/test_sourcepackagerecipebuild.py (+12/-0)
lib/lp/code/scripts/tests/test_request_daily_builds.py (+56/-0)
lib/lp/registry/model/person.py (+1/-1)
lib/lp/testing/factory.py (+8/-3)
Text conflict in lib/lp/code/browser/sourcepackagerecipe.py
Text conflict in lib/lp/code/model/tests/test_sourcepackagerecipebuild.py
To merge this branch: bzr merge lp:~abentley/launchpad/daily-builds
Reviewer Review Type Date Requested Status
Paul Hummer (community) code Approve
Review via email: mp+26232@code.launchpad.net

Commit message

Implement request_daily_builds script.

Description of the change

= Summary =
Fix bug #585905: Launchpad should provide daily builds

== Proposed fix ==
Implement cronscripts/request_daily_builds

== Pre-implementation notes ==
Discussed with thumper and rockstar

== Implementation details ==
As a preliminary step, stale recipes are detected according to whether the base
branch has been modified since the build completed.

Work has already begun on improving detection of stale recipes, but database
patches are required for this.

== Tests ==
bin/test -vt test_request_daily_builds -t test_makeDailyBuilds -t test_findStaleDailyBuilds_requires_build_daily -t test_findStaleDailyBuilds_for_modified_base_branch

== Demo and Q/A ==
None

= Launchpad lint =

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  cronscripts/request_daily_builds.py
  lib/lp/code/model/tests/test_sourcepackagerecipebuild.py
  lib/lp/code/interfaces/sourcepackagerecipebuild.py
  lib/canonical/config/schema-lazr.conf
  lib/lp/code/scripts/tests/test_request_daily_builds.py
  database/schema/security.cfg
  lib/lp/code/model/tests/test_sourcepackagerecipe.py
  lib/lp/testing/factory.py
  lib/lp/code/model/sourcepackagerecipebuild.py
  lib/lp/code/browser/sourcepackagerecipe.py
  lib/lp/code/model/sourcepackagerecipe.py
  lib/lp/code/browser/tests/test_sourcepackagerecipe.py
  configs/testrunner/launchpad-lazr.conf
  lib/lp/registry/model/person.py

== Pyflakes notices ==

cronscripts/request_daily_builds.py
    19: 'canonical' imported but unused

    ^^^ fixes circular import problem

== Pylint notices ==

cronscripts/request_daily_builds.py
    19: [W0611] Unused import canonical

    ^^^ fixes circular import problem

lib/lp/code/model/sourcepackagerecipebuild.py
    207: [W0702, SourcePackageRecipeBuild.makeDailyBuilds] No exception type(s) specified

    ^^^ Indeed; this is a catch-all exception handler.

lib/lp/registry/model/person.py
    1265: [W0104, Person.addMember] Statement seems to have no effect

    ^^^ Existing code uses this to force a flush.

To post a comment you must log in.
Revision history for this message
Paul Hummer (rockstar) wrote :

This all looks good generally. However, you should merge db-devel in and run the tests again. I suspect when you merge db-devel, my sourcepackagename removal work is going to make a few headaches for you. Just a heads up.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configs/testrunner/launchpad-lazr.conf'
2--- configs/testrunner/launchpad-lazr.conf 2010-06-01 14:28:40 +0000
3+++ configs/testrunner/launchpad-lazr.conf 2010-06-12 06:36:32 +0000
4@@ -198,6 +198,10 @@
5 oops_prefix: TAPPORTBLOB
6 error_dir: /var/tmp/lperr.test
7
8+[request_daily_builds]
9+oops_prefix: TRDB
10+error_dir: /var/tmp/lperr.test
11+
12 [rosetta]
13 generate_templates: True
14
15
16=== added file 'cronscripts/request_daily_builds.py'
17--- cronscripts/request_daily_builds.py 1970-01-01 00:00:00 +0000
18+++ cronscripts/request_daily_builds.py 2010-06-12 06:36:32 +0000
19@@ -0,0 +1,44 @@
20+#!/usr/bin/python -S
21+#
22+# Copyright 2010 Canonical Ltd. This software is licensed under the
23+# GNU Affero General Public License version 3 (see the file LICENSE).
24+
25+# pylint: disable-msg=W0403
26+
27+"""Request builds for stale daily build recipes."""
28+
29+__metaclass__ = type
30+
31+import _pythonpath
32+
33+import transaction
34+from zope.component import getUtility
35+
36+from canonical.config import config
37+# fix circular import issue
38+import canonical.launchpad.interfaces
39+from lp.code.interfaces.sourcepackagerecipebuild import (
40+ ISourcePackageRecipeBuildSource,)
41+from lp.services.scripts.base import LaunchpadCronScript
42+from canonical.launchpad.webapp.errorlog import globalErrorUtility
43+
44+
45+class RequestDailyBuilds(LaunchpadCronScript):
46+ """Run create merge proposal jobs."""
47+
48+ def __init__(self):
49+ name = 'request_daily_builds'
50+ dbuser = config.request_daily_builds.dbuser
51+ LaunchpadCronScript.__init__(self, name, dbuser)
52+
53+ def main(self):
54+ globalErrorUtility.configure(self.name)
55+ source = getUtility(ISourcePackageRecipeBuildSource)
56+ builds = source.makeDailyBuilds()
57+ self.logger.info('Requested %d daily builds.' % len(builds))
58+ transaction.commit()
59+
60+
61+if __name__ == '__main__':
62+ script = RequestDailyBuilds()
63+ script.lock_and_run()
64
65=== modified file 'database/schema/security.cfg'
66--- database/schema/security.cfg 2010-06-07 10:24:03 +0000
67+++ database/schema/security.cfg 2010-06-12 06:36:32 +0000
68@@ -687,6 +687,27 @@
69 public.validpersoncache = SELECT
70 public.validpersonorteamcache = SELECT
71
72+[request-daily-builds]
73+type=user
74+groups=script
75+public.archive = SELECT
76+public.buildqueue = SELECT, INSERT, UPDATE
77+public.branch = SELECT
78+public.component = SELECT
79+public.distroseries = SELECT
80+public.distroarchseries = SELECT
81+public.job = SELECT, INSERT
82+public.person = SELECT
83+public.processor = SELECT
84+public.processorfamily = SELECT
85+public.sourcepackagerecipe = SELECT
86+public.sourcepackagename = SELECT
87+public.sourcepackagerecipebuild = SELECT, INSERT
88+public.sourcepackagerecipebuildjob = SELECT, INSERT
89+public.sourcepackagerecipedata = SELECT
90+public.sourcepackagerecipedistroseries = SELECT
91+public.teamparticipation = SELECT
92+
93 [revisionkarma]
94 # Allocate karma for revisions.
95 type=user
96
97=== modified file 'lib/canonical/config/schema-lazr.conf'
98--- lib/canonical/config/schema-lazr.conf 2010-06-04 07:20:19 +0000
99+++ lib/canonical/config/schema-lazr.conf 2010-06-12 06:36:32 +0000
100@@ -1646,6 +1646,11 @@
101 # See [error_reports].
102 copy_to_zlog: false
103
104+[request_daily_builds]
105+dbuser: request-daily-builds
106+error_dir: none
107+oops_prefix: none
108+copy_to_zlog: false
109
110 [revisionkarma]
111 # The database user which will be used by this process.
112
113=== modified file 'lib/lp/code/browser/sourcepackagerecipe.py'
114--- lib/lp/code/browser/sourcepackagerecipe.py 2010-06-11 05:05:52 +0000
115+++ lib/lp/code/browser/sourcepackagerecipe.py 2010-06-12 06:36:32 +0000
116@@ -353,6 +353,7 @@
117 def request_action(self, action, data):
118 parser = RecipeParser(data['recipe_text'])
119 recipe = parser.parse()
120+<<<<<<< TREE
121 try:
122 source_package_recipe = getUtility(
123 ISourcePackageRecipeSource).new(
124@@ -365,6 +366,11 @@
125 'The bzr-builder instruction "run" is not permitted here.')
126 return
127
128+=======
129+ source_package_recipe = getUtility(ISourcePackageRecipeSource).new(
130+ self.user, self.user, data['name'], recipe, data['description'],
131+ data['distros'])
132+>>>>>>> MERGE-SOURCE
133 self.next_url = canonical_url(source_package_recipe)
134
135 def validate(self, data):
136
137=== modified file 'lib/lp/code/browser/tests/test_sourcepackagerecipe.py'
138--- lib/lp/code/browser/tests/test_sourcepackagerecipe.py 2010-06-11 19:03:35 +0000
139+++ lib/lp/code/browser/tests/test_sourcepackagerecipe.py 2010-06-12 06:36:32 +0000
140@@ -56,7 +56,8 @@
141 return self.factory.makeSourcePackageRecipe(
142 owner=self.chef, distroseries=self.squirrel, name=u'cake_recipe',
143 description=u'This recipe builds a foo for disto bar, with my'
144- ' Secret Squirrel changes.', branches=[cake_branch])
145+ ' Secret Squirrel changes.', branches=[cake_branch],
146+ daily_build_archive=self.ppa)
147
148 def getMainText(self, recipe, view_name=None):
149 """Return the main text of a recipe page, as seen by Chef."""
150
151=== modified file 'lib/lp/code/interfaces/sourcepackagerecipebuild.py'
152--- lib/lp/code/interfaces/sourcepackagerecipebuild.py 2010-05-28 03:27:18 +0000
153+++ lib/lp/code/interfaces/sourcepackagerecipebuild.py 2010-06-12 06:36:32 +0000
154@@ -1,7 +1,7 @@
155 # Copyright 2010 Canonical Ltd. This software is licensed under the
156 # GNU Affero General Public License version 3 (see the file LICENSE).
157
158-# pylint: disable-msg=E0213
159+# pylint: disable-msg=E0213,E0211
160
161 """Interfaces for source package builds."""
162
163@@ -83,6 +83,9 @@
164 :return: `ISourcePackageRecipeBuild`.
165 """
166
167+ def makeDailyBuilds():
168+ """Create and return builds for stale ISourcePackageRecipes."""
169+
170 def getById(build_id):
171 """Return the `ISourcePackageRecipeBuild` for the given build id.
172
173
174=== modified file 'lib/lp/code/model/sourcepackagerecipe.py'
175--- lib/lp/code/model/sourcepackagerecipe.py 2010-06-11 05:05:52 +0000
176+++ lib/lp/code/model/sourcepackagerecipe.py 2010-06-12 06:36:32 +0000
177@@ -14,7 +14,8 @@
178 from lazr.delegates import delegates
179
180 from storm.locals import (
181- Bool, Desc, Int, Reference, ReferenceSet, Store, Storm, Unicode)
182+ And, Bool, Desc, Int, Not, Reference, ReferenceSet, Select, Store, Storm,
183+ Unicode)
184
185 from zope.component import getUtility
186 from zope.interface import classProvides, implements
187@@ -29,6 +30,7 @@
188 ISourcePackageRecipeData)
189 from lp.code.interfaces.sourcepackagerecipebuild import (
190 ISourcePackageRecipeBuildSource)
191+from lp.code.model.branch import Branch
192 from lp.code.model.sourcepackagerecipebuild import SourcePackageRecipeBuild
193 from lp.code.model.sourcepackagerecipedata import SourcePackageRecipeData
194 from lp.registry.model.distroseries import DistroSeries
195@@ -47,7 +49,10 @@
196 __storm_table__ = "SourcePackageRecipeDistroSeries"
197 id = Int(primary=True)
198 sourcepackagerecipe_id = Int(name='sourcepackagerecipe', allow_none=False)
199+ sourcepackage_recipe = Reference(
200+ sourcepackagerecipe_id, 'SourcePackageRecipe.id')
201 distroseries_id = Int(name='distroseries', allow_none=False)
202+ distroseries = Reference(distroseries_id, 'DistroSeries.id')
203
204
205 class SourcePackageRecipe(Storm):
206@@ -119,8 +124,8 @@
207 return str(self.builder_recipe)
208
209 @staticmethod
210- def new(registrant, owner, distroseries, name, builder_recipe,
211- description):
212+ def new(registrant, owner, name, builder_recipe, description,
213+ distroseries=None, daily_build_archive=None, build_daily=False):
214 """See `ISourcePackageRecipeSource.new`."""
215 store = IMasterStore(SourcePackageRecipe)
216 sprecipe = SourcePackageRecipe()
217@@ -128,12 +133,34 @@
218 sprecipe.registrant = registrant
219 sprecipe.owner = owner
220 sprecipe.name = name
221- for distroseries_item in distroseries:
222- sprecipe.distroseries.add(distroseries_item)
223+ if distroseries is not None:
224+ for distroseries_item in distroseries:
225+ sprecipe.distroseries.add(distroseries_item)
226 sprecipe.description = description
227+ sprecipe.daily_build_archive = daily_build_archive
228+ sprecipe.build_daily = build_daily
229 store.add(sprecipe)
230 return sprecipe
231
232+ @classmethod
233+ def findStaleDailyBuilds(cls):
234+ store = IStore(cls)
235+ # Distroseries which have been built since the base branch was
236+ # modified.
237+ up_to_date_distroseries = Select(
238+ SourcePackageRecipeBuild.distroseries_id,
239+ And(
240+ SourcePackageRecipeData.sourcepackage_recipe_id ==
241+ SourcePackageRecipeBuild.recipe_id,
242+ SourcePackageRecipeData.base_branch_id == Branch.id,
243+ Branch.date_last_modified <
244+ SourcePackageRecipeBuild.datebuilt))
245+ return store.find(
246+ _SourcePackageRecipeDistroSeries, cls.build_daily == True,
247+ _SourcePackageRecipeDistroSeries.sourcepackagerecipe_id == cls.id,
248+ Not(_SourcePackageRecipeDistroSeries.distroseries_id.is_in(
249+ up_to_date_distroseries)))
250+
251 @staticmethod
252 def exists(owner, name):
253 """See `ISourcePackageRecipeSource.new`."""
254
255=== modified file 'lib/lp/code/model/sourcepackagerecipebuild.py'
256--- lib/lp/code/model/sourcepackagerecipebuild.py 2010-06-10 15:25:52 +0000
257+++ lib/lp/code/model/sourcepackagerecipebuild.py 2010-06-12 06:36:32 +0000
258@@ -11,6 +11,7 @@
259 ]
260
261 import datetime
262+import sys
263
264 from pytz import utc
265
266@@ -26,6 +27,7 @@
267 from zope.component import getUtility
268 from zope.interface import classProvides, implements
269
270+from canonical.launchpad.webapp import errorlog
271 from lp.buildmaster.interfaces.buildbase import BuildStatus, IBuildBase
272 from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType
273 from lp.buildmaster.model.buildbase import BuildBase
274@@ -196,6 +198,25 @@
275 store.add(spbuild)
276 return spbuild
277
278+ @staticmethod
279+ def makeDailyBuilds():
280+ from lp.code.model.sourcepackagerecipe import SourcePackageRecipe
281+ candidates = SourcePackageRecipe.findStaleDailyBuilds()
282+ builds = []
283+ for candidate in candidates:
284+ recipe = candidate.sourcepackage_recipe
285+ try:
286+ build = recipe.requestBuild(recipe.daily_build_archive,
287+ recipe.owner, candidate.distroseries,
288+ PackagePublishingPocket.RELEASE)
289+ except:
290+ info = sys.exc_info()
291+ errorlog.globalErrorUtility.raising(info)
292+ else:
293+ builds.append(build)
294+
295+ return builds
296+
297 def destroySelf(self):
298 store = Store.of(self)
299 job = self.buildqueue_record.job
300
301=== modified file 'lib/lp/code/model/tests/test_sourcepackagerecipe.py'
302--- lib/lp/code/model/tests/test_sourcepackagerecipe.py 2010-06-11 05:05:52 +0000
303+++ lib/lp/code/model/tests/test_sourcepackagerecipe.py 2010-06-12 06:36:32 +0000
304@@ -38,7 +38,7 @@
305 from lp.code.model.sourcepackagerecipebuild import (
306 SourcePackageRecipeBuildJob)
307 from lp.code.model.sourcepackagerecipe import (
308- NonPPABuildRequest)
309+ NonPPABuildRequest, SourcePackageRecipe)
310 from lp.registry.interfaces.pocket import PackagePublishingPocket
311 from lp.services.job.interfaces.job import (
312 IJob, JobStatus)
313@@ -354,6 +354,37 @@
314 # Show no database constraints were violated
315 Store.of(recipe).flush()
316
317+ def test_findStaleDailyBuilds_requires_build_daily(self):
318+ recipe = self.factory.makeSourcePackageRecipe()
319+ self.assertContentEqual(
320+ [], SourcePackageRecipe.findStaleDailyBuilds())
321+ removeSecurityProxy(recipe).build_daily = True
322+ self.assertEqual([recipe],
323+ [sprd.sourcepackage_recipe for sprd
324+ in SourcePackageRecipe.findStaleDailyBuilds()])
325+
326+ def test_findStaleDailyBuilds_for_modified_base_branch(self):
327+ recipe = self.factory.makeSourcePackageRecipe(build_daily=True)
328+ now = self.factory.getUniqueDate()
329+ self.assertEqual([recipe],
330+ [sprd.sourcepackage_recipe for sprd
331+ in SourcePackageRecipe.findStaleDailyBuilds()])
332+ recipe.base_branch.date_last_modified = now - timedelta(hours=1)
333+ build = recipe.requestBuild(
334+ archive=recipe.daily_build_archive, requester=recipe.owner,
335+ distroseries=list(recipe.distroseries)[0],
336+ pocket=PackagePublishingPocket.RELEASE)
337+ removeSecurityProxy(build).datebuilt = now
338+ self.assertContentEqual(
339+ [], SourcePackageRecipe.findStaleDailyBuilds())
340+ distro2 = self.factory.makeDistroSeries()
341+ distro3 = self.factory.makeDistroSeries()
342+ recipe.distroseries.add(distro2)
343+ recipe.distroseries.add(distro3)
344+ self.assertContentEqual(set([(recipe, distro2), (recipe, distro3)]),
345+ set((sprd.sourcepackage_recipe, sprd.distroseries) for sprd
346+ in SourcePackageRecipe.findStaleDailyBuilds()))
347+
348 def test_getMedianBuildDuration(self):
349 recipe = removeSecurityProxy(self.factory.makeSourcePackageRecipe())
350 self.assertIs(None, recipe.getMedianBuildDuration())
351@@ -584,8 +615,8 @@
352 distroseries = ws_object(launchpad, db_distroseries)
353 ws_owner = ws_object(launchpad, owner)
354 recipe = ws_owner.createRecipe(
355- name='toaster-1', description='a recipe',
356- distroseries=[distroseries.self_link], recipe_text=recipe_text)
357+ name='toaster-1', description='a recipe', recipe_text=recipe_text,
358+ distroseries=[distroseries.self_link])
359 # at the moment, distroseries is not exposed in the API.
360 transaction.commit()
361 db_recipe = owner.getRecipe(name=u'toaster-1')
362
363=== modified file 'lib/lp/code/model/tests/test_sourcepackagerecipebuild.py'
364--- lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2010-06-10 15:25:52 +0000
365+++ lib/lp/code/model/tests/test_sourcepackagerecipebuild.py 2010-06-12 06:36:32 +0000
366@@ -201,6 +201,14 @@
367 Store.of(binary).flush()
368 self.assertEqual([binary], list(spb.binary_builds))
369
370+ def test_makeDailyBuilds(self):
371+ self.assertEqual([],
372+ SourcePackageRecipeBuild.makeDailyBuilds())
373+ recipe = self.factory.makeSourcePackageRecipe(build_daily=True)
374+ build = SourcePackageRecipeBuild.makeDailyBuilds()[0]
375+ self.assertEqual(recipe, build.recipe)
376+ self.assertEqual(list(recipe.distroseries), [build.distroseries])
377+
378 def test_getRecentBuilds(self):
379 """Recent builds match the same person, series and receipe.
380
381@@ -231,6 +239,7 @@
382 removeSecurityProxy(recent_build).datecreated += a_second
383 self.assertContentEqual([recent_build], get_recent())
384
385+<<<<<<< TREE
386 class TestAsBuildmaster(TestCaseWithFactory):
387
388 layer = LaunchpadZopelessLayer
389@@ -282,6 +291,9 @@
390 assertNotifyOnce('OK', prepare_build())
391
392
393+=======
394+
395+>>>>>>> MERGE-SOURCE
396 class MakeSPRecipeBuildMixin:
397 """Provide the common makeBuild method returning a queued build."""
398
399
400=== added file 'lib/lp/code/scripts/tests/test_request_daily_builds.py'
401--- lib/lp/code/scripts/tests/test_request_daily_builds.py 1970-01-01 00:00:00 +0000
402+++ lib/lp/code/scripts/tests/test_request_daily_builds.py 2010-06-12 06:36:32 +0000
403@@ -0,0 +1,56 @@
404+#! /usr/bin/python2.5
405+#
406+# Copyright 2010 Canonical Ltd. This software is licensed under the
407+# GNU Affero General Public License version 3 (see the file LICENSE).
408+
409+"""Test the request_daily_builds script"""
410+
411+import unittest
412+import transaction
413+
414+from canonical.testing import ZopelessAppServerLayer
415+from canonical.launchpad.scripts.tests import run_script
416+from canonical.launchpad.webapp.errorlog import ErrorReportingUtility
417+from lp.soyuz.interfaces.archive import ArchivePurpose
418+from lp.testing import TestCaseWithFactory
419+
420+
421+class TestRequestDailyBuilds(TestCaseWithFactory):
422+
423+ layer = ZopelessAppServerLayer
424+
425+ def test_request_daily_builds(self):
426+ """Ensure the request_daily_builds script requests daily builds."""
427+ prod_branch = self.factory.makeProductBranch()
428+ prod_recipe = self.factory.makeSourcePackageRecipe(build_daily=True,
429+ branches=[prod_branch])
430+ pack_branch = self.factory.makePackageBranch()
431+ pack_recipe = self.factory.makeSourcePackageRecipe(build_daily=True,
432+ branches=[pack_branch])
433+ self.assertEqual(0, prod_recipe.getBuilds(True).count())
434+ self.assertEqual(0, pack_recipe.getBuilds(True).count())
435+ transaction.commit()
436+ retcode, stdout, stderr = run_script(
437+ 'cronscripts/request_daily_builds.py', [])
438+ self.assertIn('Requested 2 daily builds.', stderr)
439+ self.assertEqual(1, prod_recipe.getBuilds(True).count())
440+ self.assertEqual(1, pack_recipe.getBuilds(True).count())
441+
442+ def test_request_daily_builds_oops(self):
443+ """Ensure errors are handled cleanly."""
444+ archive = self.factory.makeArchive(purpose=ArchivePurpose.COPY)
445+ recipe = self.factory.makeSourcePackageRecipe(
446+ daily_build_archive=archive, build_daily=True)
447+ transaction.commit()
448+ retcode, stdout, stderr = run_script(
449+ 'cronscripts/request_daily_builds.py', [])
450+ self.assertEqual(0, recipe.getBuilds(True).count())
451+ self.assertIn('Requested 0 daily builds.', stderr)
452+ utility = ErrorReportingUtility()
453+ utility.configure('request_daily_builds')
454+ oops = utility.getLastOopsReport()
455+ self.assertIn('NonPPABuildRequest', oops.tb_text)
456+
457+
458+def test_suite():
459+ return unittest.TestLoader().loadTestsFromName(__name__)
460
461=== modified file 'lib/lp/registry/model/person.py'
462--- lib/lp/registry/model/person.py 2010-05-22 01:42:59 +0000
463+++ lib/lp/registry/model/person.py 2010-06-12 06:36:32 +0000
464@@ -2269,7 +2269,7 @@
465 builder_recipe = RecipeParser(recipe_text).parse()
466 spnset = getUtility(ISourcePackageNameSet)
467 return SourcePackageRecipe.new(
468- registrant, self, distroseries, name, builder_recipe, description)
469+ registrant, self, name, builder_recipe, description, distroseries)
470
471 def getRecipe(self, name):
472 from lp.code.model.sourcepackagerecipe import SourcePackageRecipe
473
474=== modified file 'lib/lp/testing/factory.py'
475--- lib/lp/testing/factory.py 2010-06-12 04:06:45 +0000
476+++ lib/lp/testing/factory.py 2010-06-12 06:36:32 +0000
477@@ -1765,8 +1765,9 @@
478 return parser.parse()
479
480 def makeSourcePackageRecipe(self, registrant=None, owner=None,
481- distroseries=None, name=None, description=None,
482- branches=()):
483+ distroseries=None, name=None,
484+ description=None, branches=(),
485+ build_daily=False, daily_build_archive=None):
486 """Make a `SourcePackageRecipe`."""
487 if registrant is None:
488 registrant = self.makePerson()
489@@ -1782,9 +1783,13 @@
490 name = self.getUniqueString().decode('utf8')
491 if description is None:
492 description = self.getUniqueString().decode('utf8')
493+ if daily_build_archive is None:
494+ daily_build_archive = self.makeArchive(
495+ distribution=distroseries.distribution, owner=owner)
496 recipe = self.makeRecipe(*branches)
497 source_package_recipe = getUtility(ISourcePackageRecipeSource).new(
498- registrant, owner, [distroseries], name, recipe, description)
499+ registrant, owner, name, recipe, description, [distroseries],
500+ daily_build_archive, build_daily)
501 IStore(source_package_recipe).flush()
502 return source_package_recipe
503