← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~rvb/launchpad/init-multiple-parents-bug-777120 into lp:launchpad/db-devel

 

Raphaël Victor Badin has proposed merging lp:~rvb/launchpad/init-multiple-parents-bug-777120 into lp:launchpad/db-devel.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #777120 in Launchpad itself: "DistroSeriesDerivationVocabularyFactory needs revisiting in light of multiple-parent work"
  https://bugs.launchpad.net/launchpad/+bug/777120

For more details, see:
https://code.launchpad.net/~rvb/launchpad/init-multiple-parents-bug-777120/+merge/63341

This branch fixes the vocabulary of possible parents for a derived series (DistroSeriesDerivationVocabulary) so that it uses DistroSeriesParent -instead of previous_series). It also fixes the +initseries page to disable the rebuild option if an initialized series (i.e. a series with published sources) already exists in the distribution.

= Tests =
(New tests)
./bin/test -cvv test_distroseries test_rebuilding_allowed
./bin/test -cvv test_distroseries test_rebuilding_not_allowed
./bin/test -cvv test_distroseries_vocabularies test_distribution_with_derived_series_from_multiple_parents

(Modified tests)
./bin/test -cvv test_distroseries_vocabularies
./bin/test -cvv -t distribution.txt

= QA =
- Test initializing a series from a distribution with an existing initialised series: it should not be possible to rebuild the packages
- Test initializing a series from a distribution without any existing initialised series: it should be possible to rebuild the packages.
-- 
https://code.launchpad.net/~rvb/launchpad/init-multiple-parents-bug-777120/+merge/63341
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~rvb/launchpad/init-multiple-parents-bug-777120 into lp:launchpad/db-devel.
=== modified file 'lib/lp/registry/browser/distroseries.py'
--- lib/lp/registry/browser/distroseries.py	2011-06-03 00:13:41 +0000
+++ lib/lp/registry/browser/distroseries.py	2011-06-03 09:34:37 +0000
@@ -647,6 +647,12 @@
         return getFeatureFlag("soyuz.derived_series_ui.enabled") is not None
 
     @property
+    def rebuilding_allowed(self):
+        # If the distro has got any initialised series already,
+        # no rebuilding is allowed.
+        return not self.context.distribution.has_published_sources
+
+    @property
     def next_url(self):
         return canonical_url(self.context)
 

=== modified file 'lib/lp/registry/browser/tests/test_distroseries.py'
--- lib/lp/registry/browser/tests/test_distroseries.py	2011-06-02 18:36:43 +0000
+++ lib/lp/registry/browser/tests/test_distroseries.py	2011-06-03 09:34:37 +0000
@@ -455,6 +455,26 @@
                 u"javascript-disabled",
                 message.get("class").split())
 
+    def test_rebuilding_allowed(self):
+        # If the distro has no initialised series, rebuilding is allowed.
+        distroseries = self.factory.makeDistroSeries()
+        self.factory.makeDistroSeries(
+            distribution=distroseries.distribution)
+        view = create_initialized_view(distroseries, "+initseries")
+
+        self.assertTrue(view.rebuilding_allowed)
+
+    def test_rebuilding_not_allowed(self):
+        # If the distro has an initialised series, no rebuilding is allowed.
+        distroseries = self.factory.makeDistroSeries()
+        another_distroseries = self.factory.makeDistroSeries(
+            distribution=distroseries.distribution)
+        self.factory.makeSourcePackagePublishingHistory(
+            distroseries=another_distroseries)
+        view = create_initialized_view(distroseries, "+initseries")
+
+        self.assertFalse(view.rebuilding_allowed)
+
 
 class DistroSeriesDifferenceMixin:
     """A helper class for testing differences pages"""

=== modified file 'lib/lp/registry/doc/distribution.txt'
--- lib/lp/registry/doc/distribution.txt	2011-05-27 19:53:20 +0000
+++ lib/lp/registry/doc/distribution.txt	2011-06-03 09:34:37 +0000
@@ -142,6 +142,15 @@
     >>> gentoo.has_published_binaries
     False
 
+You can use the has_published_sources property to find out if the
+distribution has any published sources.
+
+    >>> ubuntu.has_published_sources
+    True
+
+    >>> gentoo.has_published_sources
+    False
+
 
 Distribution Sorting
 --------------------

=== modified file 'lib/lp/registry/interfaces/distribution.py'
--- lib/lp/registry/interfaces/distribution.py	2011-05-29 21:18:09 +0000
+++ lib/lp/registry/interfaces/distribution.py	2011-06-03 09:34:37 +0000
@@ -340,6 +340,11 @@
                       "on disk."),
         readonly=True, required=False)
 
+    has_published_sources = Bool(
+        title=_("Has Published Sources"),
+        description=_("True if this distribution has sources published."),
+        readonly=True, required=False)
+
     def getArchiveIDList(archive=None):
         """Return a list of archive IDs suitable for sqlvalues() or quote().
 

=== modified file 'lib/lp/registry/javascript/distroseries.js'
--- lib/lp/registry/javascript/distroseries.js	2011-06-01 10:31:05 +0000
+++ lib/lp/registry/javascript/distroseries.js	2011-06-03 09:34:37 +0000
@@ -1369,6 +1369,15 @@
                              "Copy Source and Binaries"])
             .set("choice", "Copy Source and Binaries")
             .render(form_table_body);
+    // Disable rebuilding if LP.cache['rebuilding_allowed'] is false.
+    if (!LP.cache['rebuilding_allowed']) {
+        package_copy_options.fieldNode
+            .one('input[value="Copy Source and Rebuild"]')
+            .set('disabled', 'disabled');
+        package_copy_options.set("description", (
+            "Note that you cannot rebuild sources because the " +
+            "distribution already has an initialised series."));
+    }
     var form_actions =
         new DeriveDistroSeriesActionsWidget({
             context: LP.cache.context,

=== modified file 'lib/lp/registry/model/distribution.py'
--- lib/lp/registry/model/distribution.py	2011-05-27 21:12:25 +0000
+++ lib/lp/registry/model/distribution.py	2011-06-03 09:34:37 +0000
@@ -29,7 +29,10 @@
     Or,
     SQL,
     )
-from storm.store import Store
+from storm.store import (
+    EmptyResultSet,
+    Store,
+    )
 from zope.component import getUtility
 from zope.interface import (
     alsoProvides,
@@ -1879,6 +1882,14 @@
 
         return weight_function
 
+    @property
+    def has_published_sources(self):
+        archives_sources = EmptyResultSet()
+        for archive in self.all_distro_archives:
+            archives_sources = archives_sources.union(
+                archive.getPublishedSources())
+        return not archives_sources.is_empty()
+
 
 class DistributionSet:
     """This class is to deal with Distribution related stuff"""

=== modified file 'lib/lp/registry/templates/distroseries-initialize.pt'
--- lib/lp/registry/templates/distroseries-initialize.pt	2011-05-30 15:17:11 +0000
+++ lib/lp/registry/templates/distroseries-initialize.pt	2011-06-03 09:34:37 +0000
@@ -26,6 +26,9 @@
         please use the <code>initDerivedDistroSeries</code> API call via the
         web service.
       </p>
+      <script
+       tal:content="string:LP.cache['rebuilding_allowed'] = ('${view/rebuilding_allowed}' === 'True');">
+      </script>
       <div class="unseen" id="initseries-form-container">
         <metal:form use-macro="context/@@launchpad_form/form" />
       </div>

=== modified file 'lib/lp/registry/tests/test_distroseries_vocabularies.py'
--- lib/lp/registry/tests/test_distroseries_vocabularies.py	2011-05-31 15:08:34 +0000
+++ lib/lp/registry/tests/test_distroseries_vocabularies.py	2011-06-03 09:34:37 +0000
@@ -13,9 +13,7 @@
 from pytz import utc
 from testtools.matchers import Equals
 from zope.component import getUtility
-from zope.schema.interfaces import (
-    IVocabularyFactory,
-    )
+from zope.schema.interfaces import IVocabularyFactory
 from zope.security.proxy import removeSecurityProxy
 
 from canonical.database.sqlbase import flush_database_caches
@@ -70,16 +68,38 @@
         # the vocabulary factory returns a vocabulary for all distroseries of
         # the distribution from which the derived series have been derived.
         parent_distroseries = self.factory.makeDistroSeries()
-        # Create a sibling to the parent.
         self.factory.makeDistroSeries(
             distribution=parent_distroseries.distribution)
-        distroseries = self.factory.makeDistroSeries(
-            previous_series=parent_distroseries)
+        distroseries = self.factory.makeDistroSeries()
+        self.factory.makeDistroSeriesParent(
+            derived_series=distroseries, parent_series=parent_distroseries)
         vocabulary = DistroSeriesDerivationVocabulary(distroseries)
         expected_distroseries = set(parent_distroseries.distribution.series)
         observed_distroseries = set(term.value for term in vocabulary)
         self.assertEqual(expected_distroseries, observed_distroseries)
 
+    def test_distribution_with_derived_series_from_multiple_parents(self):
+        # Given a distribution with series, one or more of which are derived
+        # from multiple parents, the vocabulary factory returns a vocabulary
+        # for all distroseries of the distribution*s* from which the derived
+        # series have been derived.
+        parent_distroseries = self.factory.makeDistroSeries()
+        another_parent_distroseries = self.factory.makeDistroSeries()
+        self.factory.makeDistroSeries(
+            distribution=parent_distroseries.distribution)
+        distroseries = self.factory.makeDistroSeries()
+        self.factory.makeDistroSeriesParent(
+            derived_series=distroseries, parent_series=parent_distroseries)
+        self.factory.makeDistroSeriesParent(
+            derived_series=distroseries,
+            parent_series=another_parent_distroseries)
+        vocabulary = DistroSeriesDerivationVocabulary(distroseries)
+        expected_distroseries = set(
+            parent_distroseries.distribution.series).union(
+                set(another_parent_distroseries.distribution.series))
+        observed_distroseries = set(term.value for term in vocabulary)
+        self.assertEqual(expected_distroseries, observed_distroseries)
+
     def test_distribution_with_derived_series_of_self(self):
         # Given a distribution with series derived from other of its series
         # (which shouldn't happen), the vocabulary factory returns a
@@ -87,8 +107,9 @@
         # given distribution.
         parent_distroseries = self.factory.makeDistroSeries()
         distroseries = self.factory.makeDistroSeries(
-            distribution=parent_distroseries.distribution,
-            previous_series=parent_distroseries)
+            distribution=parent_distroseries.distribution)
+        self.factory.makeDistroSeriesParent(
+            derived_series=distroseries, parent_series=parent_distroseries)
         vocabulary = DistroSeriesDerivationVocabulary(distroseries)
         expected_distroseries = (
             set(self.all_distroseries).difference(
@@ -168,8 +189,9 @@
         distribution = self.factory.makeDistribution()
         parent_distroseries = self.factory.makeDistroSeries()
         distroseries = self.factory.makeDistroSeries(
-            previous_series=parent_distroseries,
             distribution=distribution)
+        self.factory.makeDistroSeriesParent(
+            derived_series=distroseries, parent_series=parent_distroseries)
         flush_database_caches()
         # Reload distroseries and distribution; these will reasonably already
         # be loaded before using the vocabulary.

=== modified file 'lib/lp/registry/vocabularies.py'
--- lib/lp/registry/vocabularies.py	2011-05-31 15:08:34 +0000
+++ lib/lp/registry/vocabularies.py	2011-06-03 09:34:37 +0000
@@ -79,9 +79,7 @@
 from storm.info import ClassAlias
 from zope.component import getUtility
 from zope.interface import implements
-from zope.schema.interfaces import (
-    IVocabularyTokenized,
-    )
+from zope.schema.interfaces import IVocabularyTokenized
 from zope.schema.vocabulary import (
     SimpleTerm,
     SimpleVocabulary,
@@ -164,11 +162,15 @@
 from lp.registry.interfaces.sourcepackage import ISourcePackage
 from lp.registry.model.distribution import Distribution
 from lp.registry.model.distroseries import DistroSeries
+from lp.registry.model.distroseriesparent import DistroSeriesParent
 from lp.registry.model.featuredproject import FeaturedProject
 from lp.registry.model.karma import KarmaCategory
 from lp.registry.model.mailinglist import MailingList
 from lp.registry.model.milestone import Milestone
-from lp.registry.model.person import Person, IrcID
+from lp.registry.model.person import (
+    IrcID,
+    Person,
+    )
 from lp.registry.model.pillar import PillarName
 from lp.registry.model.product import Product
 from lp.registry.model.productrelease import ProductRelease
@@ -1603,7 +1605,8 @@
             parent.distributionID, And(
                 parent.distributionID != self.distribution.id,
                 child.distributionID == self.distribution.id,
-                child.previous_seriesID == parent.id))
+                child.id == DistroSeriesParent.derived_series_id,
+                parent.id == DistroSeriesParent.parent_series_id))
         where.append(
             DistroSeries.distributionID.is_in(parent_distributions))
         terms = self.find_terms(where)