Merge lp:~abentley/launchpad/retain-spr-builds into lp:launchpad/db-devel

Proposed by Aaron Bentley
Status: Merged
Approved by: Aaron Bentley
Approved revision: no longer in the source branch.
Merged at revision: 9979
Proposed branch: lp:~abentley/launchpad/retain-spr-builds
Merge into: lp:launchpad/db-devel
Diff against target: 136 lines (+41/-15)
6 files modified
database/schema/patch-2208-28-0.sql (+7/-0)
lib/canonical/launchpad/security.py (+2/-1)
lib/lp/code/interfaces/sourcepackagerecipebuild.py (+1/-2)
lib/lp/code/model/sourcepackagerecipe.py (+3/-8)
lib/lp/code/model/sourcepackagerecipebuild.py (+1/-1)
lib/lp/code/model/tests/test_sourcepackagerecipe.py (+27/-3)
To merge this branch: bzr merge lp:~abentley/launchpad/retain-spr-builds
Reviewer Review Type Date Requested Status
Stuart Bishop (community) db Approve
Tim Penhey (community) Approve
Robert Collins db Pending
Review via email: mp+40669@code.launchpad.net

Commit message

NULL recipes in recipe builds on deletion.

Description of the change

= Summary =
Fix bug #645620: Deleting recipe leaves SourcePackageReleases with no
traceability

== Proposed fix ==
Relax the not-null constraint for recipe on sourcepackagerecipebuild. NULL
sourcepackagerecipebuilds on recipe deletion instead of deleting them.

== Pre-implementation notes ==
Discussed with thumper

== Implementation details ==
None

== Tests ==
bin/test -t test_destroySelf_retains_build -t test_destroySelf_preserves_release

== Demo and Q/A ==
Cannot be demoed because sourcepackagerecipebuilds do not have a valid URL if
their recipe is deleted.

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/code/interfaces/sourcepackagerecipebuild.py
  lib/canonical/launchpad/security.py
  database/schema/patch-2208-90-0.sql
  lib/lp/code/model/tests/test_sourcepackagerecipe.py
  lib/lp/code/model/sourcepackagerecipebuild.py
  lib/lp/code/model/sourcepackagerecipe.py

./lib/canonical/launchpad/security.py
     721: E302 expected 2 blank lines, found 1
    1256: E302 expected 2 blank lines, found 1
    1466: E302 expected 2 blank lines, found 1

To post a comment you must log in.
Revision history for this message
Tim Penhey (thumper) wrote :

Looks good. Just one small point: when clearing out the recipe value from the builds, we should use a set based update rather than iterating over each one.

review: Approve
Revision history for this message
Stuart Bishop (stub) wrote :

Fine. patch-2208-28-0.sql

review: Approve (db)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'database/schema/patch-2208-28-0.sql'
2--- database/schema/patch-2208-28-0.sql 1970-01-01 00:00:00 +0000
3+++ database/schema/patch-2208-28-0.sql 2010-11-17 19:49:40 +0000
4@@ -0,0 +1,7 @@
5+-- Copyright 2010 Canonical Ltd. This software is licensed under the
6+-- GNU Affero General Public License version 3 (see the file LICENSE).
7+SET client_min_messages=ERROR;
8+
9+ALTER TABLE SourcePackageRecipeBuild ALTER COLUMN recipe DROP NOT NULL;
10+
11+INSERT INTO LaunchpadDatabaseRevision VALUES (2208, 28, 0);
12
13=== modified file 'lib/canonical/launchpad/security.py'
14--- lib/canonical/launchpad/security.py 2010-11-12 23:30:57 +0000
15+++ lib/canonical/launchpad/security.py 2010-11-17 19:49:40 +0000
16@@ -2284,7 +2284,8 @@
17 usedfor = ISourcePackageRecipeBuild
18
19 def iter_objects(self):
20- yield self.obj.recipe
21+ if self.obj.recipe is not None:
22+ yield self.obj.recipe
23 yield self.obj.archive
24
25
26
27=== modified file 'lib/lp/code/interfaces/sourcepackagerecipebuild.py'
28--- lib/lp/code/interfaces/sourcepackagerecipebuild.py 2010-08-27 02:55:05 +0000
29+++ lib/lp/code/interfaces/sourcepackagerecipebuild.py 2010-11-17 19:49:40 +0000
30@@ -58,8 +58,7 @@
31 title=_("The person who wants this to be done."))
32
33 recipe = Object(
34- schema=ISourcePackageRecipe, required=True,
35- title=_("The recipe being built."))
36+ schema=ISourcePackageRecipe, title=_("The recipe being built."))
37
38 manifest = Object(
39 schema=ISourcePackageRecipeData, title=_(
40
41=== modified file 'lib/lp/code/model/sourcepackagerecipe.py'
42--- lib/lp/code/model/sourcepackagerecipe.py 2010-11-04 06:36:29 +0000
43+++ lib/lp/code/model/sourcepackagerecipe.py 2010-11-17 19:49:40 +0000
44@@ -28,7 +28,6 @@
45 implements,
46 )
47
48-from canonical.config import config
49 from canonical.database.datetimecol import UtcDateTimeCol
50 from canonical.launchpad.interfaces.lpstorm import (
51 IMasterStore,
52@@ -198,13 +197,9 @@
53 store = Store.of(self)
54 self.distroseries.clear()
55 self._recipe_data.instructions.find().remove()
56-
57- def destroyBuilds(pending):
58- builds = self.getBuilds(pending=pending)
59- for build in builds:
60- build.destroySelf()
61- destroyBuilds(pending=True)
62- destroyBuilds(pending=False)
63+ builds = store.find(
64+ SourcePackageRecipeBuild, SourcePackageRecipeBuild.recipe==self)
65+ builds.set(recipe_id=None)
66 store.remove(self._recipe_data)
67 store.remove(self)
68
69
70=== modified file 'lib/lp/code/model/sourcepackagerecipebuild.py'
71--- lib/lp/code/model/sourcepackagerecipebuild.py 2010-10-22 20:50:50 +0000
72+++ lib/lp/code/model/sourcepackagerecipebuild.py 2010-11-17 19:49:40 +0000
73@@ -109,7 +109,7 @@
74
75 is_virtualized = True
76
77- recipe_id = Int(name='recipe', allow_none=False)
78+ recipe_id = Int(name='recipe')
79 recipe = Reference(recipe_id, 'SourcePackageRecipe.id')
80
81 manifest = Reference(
82
83=== modified file 'lib/lp/code/model/tests/test_sourcepackagerecipe.py'
84--- lib/lp/code/model/tests/test_sourcepackagerecipe.py 2010-11-08 01:08:15 +0000
85+++ lib/lp/code/model/tests/test_sourcepackagerecipe.py 2010-11-17 19:49:40 +0000
86@@ -51,7 +51,10 @@
87 NonPPABuildRequest,
88 SourcePackageRecipe,
89 )
90-from lp.code.model.sourcepackagerecipebuild import SourcePackageRecipeBuildJob
91+from lp.code.model.sourcepackagerecipebuild import (
92+ SourcePackageRecipeBuild,
93+ SourcePackageRecipeBuildJob,
94+ )
95 from lp.code.tests.helpers import recipe_parser_newest_version
96 from lp.registry.interfaces.pocket import PackagePublishingPocket
97 from lp.services.job.interfaces.job import (
98@@ -484,7 +487,7 @@
99 # Show no database constraints were violated
100 Store.of(recipe).flush()
101
102- def test_destroySelf_clears_release(self):
103+ def test_destroySelf_preserves_release(self):
104 # Destroying a sourcepackagerecipe removes references to its builds
105 # from their releases.
106 recipe = self.factory.makeSourcePackageRecipe()
107@@ -494,7 +497,28 @@
108 self.assertEqual(build, release.source_package_recipe_build)
109 with person_logged_in(recipe.owner):
110 recipe.destroySelf()
111- self.assertIs(None, release.source_package_recipe_build)
112+ self.assertIsNot(None, release.source_package_recipe_build)
113+
114+ def test_destroySelf_retains_build(self):
115+ # Destroying a sourcepackagerecipe removes references to its builds
116+ # from their releases.
117+ recipe = self.factory.makeSourcePackageRecipe()
118+ build = self.factory.makeSourcePackageRecipeBuild(recipe=recipe)
119+ store = Store.of(build)
120+ store.flush()
121+ build_id = build.id
122+ build = store.find(
123+ SourcePackageRecipeBuild,
124+ SourcePackageRecipeBuild.id == build_id).one()
125+ self.assertIsNot(None, build)
126+ self.assertEqual(recipe, build.recipe)
127+ with person_logged_in(recipe.owner):
128+ recipe.destroySelf()
129+ build = store.find(
130+ SourcePackageRecipeBuild,
131+ SourcePackageRecipeBuild.id == build_id).one()
132+ self.assertIsNot(None, build)
133+ self.assertIs(None, build.recipe)
134 transaction.commit()
135
136 def test_findStaleDailyBuilds(self):

Subscribers

People subscribed via source and target branches

to status/vote changes: