Merge lp:~cjwatson/launchpad/copy-set-phase into lp:launchpad

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: no longer in the source branch.
Merged at revision: 16697
Proposed branch: lp:~cjwatson/launchpad/copy-set-phase
Merge into: lp:launchpad
Diff against target: 721 lines (+191/-53)
17 files modified
lib/lp/archiveuploader/tests/nascentupload-ddebs.txt (+5/-3)
lib/lp/soyuz/adapters/overrides.py (+25/-6)
lib/lp/soyuz/adapters/tests/test_overrides.py (+46/-5)
lib/lp/soyuz/interfaces/archive.py (+11/-2)
lib/lp/soyuz/interfaces/packagecopyjob.py (+8/-2)
lib/lp/soyuz/interfaces/publishing.py (+1/-1)
lib/lp/soyuz/model/archive.py (+14/-4)
lib/lp/soyuz/model/packagecopyjob.py (+10/-3)
lib/lp/soyuz/model/publishing.py (+16/-11)
lib/lp/soyuz/model/queue.py (+2/-1)
lib/lp/soyuz/scripts/packagecopier.py (+12/-4)
lib/lp/soyuz/scripts/tests/test_copypackage.py (+21/-0)
lib/lp/soyuz/stories/soyuz/xx-person-packages.txt (+8/-5)
lib/lp/soyuz/tests/test_archive.py (+4/-2)
lib/lp/soyuz/tests/test_packagecopyjob.py (+3/-1)
lib/lp/soyuz/tests/test_publishing.py (+4/-2)
lib/lp/testing/factory.py (+1/-1)
To merge this branch: bzr merge lp:~cjwatson/launchpad/copy-set-phase
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+170775@code.launchpad.net

Commit message

Allow setting the phased-update-percentage for binary publications created by copies.

Description of the change

== Summary ==

Copying packages to the -updates pocket but gradually phasing them in using the phased_update_percentage mechanism effectively requires the PUP to be set to 0 after the copy. However, doing this with BPPH.changeOverride is problematic: it requires archive owner privileges rather than merely the ability to copy, and it's racy because you have to wait for the async copy to complete before you can change its overrides and you have to make sure you squeeze the override change in before the next publisher run. It would be better to be able to specify an initial PUP for the copied binaries. Bug 1192286 has more details.

== Proposed fix ==

Add a phased_update_percentage argument to Archive.copyPackage and propagate it all the way down. The only fiddly bit is choosing exactly how to pass it through PublishingSet.copyBinaries; I opted for making it a parameter you can tweak when creating an override policy, which the policy then remembers and applies as appropriate.

== LOC Rationale ==

+133. This is making an existing feature properly usable so I think it's reasonable; and I have a good track record at removing LoC from LP ...

== Tests ==

bin/test -vvct lp.soyuz.adapters.tests.test_overrides -t lp.soyuz.tests.test_archive -t lp.soyuz.tests.test_packagecopyjob -t lp.soyuz.scripts.tests.test_copypackage -t lp.soyuz.tests.test_publishing -t lp.soyuz.tests.test_packageupload

== Demo and Q/A ==

''Explain how to demonstrate the fix and how to carry out QA on it.''

On DF, pick two packages in PROPOSED pockets but not elsewhere and copy them to UPDATES, one with phased_update_percentage=0 and one with that argument unspecified. Run the publisher. The first should be published with "Phased-Update-Percentage: 0" in Packages, and the second should have that field missing.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) wrote :

Oops, this slipped under the radar. Looks fine to me, thanks.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/archiveuploader/tests/nascentupload-ddebs.txt'
--- lib/lp/archiveuploader/tests/nascentupload-ddebs.txt 2013-05-24 03:05:34 +0000
+++ lib/lp/archiveuploader/tests/nascentupload-ddebs.txt 2013-06-21 17:17:27 +0000
@@ -81,6 +81,7 @@
8181
82We override the binary to main/devel, and accept it into the archive.82We override the binary to main/devel, and accept it into the archive.
8383
84 >>> from operator import attrgetter
84 >>> from lp.soyuz.interfaces.component import IComponentSet85 >>> from lp.soyuz.interfaces.component import IComponentSet
85 >>> from lp.soyuz.interfaces.section import ISectionSet86 >>> from lp.soyuz.interfaces.section import ISectionSet
86 >>> main = getUtility(IComponentSet)['main']87 >>> main = getUtility(IComponentSet)['main']
@@ -99,7 +100,8 @@
99100
100 >>> switch_dbuser(config.uploadqueue.dbuser)101 >>> switch_dbuser(config.uploadqueue.dbuser)
101102
102 >>> bin_pubs = bin.queue_root.realiseUpload()103 >>> bin_pubs = sorted(
104 ... bin.queue_root.realiseUpload(), key=attrgetter('displayname'))
103105
104 >>> switch_dbuser('uploader')106 >>> switch_dbuser('uploader')
105107
@@ -109,8 +111,8 @@
109 ... print '%s %s %s %s' % (111 ... print '%s %s %s %s' % (
110 ... bin_pub.displayname, bin_pub.status.name,112 ... bin_pub.displayname, bin_pub.status.name,
111 ... bin_pub.component.name, bin_pub.section.name)113 ... bin_pub.component.name, bin_pub.section.name)
114 debug-bin 1.0-1 in hoary i386 PENDING main devel
112 debug-bin-dbgsym 1.0-1 in hoary i386 PENDING main devel115 debug-bin-dbgsym 1.0-1 in hoary i386 PENDING main devel
113 debug-bin 1.0-1 in hoary i386 PENDING main devel
114116
115DEBs and DDEBs are uploaded to separate archives, because the size117DEBs and DDEBs are uploaded to separate archives, because the size
116impact of uploading them to a single archive on mirrors would be118impact of uploading them to a single archive on mirrors would be
@@ -118,7 +120,7 @@
118120
119The DDEB is stored appropriately in the database.121The DDEB is stored appropriately in the database.
120122
121 >>> [ddeb_pub, deb_pub] = bin_pubs123 >>> [deb_pub, ddeb_pub] = bin_pubs
122 >>> ddeb = ddeb_pub.binarypackagerelease124 >>> ddeb = ddeb_pub.binarypackagerelease
123125
124 >>> print ddeb.title126 >>> print ddeb.title
125127
=== modified file 'lib/lp/soyuz/adapters/overrides.py'
--- lib/lp/soyuz/adapters/overrides.py 2013-06-20 05:50:00 +0000
+++ lib/lp/soyuz/adapters/overrides.py 2013-06-21 17:17:27 +0000
@@ -70,6 +70,8 @@
70 "The IDistroArchSeries for the publication")70 "The IDistroArchSeries for the publication")
71 priority = Attribute(71 priority = Attribute(
72 "The PackagePublishingPriority that's being overridden")72 "The PackagePublishingPriority that's being overridden")
73 phased_update_percentage = Attribute(
74 "The phased update percentage that's being overridden")
7375
7476
75class Override:77class Override:
@@ -109,11 +111,12 @@
109 implements(IBinaryOverride)111 implements(IBinaryOverride)
110112
111 def __init__(self, binary_package_name, distro_arch_series, component,113 def __init__(self, binary_package_name, distro_arch_series, component,
112 section, priority):114 section, priority, phased_update_percentage):
113 super(BinaryOverride, self).__init__(component, section)115 super(BinaryOverride, self).__init__(component, section)
114 self.binary_package_name = binary_package_name116 self.binary_package_name = binary_package_name
115 self.distro_arch_series = distro_arch_series117 self.distro_arch_series = distro_arch_series
116 self.priority = priority118 self.priority = priority
119 self.phased_update_percentage = phased_update_percentage
117120
118 def __eq__(self, other):121 def __eq__(self, other):
119 return (122 return (
@@ -121,13 +124,16 @@
121 self.distro_arch_series == other.distro_arch_series and124 self.distro_arch_series == other.distro_arch_series and
122 self.component == other.component and125 self.component == other.component and
123 self.section == other.section and126 self.section == other.section and
124 self.priority == other.priority)127 self.priority == other.priority and
128 self.phased_update_percentage == other.phased_update_percentage)
125129
126 def __repr__(self):130 def __repr__(self):
127 return ("<BinaryOverride at %x component=%r section=%r "131 return ("<BinaryOverride at %x component=%r section=%r "
128 "binary_package_name=%r distro_arch_series=%r priority=%r>" %132 "binary_package_name=%r distro_arch_series=%r priority=%r "
133 "phased_update_percentage=%r>" %
129 (id(self), self.component, self.section, self.binary_package_name,134 (id(self), self.component, self.section, self.binary_package_name,
130 self.distro_arch_series, self.priority))135 self.distro_arch_series, self.priority,
136 self.phased_update_percentage))
131137
132138
133class IOverridePolicy(Interface):139class IOverridePolicy(Interface):
@@ -140,6 +146,9 @@
140 keep the same component and section as their ancestor publications.146 keep the same component and section as their ancestor publications.
141 """147 """
142148
149 phased_update_percentage = Attribute(
150 "The phased update percentage to apply to binary publications.")
151
143 def calculateSourceOverrides(archive, distroseries, pocket, sources,152 def calculateSourceOverrides(archive, distroseries, pocket, sources,
144 source_component=None):153 source_component=None):
145 """Calculate source overrides.154 """Calculate source overrides.
@@ -173,6 +182,10 @@
173182
174 implements(IOverridePolicy)183 implements(IOverridePolicy)
175184
185 def __init__(self, phased_update_percentage=None):
186 super(BaseOverridePolicy, self).__init__()
187 self.phased_update_percentage = phased_update_percentage
188
176 def calculateSourceOverrides(self, archive, distroseries, pocket,189 def calculateSourceOverrides(self, archive, distroseries, pocket,
177 sources, source_component=None):190 sources, source_component=None):
178 raise NotImplementedError()191 raise NotImplementedError()
@@ -245,6 +258,8 @@
245 for bpn, das in expanded if das is not None]258 for bpn, das in expanded if das is not None]
246 if len(candidates) == 0:259 if len(candidates) == 0:
247 return []260 return []
261 # Do not copy phased_update_percentage from existing publications;
262 # it is too context-dependent to copy.
248 already_published = DecoratedResultSet(263 already_published = DecoratedResultSet(
249 store.find(264 store.find(
250 (BinaryPackagePublishingHistory.binarypackagenameID,265 (BinaryPackagePublishingHistory.binarypackagenameID,
@@ -269,7 +284,9 @@
269 None)),284 None)),
270 pre_iter_hook=eager_load)285 pre_iter_hook=eager_load)
271 return [286 return [
272 BinaryOverride(name, das, component, section, priority)287 BinaryOverride(
288 name, das, component, section, priority,
289 self.phased_update_percentage)
273 for name, das, component, section, priority in already_published]290 for name, das, component, section, priority in already_published]
274291
275292
@@ -324,7 +341,9 @@
324 default_component = archive.default_component or getUtility(341 default_component = archive.default_component or getUtility(
325 IComponentSet)['universe']342 IComponentSet)['universe']
326 return [343 return [
327 BinaryOverride(binary, das, default_component, None, None)344 BinaryOverride(
345 binary, das, default_component, None, None,
346 self.phased_update_percentage)
328 for binary, das in calculate_target_das(distroseries, binaries)]347 for binary, das in calculate_target_das(distroseries, binaries)]
329348
330349
331350
=== modified file 'lib/lp/soyuz/adapters/tests/test_overrides.py'
--- lib/lp/soyuz/adapters/tests/test_overrides.py 2013-05-23 07:06:42 +0000
+++ lib/lp/soyuz/adapters/tests/test_overrides.py 2013-06-21 17:17:27 +0000
@@ -1,4 +1,4 @@
1# Copyright 2011 Canonical Ltd. This software is licensed under the1# Copyright 2011-2013 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Test generic override policy classes."""4"""Test generic override policy classes."""
@@ -124,7 +124,7 @@
124 BinaryOverride(124 BinaryOverride(
125 bpph.binarypackagerelease.binarypackagename,125 bpph.binarypackagerelease.binarypackagename,
126 bpph.distroarchseries, bpph.component, bpph.section,126 bpph.distroarchseries, bpph.component, bpph.section,
127 bpph.priority)]127 bpph.priority, None)]
128 self.assertEqual(expected, overrides)128 self.assertEqual(expected, overrides)
129129
130 def test_binary_overrides_constant_query_count(self):130 def test_binary_overrides_constant_query_count(self):
@@ -203,7 +203,7 @@
203 expected = [203 expected = [
204 BinaryOverride(204 BinaryOverride(
205 bpph.binarypackagerelease.binarypackagename,205 bpph.binarypackagerelease.binarypackagename,
206 bpph.distroarchseries, universe, None, None)]206 bpph.distroarchseries, universe, None, None, None)]
207 self.assertEqual(expected, overrides)207 self.assertEqual(expected, overrides)
208208
209 def test_ubuntu_override_policy_sources(self):209 def test_ubuntu_override_policy_sources(self):
@@ -259,13 +259,14 @@
259 expected.append(259 expected.append(
260 BinaryOverride(260 BinaryOverride(
261 bpn, distroarchseries, bpph.component, bpph.section,261 bpn, distroarchseries, bpph.component, bpph.section,
262 bpph.priority))262 bpph.priority, None))
263 for i in xrange(2):263 for i in xrange(2):
264 distroarchseries = self.factory.makeDistroArchSeries(264 distroarchseries = self.factory.makeDistroArchSeries(
265 distroseries=distroseries)265 distroseries=distroseries)
266 bpns.append((bpn, distroarchseries.architecturetag))266 bpns.append((bpn, distroarchseries.architecturetag))
267 expected.append(267 expected.append(
268 BinaryOverride(bpn, distroarchseries, universe, None, None))268 BinaryOverride(
269 bpn, distroarchseries, universe, None, None, None))
269 distroseries.nominatedarchindep = distroarchseries270 distroseries.nominatedarchindep = distroarchseries
270 policy = UbuntuOverridePolicy()271 policy = UbuntuOverridePolicy()
271 overrides = policy.calculateBinaryOverrides(272 overrides = policy.calculateBinaryOverrides(
@@ -294,3 +295,43 @@
294 distroseries.main_archive, distroseries, pocket, ((bpn, 'i386'),))295 distroseries.main_archive, distroseries, pocket, ((bpn, 'i386'),))
295296
296 self.assertEqual([], overrides)297 self.assertEqual([], overrides)
298
299 def test_phased_update_percentage(self):
300 # A policy with a phased_update_percentage applies it to new binary
301 # overrides.
302 universe = getUtility(IComponentSet)['universe']
303 distroseries = self.factory.makeDistroSeries()
304 pocket = self.factory.getAnyPocket()
305 bpn = self.factory.makeBinaryPackageName()
306 bpns = []
307 expected = []
308 distroarchseries = self.factory.makeDistroArchSeries(
309 distroseries=distroseries)
310 bpb = self.factory.makeBinaryPackageBuild(
311 distroarchseries=distroarchseries)
312 bpr = self.factory.makeBinaryPackageRelease(
313 build=bpb, binarypackagename=bpn, architecturespecific=True)
314 bpph = self.factory.makeBinaryPackagePublishingHistory(
315 binarypackagerelease=bpr, distroarchseries=distroarchseries,
316 archive=distroseries.main_archive, pocket=pocket)
317 bpns.append((bpn, distroarchseries.architecturetag))
318 expected.append(
319 BinaryOverride(
320 bpn, distroarchseries, bpph.component, bpph.section,
321 bpph.priority, 50))
322 distroarchseries = self.factory.makeDistroArchSeries(
323 distroseries=distroseries)
324 bpns.append((bpn, distroarchseries.architecturetag))
325 expected.append(
326 BinaryOverride(bpn, distroarchseries, universe, None, None, 50))
327 distroseries.nominatedarchindep = distroarchseries
328 policy = UbuntuOverridePolicy(phased_update_percentage=50)
329 overrides = policy.calculateBinaryOverrides(
330 distroseries.main_archive, distroseries, pocket, bpns)
331 self.assertEqual(2, len(overrides))
332 key = attrgetter("binary_package_name.name",
333 "distro_arch_series.architecturetag",
334 "component.name")
335 sorted_expected = sorted(expected, key=key)
336 sorted_overrides = sorted(overrides, key=key)
337 self.assertEqual(sorted_expected, sorted_overrides)
297338
=== modified file 'lib/lp/soyuz/interfaces/archive.py'
--- lib/lp/soyuz/interfaces/archive.py 2013-05-24 04:49:14 +0000
+++ lib/lp/soyuz/interfaces/archive.py 2013-06-21 17:17:27 +0000
@@ -1042,7 +1042,7 @@
1042 def getPockets():1042 def getPockets():
1043 """Return iterable containing valid pocket names for this archive."""1043 """Return iterable containing valid pocket names for this archive."""
10441044
1045 def getOverridePolicy():1045 def getOverridePolicy(phased_update_percentage=None):
1046 """Returns an instantiated `IOverridePolicy` for the archive."""1046 """Returns an instantiated `IOverridePolicy` for the archive."""
10471047
1048 buildd_secret = TextLine(1048 buildd_secret = TextLine(
@@ -1356,13 +1356,20 @@
1356 from_pocket=TextLine(title=_("Source pocket name"), required=False),1356 from_pocket=TextLine(title=_("Source pocket name"), required=False),
1357 from_series=TextLine(1357 from_series=TextLine(
1358 title=_("Source distroseries name"), required=False),1358 title=_("Source distroseries name"), required=False),
1359 phased_update_percentage=Int(
1360 title=_("Phased update percentage"),
1361 description=_("The percentage of users for whom this package"
1362 " should be recommended, or None to publish the"
1363 " update for everyone."),
1364 required=False),
1359 )1365 )
1360 @export_write_operation()1366 @export_write_operation()
1361 @operation_for_version('devel')1367 @operation_for_version('devel')
1362 def copyPackage(source_name, version, from_archive, to_pocket,1368 def copyPackage(source_name, version, from_archive, to_pocket,
1363 person, to_series=None, include_binaries=False,1369 person, to_series=None, include_binaries=False,
1364 sponsored=None, unembargo=False, auto_approve=False,1370 sponsored=None, unembargo=False, auto_approve=False,
1365 from_pocket=None, from_series=None):1371 from_pocket=None, from_series=None,
1372 phased_update_percentage=None):
1366 """Copy a single named source into this archive.1373 """Copy a single named source into this archive.
13671374
1368 Asynchronously copy a specific version of a named source to the1375 Asynchronously copy a specific version of a named source to the
@@ -1393,6 +1400,8 @@
1393 copy from any pocket with a matching version.1400 copy from any pocket with a matching version.
1394 :param from_series: the source distroseries (as a string). If1401 :param from_series: the source distroseries (as a string). If
1395 omitted, copy from any series with a matching version.1402 omitted, copy from any series with a matching version.
1403 :param phased_update_percentage: the phased update percentage to
1404 apply to the copied publication.
13961405
1397 :raises NoSuchSourcePackageName: if the source name is invalid1406 :raises NoSuchSourcePackageName: if the source name is invalid
1398 :raises PocketNotFound: if the pocket name is invalid1407 :raises PocketNotFound: if the pocket name is invalid
13991408
=== modified file 'lib/lp/soyuz/interfaces/packagecopyjob.py'
--- lib/lp/soyuz/interfaces/packagecopyjob.py 2012-10-23 12:36:50 +0000
+++ lib/lp/soyuz/interfaces/packagecopyjob.py 2013-06-21 17:17:27 +0000
@@ -1,4 +1,4 @@
1# Copyright 2010-2012 Canonical Ltd. This software is licensed under the1# Copyright 2010-2013 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4__metaclass__ = type4__metaclass__ = type
@@ -129,7 +129,8 @@
129 include_binaries=False, package_version=None,129 include_binaries=False, package_version=None,
130 copy_policy=PackageCopyPolicy.INSECURE, requester=None,130 copy_policy=PackageCopyPolicy.INSECURE, requester=None,
131 sponsored=None, unembargo=False, auto_approve=False,131 sponsored=None, unembargo=False, auto_approve=False,
132 source_distroseries=None, source_pocket=None):132 source_distroseries=None, source_pocket=None,
133 phased_update_percentage=None):
133 """Create a new `IPlainPackageCopyJob`.134 """Create a new `IPlainPackageCopyJob`.
134135
135 :param package_name: The name of the source package to copy.136 :param package_name: The name of the source package to copy.
@@ -157,6 +158,8 @@
157 :param source_pocket: The pocket from which to copy the packages.158 :param source_pocket: The pocket from which to copy the packages.
158 Must be a member of `PackagePublishingPocket`. If omitted, copy159 Must be a member of `PackagePublishingPocket`. If omitted, copy
159 from any pocket with a matching version.160 from any pocket with a matching version.
161 :param phased_update_percentage: The phased update percentage to
162 apply to the copied publication.
160 """163 """
161164
162 def createMultiple(target_distroseries, copy_tasks, requester,165 def createMultiple(target_distroseries, copy_tasks, requester,
@@ -242,6 +245,9 @@
242 title=_("Source package publishing pocket"), required=False,245 title=_("Source package publishing pocket"), required=False,
243 readonly=True)246 readonly=True)
244247
248 phased_update_percentage = Int(
249 title=_("Phased update percentage"), required=False, readonly=True)
250
245 def addSourceOverride(override):251 def addSourceOverride(override):
246 """Add an `ISourceOverride` to the metadata."""252 """Add an `ISourceOverride` to the metadata."""
247253
248254
=== modified file 'lib/lp/soyuz/interfaces/publishing.py'
--- lib/lp/soyuz/interfaces/publishing.py 2013-05-31 04:00:53 +0000
+++ lib/lp/soyuz/interfaces/publishing.py 2013-06-21 17:17:27 +0000
@@ -991,7 +991,7 @@
991 :param pocket: The target `PackagePublishingPocket`.991 :param pocket: The target `PackagePublishingPocket`.
992 :param binaries: A dict mapping `BinaryPackageReleases` to their992 :param binaries: A dict mapping `BinaryPackageReleases` to their
993 desired overrides as (`Component`, `Section`,993 desired overrides as (`Component`, `Section`,
994 `PackagePublishingPriority`) tuples.994 `PackagePublishingPriority`, `phased_update_percentage`) tuples.
995995
996 :return: A list of new `IBinaryPackagePublishingHistory` records.996 :return: A list of new `IBinaryPackagePublishingHistory` records.
997 """997 """
998998
=== modified file 'lib/lp/soyuz/model/archive.py'
--- lib/lp/soyuz/model/archive.py 2013-06-20 05:50:00 +0000
+++ lib/lp/soyuz/model/archive.py 2013-06-21 17:17:27 +0000
@@ -1635,9 +1635,17 @@
1635 def copyPackage(self, source_name, version, from_archive, to_pocket,1635 def copyPackage(self, source_name, version, from_archive, to_pocket,
1636 person, to_series=None, include_binaries=False,1636 person, to_series=None, include_binaries=False,
1637 sponsored=None, unembargo=False, auto_approve=False,1637 sponsored=None, unembargo=False, auto_approve=False,
1638 from_pocket=None, from_series=None):1638 from_pocket=None, from_series=None,
1639 phased_update_percentage=None):
1639 """See `IArchive`."""1640 """See `IArchive`."""
1640 # Asynchronously copy a package using the job system.1641 # Asynchronously copy a package using the job system.
1642 if phased_update_percentage is not None:
1643 if phased_update_percentage < 0 or phased_update_percentage > 100:
1644 raise ValueError(
1645 "phased_update_percentage must be between 0 and 100 "
1646 "(inclusive).")
1647 elif phased_update_percentage == 100:
1648 phased_update_percentage = None
1641 pocket = self._text_to_pocket(to_pocket)1649 pocket = self._text_to_pocket(to_pocket)
1642 series = self._text_to_series(to_series)1650 series = self._text_to_series(to_series)
1643 if from_pocket:1651 if from_pocket:
@@ -1663,7 +1671,8 @@
1663 copy_policy=PackageCopyPolicy.INSECURE, requester=person,1671 copy_policy=PackageCopyPolicy.INSECURE, requester=person,
1664 sponsored=sponsored, unembargo=unembargo,1672 sponsored=sponsored, unembargo=unembargo,
1665 auto_approve=auto_approve, source_distroseries=from_series,1673 auto_approve=auto_approve, source_distroseries=from_series,
1666 source_pocket=from_pocket)1674 source_pocket=from_pocket,
1675 phased_update_percentage=phased_update_percentage)
16671676
1668 def copyPackages(self, source_names, from_archive, to_pocket,1677 def copyPackages(self, source_names, from_archive, to_pocket,
1669 person, to_series=None, from_series=None,1678 person, to_series=None, from_series=None,
@@ -1996,14 +2005,15 @@
1996 # understandiung EnumItems.2005 # understandiung EnumItems.
1997 return list(PackagePublishingPocket.items)2006 return list(PackagePublishingPocket.items)
19982007
1999 def getOverridePolicy(self):2008 def getOverridePolicy(self, phased_update_percentage=None):
2000 """See `IArchive`."""2009 """See `IArchive`."""
2001 # Circular imports.2010 # Circular imports.
2002 from lp.soyuz.adapters.overrides import UbuntuOverridePolicy2011 from lp.soyuz.adapters.overrides import UbuntuOverridePolicy
2003 # XXX StevenK: bug=785004 2011-05-19 Return PPAOverridePolicy() for2012 # XXX StevenK: bug=785004 2011-05-19 Return PPAOverridePolicy() for
2004 # a PPA that overrides the component/pocket to main/RELEASE.2013 # a PPA that overrides the component/pocket to main/RELEASE.
2005 if self.purpose in MAIN_ARCHIVE_PURPOSES:2014 if self.purpose in MAIN_ARCHIVE_PURPOSES:
2006 return UbuntuOverridePolicy()2015 return UbuntuOverridePolicy(
2016 phased_update_percentage=phased_update_percentage)
2007 return None2017 return None
20082018
2009 def removeCopyNotification(self, job_id):2019 def removeCopyNotification(self, job_id):
20102020
=== modified file 'lib/lp/soyuz/model/packagecopyjob.py'
--- lib/lp/soyuz/model/packagecopyjob.py 2013-06-20 05:50:00 +0000
+++ lib/lp/soyuz/model/packagecopyjob.py 2013-06-21 17:17:27 +0000
@@ -272,7 +272,7 @@
272 def _makeMetadata(cls, target_pocket, package_version,272 def _makeMetadata(cls, target_pocket, package_version,
273 include_binaries, sponsored=None, unembargo=False,273 include_binaries, sponsored=None, unembargo=False,
274 auto_approve=False, source_distroseries=None,274 auto_approve=False, source_distroseries=None,
275 source_pocket=None):275 source_pocket=None, phased_update_percentage=None):
276 """Produce a metadata dict for this job."""276 """Produce a metadata dict for this job."""
277 return {277 return {
278 'target_pocket': target_pocket.value,278 'target_pocket': target_pocket.value,
@@ -284,6 +284,7 @@
284 'source_distroseries':284 'source_distroseries':
285 source_distroseries.name if source_distroseries else None,285 source_distroseries.name if source_distroseries else None,
286 'source_pocket': source_pocket.value if source_pocket else None,286 'source_pocket': source_pocket.value if source_pocket else None,
287 'phased_update_percentage': phased_update_percentage,
287 }288 }
288289
289 @classmethod290 @classmethod
@@ -292,13 +293,15 @@
292 include_binaries=False, package_version=None,293 include_binaries=False, package_version=None,
293 copy_policy=PackageCopyPolicy.INSECURE, requester=None,294 copy_policy=PackageCopyPolicy.INSECURE, requester=None,
294 sponsored=None, unembargo=False, auto_approve=False,295 sponsored=None, unembargo=False, auto_approve=False,
295 source_distroseries=None, source_pocket=None):296 source_distroseries=None, source_pocket=None,
297 phased_update_percentage=None):
296 """See `IPlainPackageCopyJobSource`."""298 """See `IPlainPackageCopyJobSource`."""
297 assert package_version is not None, "No package version specified."299 assert package_version is not None, "No package version specified."
298 assert requester is not None, "No requester specified."300 assert requester is not None, "No requester specified."
299 metadata = cls._makeMetadata(301 metadata = cls._makeMetadata(
300 target_pocket, package_version, include_binaries, sponsored,302 target_pocket, package_version, include_binaries, sponsored,
301 unembargo, auto_approve, source_distroseries, source_pocket)303 unembargo, auto_approve, source_distroseries, source_pocket,
304 phased_update_percentage)
302 job = PackageCopyJob(305 job = PackageCopyJob(
303 job_type=cls.class_job_type,306 job_type=cls.class_job_type,
304 source_archive=source_archive,307 source_archive=source_archive,
@@ -451,6 +454,10 @@
451 return None454 return None
452 return PackagePublishingPocket.items[name]455 return PackagePublishingPocket.items[name]
453456
457 @property
458 def phased_update_percentage(self):
459 return self.metadata.get('phased_update_percentage')
460
454 def _createPackageUpload(self, unapproved=False):461 def _createPackageUpload(self, unapproved=False):
455 pu = self.target_distroseries.createQueueEntry(462 pu = self.target_distroseries.createQueueEntry(
456 pocket=self.target_pocket, archive=self.target_archive,463 pocket=self.target_pocket, archive=self.target_archive,
457464
=== modified file 'lib/lp/soyuz/model/publishing.py'
--- lib/lp/soyuz/model/publishing.py 2013-06-21 02:49:33 +0000
+++ lib/lp/soyuz/model/publishing.py 2013-06-21 17:17:27 +0000
@@ -1445,20 +1445,18 @@
1445 return []1445 return []
14461446
1447 BPPH = BinaryPackagePublishingHistory1447 BPPH = BinaryPackagePublishingHistory
1448 # XXX cjwatson 2013-02-13: We do not currently set the
1449 # phased_update_percentage here. However, it might be useful in
1450 # future to be able to copy a package from PROPOSED to UPDATES and
1451 # immediately set its phased_update_percentage to zero; this should
1452 # perhaps be an option.
1453 return bulk.create(1448 return bulk.create(
1454 (BPPH.archive, BPPH.distroarchseries, BPPH.pocket,1449 (BPPH.archive, BPPH.distroarchseries, BPPH.pocket,
1455 BPPH.binarypackagerelease, BPPH.binarypackagename,1450 BPPH.binarypackagerelease, BPPH.binarypackagename,
1456 BPPH.component, BPPH.section, BPPH.priority, BPPH.status,1451 BPPH.component, BPPH.section, BPPH.priority,
1457 BPPH.datecreated),1452 BPPH.phased_update_percentage, BPPH.status, BPPH.datecreated),
1458 [(archive, das, pocket, bpr, bpr.binarypackagename,1453 [(archive, das, pocket, bpr, bpr.binarypackagename,
1459 get_component(archive, das.distroseries, component),1454 get_component(archive, das.distroseries, component),
1460 section, priority, PackagePublishingStatus.PENDING, UTC_NOW)1455 section, priority, phased_update_percentage,
1461 for (das, bpr, (component, section, priority)) in needed],1456 PackagePublishingStatus.PENDING, UTC_NOW)
1457 for (das, bpr,
1458 (component, section, priority,
1459 phased_update_percentage)) in needed],
1462 get_objects=True)1460 get_objects=True)
14631461
1464 def copyBinaries(self, archive, distroseries, pocket, bpphs, policy=None):1462 def copyBinaries(self, archive, distroseries, pocket, bpphs, policy=None):
@@ -1500,7 +1498,14 @@
1500 new_component = override.component or bpph.component1498 new_component = override.component or bpph.component
1501 new_section = override.section or bpph.section1499 new_section = override.section or bpph.section
1502 new_priority = override.priority or bpph.priority1500 new_priority = override.priority or bpph.priority
1503 calculated = (new_component, new_section, new_priority)1501 # No "or bpph.phased_update_percentage" here; if the
1502 # override doesn't specify one then we leave it at None
1503 # (a.k.a. 100% of users).
1504 new_phased_update_percentage = (
1505 override.phased_update_percentage)
1506 calculated = (
1507 new_component, new_section, new_priority,
1508 new_phased_update_percentage)
1504 with_overrides[bpph.binarypackagerelease] = calculated1509 with_overrides[bpph.binarypackagerelease] = calculated
15051510
1506 # If there is a corresponding DDEB then give it our1511 # If there is a corresponding DDEB then give it our
@@ -1514,7 +1519,7 @@
1514 else:1519 else:
1515 with_overrides = dict(1520 with_overrides = dict(
1516 (bpph.binarypackagerelease, (bpph.component, bpph.section,1521 (bpph.binarypackagerelease, (bpph.component, bpph.section,
1517 bpph.priority)) for bpph in bpphs)1522 bpph.priority, None)) for bpph in bpphs)
1518 if not with_overrides:1523 if not with_overrides:
1519 return list()1524 return list()
1520 return self.publishBinaries(1525 return self.publishBinaries(
15211526
=== modified file 'lib/lp/soyuz/model/queue.py'
--- lib/lp/soyuz/model/queue.py 2013-06-20 05:50:00 +0000
+++ lib/lp/soyuz/model/queue.py 2013-06-21 17:17:27 +0000
@@ -1207,7 +1207,8 @@
1207 binary.version,1207 binary.version,
1208 'Specific' if binary.architecturespecific else 'Independent',1208 'Specific' if binary.architecturespecific else 'Independent',
1209 ))1209 ))
1210 bins[binary] = (binary.component, binary.section, binary.priority)1210 bins[binary] = (
1211 binary.component, binary.section, binary.priority, None)
1211 return getUtility(IPublishingSet).publishBinaries(1212 return getUtility(IPublishingSet).publishBinaries(
1212 self.packageupload.archive, distroseries,1213 self.packageupload.archive, distroseries,
1213 self.packageupload.pocket, bins)1214 self.packageupload.pocket, bins)
12141215
=== modified file 'lib/lp/soyuz/scripts/packagecopier.py'
--- lib/lp/soyuz/scripts/packagecopier.py 2013-06-21 02:39:33 +0000
+++ lib/lp/soyuz/scripts/packagecopier.py 2013-06-21 17:17:27 +0000
@@ -506,7 +506,8 @@
506 person=None, check_permissions=True, overrides=None,506 person=None, check_permissions=True, overrides=None,
507 send_email=False, strict_binaries=True, close_bugs=True,507 send_email=False, strict_binaries=True, close_bugs=True,
508 create_dsd_job=True, announce_from_person=None, sponsored=None,508 create_dsd_job=True, announce_from_person=None, sponsored=None,
509 packageupload=None, unembargo=False, logger=None):509 packageupload=None, unembargo=False, phased_update_percentage=None,
510 logger=None):
510 """Perform the complete copy of the given sources incrementally.511 """Perform the complete copy of the given sources incrementally.
511512
512 Verifies if each copy can be performed using `CopyChecker` and513 Verifies if each copy can be performed using `CopyChecker` and
@@ -553,6 +554,8 @@
553 :param unembargo: If True, allow copying restricted files from a private554 :param unembargo: If True, allow copying restricted files from a private
554 archive to a public archive, and unrestrict their library files when555 archive to a public archive, and unrestrict their library files when
555 doing so.556 doing so.
557 :param phased_update_percentage: The phased update percentage to apply
558 to the copied publication.
556 :param logger: An optional logger.559 :param logger: An optional logger.
557560
558 :raise CannotCopy when one or more copies were not allowed. The error561 :raise CannotCopy when one or more copies were not allowed. The error
@@ -628,7 +631,8 @@
628 source, archive, destination_series, pocket, include_binaries,631 source, archive, destination_series, pocket, include_binaries,
629 override, close_bugs=close_bugs, create_dsd_job=create_dsd_job,632 override, close_bugs=close_bugs, create_dsd_job=create_dsd_job,
630 close_bugs_since_version=old_version, creator=creator,633 close_bugs_since_version=old_version, creator=creator,
631 sponsor=sponsor, packageupload=packageupload, logger=logger)634 sponsor=sponsor, packageupload=packageupload,
635 phased_update_percentage=phased_update_percentage, logger=logger)
632 if send_email:636 if send_email:
633 notify(637 notify(
634 person, source.sourcepackagerelease, [], [], archive,638 person, source.sourcepackagerelease, [], [], archive,
@@ -655,7 +659,8 @@
655def _do_direct_copy(source, archive, series, pocket, include_binaries,659def _do_direct_copy(source, archive, series, pocket, include_binaries,
656 override=None, close_bugs=True, create_dsd_job=True,660 override=None, close_bugs=True, create_dsd_job=True,
657 close_bugs_since_version=None, creator=None,661 close_bugs_since_version=None, creator=None,
658 sponsor=None, packageupload=None, logger=None):662 sponsor=None, packageupload=None,
663 phased_update_percentage=None, logger=None):
659 """Copy publishing records to another location.664 """Copy publishing records to another location.
660665
661 Copy each item of the given list of `SourcePackagePublishingHistory`666 Copy each item of the given list of `SourcePackagePublishingHistory`
@@ -685,6 +690,8 @@
685 :param sponsor: the sponsor `IPerson`, if this copy is being sponsored.690 :param sponsor: the sponsor `IPerson`, if this copy is being sponsored.
686 :param packageupload: The `IPackageUpload` that caused this publication691 :param packageupload: The `IPackageUpload` that caused this publication
687 to be created.692 to be created.
693 :param phased_update_percentage: The phased update percentage to apply
694 to the copied publication.
688 :param logger: An optional logger.695 :param logger: An optional logger.
689696
690 :return: a list of `ISourcePackagePublishingHistory` and697 :return: a list of `ISourcePackagePublishingHistory` and
@@ -703,7 +710,8 @@
703 version=source.sourcepackagerelease.version,710 version=source.sourcepackagerelease.version,
704 status=active_publishing_status,711 status=active_publishing_status,
705 distroseries=series, pocket=pocket)712 distroseries=series, pocket=pocket)
706 policy = archive.getOverridePolicy()713 policy = archive.getOverridePolicy(
714 phased_update_percentage=phased_update_percentage)
707 if source_in_destination.is_empty():715 if source_in_destination.is_empty():
708 # If no manual overrides were specified and the archive has an716 # If no manual overrides were specified and the archive has an
709 # override policy then use that policy to get overrides.717 # override policy then use that policy to get overrides.
710718
=== modified file 'lib/lp/soyuz/scripts/tests/test_copypackage.py'
--- lib/lp/soyuz/scripts/tests/test_copypackage.py 2013-05-29 07:24:13 +0000
+++ lib/lp/soyuz/scripts/tests/test_copypackage.py 2013-06-21 17:17:27 +0000
@@ -1380,6 +1380,27 @@
1380 section=override.section)1380 section=override.section)
1381 self.assertThat(copied_source, matcher)1381 self.assertThat(copied_source, matcher)
13821382
1383 def test_copy_with_phased_update_percentage(self):
1384 # Test the phased_update_percentage parameter for do_copy.
1385 nobby, archive, source = self._setup_archive(
1386 use_nobby=True, pocket=PackagePublishingPocket.PROPOSED)
1387 [bin_i386, bin_hppa] = self.test_publisher.getPubBinaries(
1388 pub_source=source, distroseries=nobby,
1389 pocket=PackagePublishingPocket.PROPOSED)
1390 transaction.commit()
1391 switch_dbuser('archivepublisher')
1392 [copied_source, copied_bin_i386, copied_bin_hppa] = do_copy(
1393 [source], archive, nobby, PackagePublishingPocket.UPDATES,
1394 include_binaries=True, check_permissions=False)
1395 self.assertIsNone(copied_bin_i386.phased_update_percentage)
1396 self.assertIsNone(copied_bin_hppa.phased_update_percentage)
1397 [copied_source, copied_bin_i386, copied_bin_hppa] = do_copy(
1398 [source], archive, nobby, PackagePublishingPocket.BACKPORTS,
1399 include_binaries=True, check_permissions=False,
1400 phased_update_percentage=50)
1401 self.assertEqual(50, copied_bin_i386.phased_update_percentage)
1402 self.assertEqual(50, copied_bin_hppa.phased_update_percentage)
1403
1383 def test_copy_ppa_generates_notification(self):1404 def test_copy_ppa_generates_notification(self):
1384 # When a copy into a PPA is performed, a notification is sent.1405 # When a copy into a PPA is performed, a notification is sent.
1385 nobby, archive, source = self._setup_archive()1406 nobby, archive, source = self._setup_archive()
13861407
=== modified file 'lib/lp/soyuz/stories/soyuz/xx-person-packages.txt'
--- lib/lp/soyuz/stories/soyuz/xx-person-packages.txt 2013-06-20 05:50:00 +0000
+++ lib/lp/soyuz/stories/soyuz/xx-person-packages.txt 2013-06-21 17:17:27 +0000
@@ -189,9 +189,11 @@
189Create some new source packages, source1 and source2, both created by cprov189Create some new source packages, source1 and source2, both created by cprov
190so that they appear in his +packages page.190so that they appear in his +packages page.
191191
192 >>> from storm.expr import SQL
192 >>> from zope.component import getUtility193 >>> from zope.component import getUtility
193 >>> from lp.registry.interfaces.distribution import IDistributionSet194 >>> from lp.registry.interfaces.distribution import IDistributionSet
194 >>> from lp.registry.interfaces.person import IPersonSet195 >>> from lp.registry.interfaces.person import IPersonSet
196 >>> from lp.services.database.constants import UTC_NOW
195 >>> from lp.soyuz.tests.test_publishing import SoyuzTestPublisher197 >>> from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
196 >>> from lp.soyuz.enums import PackagePublishingStatus198 >>> from lp.soyuz.enums import PackagePublishingStatus
197199
@@ -207,7 +209,8 @@
207 >>> source1 = test_publisher.getPubSource(209 >>> source1 = test_publisher.getPubSource(
208 ... status=PackagePublishingStatus.PUBLISHED,210 ... status=PackagePublishingStatus.PUBLISHED,
209 ... sourcename='source1',211 ... sourcename='source1',
210 ... archive=cprov.archive)212 ... archive=cprov.archive,
213 ... date_uploaded=UTC_NOW - SQL("INTERVAL '1 second'"))
211 >>> source1.sourcepackagerelease.creator=cprov214 >>> source1.sourcepackagerelease.creator=cprov
212 >>> source1_mark = source1.copyTo(215 >>> source1_mark = source1.copyTo(
213 ... source1.distroseries, source1.pocket, mark.archive)216 ... source1.distroseries, source1.pocket, mark.archive)
@@ -260,17 +263,17 @@
260 >>> nopriv_browser = setupBrowser(auth="Basic no-priv@canonical.com:test")263 >>> nopriv_browser = setupBrowser(auth="Basic no-priv@canonical.com:test")
261 >>> nopriv_browser.open("http://launchpad.dev/~cprov/+related-packages")264 >>> nopriv_browser.open("http://launchpad.dev/~cprov/+related-packages")
262 >>> print_ppa_rows(nopriv_browser)265 >>> print_ppa_rows(nopriv_browser)
266 source2 PPA named p3a for No Priv... Ubuntutest Breezy-autotest 666
267 ...ago None
263 source1 PPA for Celso Providelo - Ubuntutest Breezy-autotest 666268 source1 PPA for Celso Providelo - Ubuntutest Breezy-autotest 666
264 ...ago None269 ...ago None
265 source2 PPA named p3a for No Priv... Ubuntutest Breezy-autotest 666
266 ...ago None
267270
268 >>> admin_browser.open("http://launchpad.dev/~cprov/+related-packages")271 >>> admin_browser.open("http://launchpad.dev/~cprov/+related-packages")
269 >>> print_ppa_rows(admin_browser)272 >>> print_ppa_rows(admin_browser)
273 source2 PPA named p3a for No Priv... Ubuntutest Breezy-autotest 666
274 ...ago None
270 source1 PPA for Celso Providelo - Ubuntutest Breezy-autotest 666275 source1 PPA for Celso Providelo - Ubuntutest Breezy-autotest 666
271 ...ago None276 ...ago None
272 source2 PPA named p3a for No Priv... Ubuntutest Breezy-autotest 666
273 ...ago None
274277
275Let's move the publication of source1 from mark's public archive to his278Let's move the publication of source1 from mark's public archive to his
276private one and the view the page again.279private one and the view the page again.
277280
=== modified file 'lib/lp/soyuz/tests/test_archive.py'
--- lib/lp/soyuz/tests/test_archive.py 2013-06-20 05:50:00 +0000
+++ lib/lp/soyuz/tests/test_archive.py 2013-06-21 17:17:27 +0000
@@ -2154,7 +2154,8 @@
2154 target_archive.copyPackage(2154 target_archive.copyPackage(
2155 source_name, version, source_archive, to_pocket.name,2155 source_name, version, source_archive, to_pocket.name,
2156 to_series=to_series.name, include_binaries=False,2156 to_series=to_series.name, include_binaries=False,
2157 person=target_archive.owner, sponsored=sponsored)2157 person=target_archive.owner, sponsored=sponsored,
2158 phased_update_percentage=30)
21582159
2159 # The source should not be published yet in the target_archive.2160 # The source should not be published yet in the target_archive.
2160 published = target_archive.getPublishedSources(2161 published = target_archive.getPublishedSources(
@@ -2175,7 +2176,8 @@
2175 target_pocket=to_pocket,2176 target_pocket=to_pocket,
2176 include_binaries=False,2177 include_binaries=False,
2177 sponsored=sponsored,2178 sponsored=sponsored,
2178 copy_policy=PackageCopyPolicy.INSECURE))2179 copy_policy=PackageCopyPolicy.INSECURE,
2180 phased_update_percentage=30))
21792181
2180 def test_copyPackage_disallows_non_primary_archive_uploaders(self):2182 def test_copyPackage_disallows_non_primary_archive_uploaders(self):
2181 # If copying to a primary archive and you're not an uploader for2183 # If copying to a primary archive and you're not an uploader for
21822184
=== modified file 'lib/lp/soyuz/tests/test_packagecopyjob.py'
--- lib/lp/soyuz/tests/test_packagecopyjob.py 2013-06-20 05:50:00 +0000
+++ lib/lp/soyuz/tests/test_packagecopyjob.py 2013-06-21 17:17:27 +0000
@@ -206,7 +206,8 @@
206 target_pocket=PackagePublishingPocket.RELEASE,206 target_pocket=PackagePublishingPocket.RELEASE,
207 package_version="1.0-1", include_binaries=False,207 package_version="1.0-1", include_binaries=False,
208 copy_policy=PackageCopyPolicy.MASS_SYNC,208 copy_policy=PackageCopyPolicy.MASS_SYNC,
209 requester=requester, sponsored=sponsored)209 requester=requester, sponsored=sponsored,
210 phased_update_percentage=20)
210 self.assertProvides(job, IPackageCopyJob)211 self.assertProvides(job, IPackageCopyJob)
211 self.assertEqual(archive1.id, job.source_archive_id)212 self.assertEqual(archive1.id, job.source_archive_id)
212 self.assertEqual(archive1, job.source_archive)213 self.assertEqual(archive1, job.source_archive)
@@ -220,6 +221,7 @@
220 self.assertEqual(PackageCopyPolicy.MASS_SYNC, job.copy_policy)221 self.assertEqual(PackageCopyPolicy.MASS_SYNC, job.copy_policy)
221 self.assertEqual(requester, job.requester)222 self.assertEqual(requester, job.requester)
222 self.assertEqual(sponsored, job.sponsored)223 self.assertEqual(sponsored, job.sponsored)
224 self.assertEqual(20, job.phased_update_percentage)
223225
224 def test_createMultiple_creates_one_job_per_copy(self):226 def test_createMultiple_creates_one_job_per_copy(self):
225 mother = self.factory.makeDistroSeriesParent()227 mother = self.factory.makeDistroSeriesParent()
226228
=== modified file 'lib/lp/soyuz/tests/test_publishing.py'
--- lib/lp/soyuz/tests/test_publishing.py 2013-05-17 02:40:30 +0000
+++ lib/lp/soyuz/tests/test_publishing.py 2013-06-21 17:17:27 +0000
@@ -1422,7 +1422,7 @@
1422 'binaries': dict(1422 'binaries': dict(
1423 (bpr, (self.factory.makeComponent(),1423 (bpr, (self.factory.makeComponent(),
1424 self.factory.makeSection(),1424 self.factory.makeSection(),
1425 PackagePublishingPriority.REQUIRED)) for bpr in bprs),1425 PackagePublishingPriority.REQUIRED, 50)) for bpr in bprs),
1426 }1426 }
14271427
1428 def test_architecture_dependent(self):1428 def test_architecture_dependent(self):
@@ -1445,7 +1445,9 @@
1445 (args['archive'], target_das, args['pocket']),1445 (args['archive'], target_das, args['pocket']),
1446 (bpph.archive, bpph.distroarchseries, bpph.pocket))1446 (bpph.archive, bpph.distroarchseries, bpph.pocket))
1447 self.assertEqual(1447 self.assertEqual(
1448 overrides, (bpph.component, bpph.section, bpph.priority))1448 overrides,
1449 (bpph.component, bpph.section, bpph.priority,
1450 bpph.phased_update_percentage))
1449 self.assertEqual(PackagePublishingStatus.PENDING, bpph.status)1451 self.assertEqual(PackagePublishingStatus.PENDING, bpph.status)
14501452
1451 def test_architecture_independent(self):1453 def test_architecture_independent(self):
14521454
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2013-06-20 05:50:00 +0000
+++ lib/lp/testing/factory.py 2013-06-21 17:17:27 +0000
@@ -3809,7 +3809,7 @@
3809 archive, distroarchseries.distroseries, pocket,3809 archive, distroarchseries.distroseries, pocket,
3810 {binarypackagerelease: (3810 {binarypackagerelease: (
3811 binarypackagerelease.component, binarypackagerelease.section,3811 binarypackagerelease.component, binarypackagerelease.section,
3812 priority)})3812 priority, None)})
3813 for bpph in bpphs:3813 for bpph in bpphs:
3814 naked_bpph = removeSecurityProxy(bpph)3814 naked_bpph = removeSecurityProxy(bpph)
3815 naked_bpph.status = status3815 naked_bpph.status = status