← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~allenap/launchpad/dd-initseries-bug-727105-feature-flag into lp:launchpad

 

Gavin Panella has proposed merging lp:~allenap/launchpad/dd-initseries-bug-727105-feature-flag into lp:launchpad with lp:~allenap/launchpad/dd-initseries-bug-727105-derive-distro-series as a prerequisite.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #742511 in Launchpad itself: "+initseries: feature flag it"
  https://bugs.launchpad.net/launchpad/+bug/742511

For more details, see:
https://code.launchpad.net/~allenap/launchpad/dd-initseries-bug-727105-feature-flag/+merge/54884

- Fixes some lint in apihelpers.py, and corrects its __all__ to avoid
  import warnings.

- Adds an is_feature_enabled property to
  DistroSeriesInitializeView. This refers to a feature flag.

- When the feature is not enabled, shows an explanatory message on
  +initseries.

- Fixes an API versioning problem with PackagesetSet
  getBySeries(). The addition of getBySeries() was originally
  completed earlier in this branch's pipeline before changes in devel
  made the explicit versioning mandatory. I accidentally fixed it in
  this pipe.

-- 
https://code.launchpad.net/~allenap/launchpad/dd-initseries-bug-727105-feature-flag/+merge/54884
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~allenap/launchpad/dd-initseries-bug-727105-feature-flag into lp:launchpad.
=== modified file 'lib/canonical/launchpad/components/apihelpers.py'
--- lib/canonical/launchpad/components/apihelpers.py	2011-03-24 13:09:03 +0000
+++ lib/canonical/launchpad/components/apihelpers.py	2011-03-25 16:08:35 +0000
@@ -14,13 +14,16 @@
 __metaclass__ = type
 
 __all__ = [
-    'patch_entry_return_type',
     'patch_choice_parameter_type',
     'patch_choice_vocabulary',
     'patch_collection_property',
     'patch_collection_return_type',
+    'patch_entry_explicit_version',
+    'patch_entry_return_type',
+    'patch_list_parameter_type',
+    'patch_operation_explicit_version',
+    'patch_operations_explicit_version',
     'patch_plain_parameter_type',
-    'patch_list_parameter_type',
     'patch_reference_property',
     ]
 
@@ -148,7 +151,9 @@
         tagged = field.queryTaggedValue(LAZR_WEBSERVICE_EXPORTED)
         if tagged is None:
             continue
-        versioned = tagged.dict_for_name(version) or tagged.dict_for_name(None)
+        versioned = (
+            tagged.dict_for_name(version) or
+            tagged.dict_for_name(None))
         if versioned is None:
             # This field is explicitly published in some other version.
             # Just ignore it.

=== modified file 'lib/canonical/launchpad/interfaces/_schema_circular_imports.py'
--- lib/canonical/launchpad/interfaces/_schema_circular_imports.py	2011-03-25 16:08:33 +0000
+++ lib/canonical/launchpad/interfaces/_schema_circular_imports.py	2011-03-25 16:08:35 +0000
@@ -30,12 +30,12 @@
     patch_plain_parameter_type,
     patch_reference_property,
     )
+from canonical.launchpad.interfaces.emailaddress import IEmailAddress
 from canonical.launchpad.interfaces.message import (
     IIndexedMessage,
     IMessage,
     IUserToUserEmail,
     )
-from canonical.launchpad.interfaces.emailaddress import IEmailAddress
 from canonical.launchpad.interfaces.temporaryblobstorage import (
     ITemporaryBlobStorage,
     ITemporaryStorageManager,
@@ -68,19 +68,12 @@
     IBugTrackerSet,
     )
 from lp.bugs.interfaces.bugwatch import IBugWatch
-<<<<<<< TREE
 from lp.bugs.interfaces.cve import ICve
 from lp.bugs.interfaces.malone import IMaloneApplication
 from lp.bugs.interfaces.structuralsubscription import (
     IStructuralSubscription,
     IStructuralSubscriptionTarget,
     )
-=======
-from lp.bugs.interfaces.structuralsubscription import (
-    IStructuralSubscription,
-    IStructuralSubscriptionTarget,
-    )
->>>>>>> MERGE-SOURCE
 from lp.buildmaster.enums import BuildStatus
 from lp.buildmaster.interfaces.builder import (
     IBuilder,
@@ -88,10 +81,7 @@
     )
 from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob
 from lp.buildmaster.interfaces.buildqueue import IBuildQueue
-from lp.code.interfaces.branch import (
-    IBranch,
-    IBranchSet,
-    )
+from lp.code.interfaces.branch import IBranch
 from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal
 from lp.code.interfaces.branchmergequeue import IBranchMergeQueue
 from lp.code.interfaces.branchsubscription import IBranchSubscription
@@ -122,7 +112,9 @@
     IHWSubmissionDevice,
     IHWVendorID,
     )
-from lp.registry.interfaces.commercialsubscription import ICommercialSubscription
+from lp.registry.interfaces.commercialsubscription import (
+    ICommercialSubscription,
+    )
 from lp.registry.interfaces.distribution import IDistribution
 from lp.registry.interfaces.distributionmirror import IDistributionMirror
 from lp.registry.interfaces.distributionsourcepackage import (
@@ -138,12 +130,13 @@
 from lp.registry.interfaces.gpg import IGPGKey
 from lp.registry.interfaces.irc import IIrcID
 from lp.registry.interfaces.jabber import IJabberID
-from lp.registry.interfaces.milestone import IHasMilestones
-from lp.registry.interfaces.milestone import IMilestone
+from lp.registry.interfaces.milestone import (
+    IHasMilestones,
+    IMilestone,
+    )
 from lp.registry.interfaces.person import (
     IPerson,
     IPersonPublic,
-    IPersonSet,
     ITeam,
     )
 from lp.registry.interfaces.pillar import (
@@ -155,8 +148,10 @@
     IProduct,
     IProductSet,
     )
-from lp.registry.interfaces.productrelease import IProductRelease
-from lp.registry.interfaces.productrelease import IProductReleaseFile
+from lp.registry.interfaces.productrelease import (
+    IProductRelease,
+    IProductReleaseFile,
+    )
 from lp.registry.interfaces.productseries import (
     IProductSeries,
     ITimelineProductSeries,
@@ -166,12 +161,9 @@
     IProjectGroupSet,
     )
 from lp.registry.interfaces.sourcepackage import ISourcePackage
-<<<<<<< TREE
 from lp.registry.interfaces.ssh import ISSHKey
 from lp.registry.interfaces.teammembership import ITeamMembership
 from lp.registry.interfaces.wikiname import IWikiName
-=======
->>>>>>> MERGE-SOURCE
 from lp.services.comments.interfaces.conversation import IComment
 from lp.services.worlddata.interfaces.country import (
     ICountry,
@@ -186,8 +178,8 @@
     PackageUploadCustomFormat,
     PackageUploadStatus,
     )
+from lp.soyuz.interfaces.archive import IArchive
 from lp.soyuz.interfaces.archivedependency import IArchiveDependency
-from lp.soyuz.interfaces.archive import IArchive
 from lp.soyuz.interfaces.archivepermission import IArchivePermission
 from lp.soyuz.interfaces.archivesubscriber import IArchiveSubscriber
 from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuild
@@ -225,6 +217,7 @@
     ITranslationImportQueueEntry,
     )
 
+
 IBranch['bug_branches'].value_type.schema = IBugBranch
 IBranch['linked_bugs'].value_type.schema = IBug
 IBranch['dependent_branches'].value_type.schema = IBranchMergeProposal

=== modified file 'lib/lp/registry/browser/distroseries.py'
--- lib/lp/registry/browser/distroseries.py	2011-03-25 16:08:33 +0000
+++ lib/lp/registry/browser/distroseries.py	2011-03-25 16:08:35 +0000
@@ -91,9 +91,7 @@
 from lp.services.worlddata.interfaces.country import ICountry
 from lp.services.worlddata.interfaces.language import ILanguageSet
 from lp.soyuz.browser.packagesearch import PackageSearchViewBase
-from lp.soyuz.interfaces.archive import (
-    CannotCopy,
-    )
+from lp.soyuz.interfaces.archive import CannotCopy
 from lp.soyuz.interfaces.queue import IPackageUploadSet
 from lp.translations.browser.distroseries import (
     check_distroseries_translations_viewable,
@@ -547,6 +545,10 @@
     page_title = label
 
     @property
+    def is_feature_enabled(self):
+        return getFeatureFlag("soyuz.derived-series-ui.enabled") is not None
+
+    @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-03-25 16:08:33 +0000
+++ lib/lp/registry/browser/tests/test_distroseries.py	2011-03-25 16:08:35 +0000
@@ -5,8 +5,14 @@
 
 __metaclass__ = type
 
+from lxml import html
+
 from canonical.testing.layers import DatabaseFunctionalLayer
-from lp.testing import TestCaseWithFactory
+from lp.testing import (
+    feature_flags,
+    set_feature_flag,
+    TestCaseWithFactory,
+    )
 from lp.testing.views import create_initialized_view
 
 
@@ -19,3 +25,47 @@
         distroseries = self.factory.makeDistroSeries()
         view = create_initialized_view(distroseries, "+initseries")
         self.assertTrue(view)
+
+    def test_feature_enabled(self):
+        # The feature is disabled by default, but can be enabled by setting
+        # the soyuz.derived-series-ui.enabled flag.
+        distroseries = self.factory.makeDistroSeries()
+        view = create_initialized_view(distroseries, "+initseries")
+        with feature_flags():
+            self.assertFalse(view.is_feature_enabled)
+        with feature_flags():
+            set_feature_flag(u"soyuz.derived-series-ui.enabled", u"true")
+            self.assertTrue(view.is_feature_enabled)
+
+    def test_form_hidden_when_feature_disabled(self):
+        # The form is hidden when the feature flag is not set.
+        distroseries = self.factory.makeDistroSeries()
+        view = create_initialized_view(distroseries, "+initseries")
+        with feature_flags():
+            root = html.fromstring(view())
+            self.assertEqual(
+                [], root.cssselect("#init-series-form-container"))
+            # Instead an explanatory message is shown.
+            [message] = root.cssselect("p.error.message")
+            self.assertIn(
+                u"The Derivative Distributions feature is under development",
+                message.text)
+
+    def test_form_shown_when_feature_enabled(self):
+        # The form is shown when the feature flag is set.
+        distroseries = self.factory.makeDistroSeries()
+        view = create_initialized_view(distroseries, "+initseries")
+        with feature_flags():
+            set_feature_flag(u"soyuz.derived-series-ui.enabled", u"true")
+            root = html.fromstring(view())
+            self.assertNotEqual(
+                [], root.cssselect("#init-series-form-container"))
+            # A different explanatory message is shown for clients that don't
+            # process Javascript.
+            [message] = root.cssselect("p.error.message")
+            self.assertIn(
+                u"Javascript is required to use this page",
+                message.text)
+            self.assertIn(
+                u"javascript-disabled",
+                message.get("class").split())

=== modified file 'lib/lp/registry/templates/distroseries-initialize.pt'
--- lib/lp/registry/templates/distroseries-initialize.pt	2011-03-25 16:08:33 +0000
+++ lib/lp/registry/templates/distroseries-initialize.pt	2011-03-25 16:08:35 +0000
@@ -12,6 +12,7 @@
   </metal:head-epilogue>
   <body>
     <div metal:fill-slot="main">
+      <tal:enabled condition="view/is_feature_enabled">
       <div class="top-portlet">
         This page allows you to initialize a distribution series.
       </div>
@@ -29,6 +30,16 @@
           Y.on('domready', Y.lp.registry.distroseries.initseries.setup);
         });
       </script>
+      </tal:enabled>
+      <tal:disabled condition="not:view/is_feature_enabled">
+      <p class="error message">
+        The Derivative Distributions feature is under development
+        and is not yet generally available. You can read more about
+        this feature on its <a
+        href="https://dev.launchpad.net/LEP/DerivativeDistributions";>proposal
+        page</a>.
+      </p>
+      </tal:disabled>
     </div>
   </body>
 </html>

=== modified file 'lib/lp/soyuz/interfaces/packageset.py'
--- lib/lp/soyuz/interfaces/packageset.py	2011-03-25 16:08:33 +0000
+++ lib/lp/soyuz/interfaces/packageset.py	2011-03-25 16:08:35 +0000
@@ -22,6 +22,7 @@
     export_read_operation,
     export_write_operation,
     exported,
+    operation_for_version,
     operation_parameters,
     operation_returns_collection_of,
     operation_returns_entry,
@@ -425,13 +426,13 @@
         """
 
     @operation_parameters(
-        distroseries=Reference(
-            IDistroSeries, title=_("Distroseries"), required=True,
-            readonly=True, description=_(
+        distroseries=copy_field(
+            IPackageset['distroseries'], description=_(
                 "The distribution series to which the packagesets "
                 "are related.")))
     @operation_returns_collection_of(IPackageset)
     @export_read_operation()
+    @operation_for_version("beta")
     def getBySeries(distroseries):
         """Return the package sets associated with the given distroseries.