← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~cjwatson/launchpad/remove-derived-series-ui-flag into lp:launchpad

 

Colin Watson has proposed merging lp:~cjwatson/launchpad/remove-derived-series-ui-flag into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/remove-derived-series-ui-flag/+merge/117249

The soyuz.derived_series_ui.enabled feature flag has been enabled everywhere since 2011-06-09, and is now working well for such things as initialising new Ubuntu series so unlikely to be disabled again.  We might as well remove the code allowing it to be turned off.
-- 
https://code.launchpad.net/~cjwatson/launchpad/remove-derived-series-ui-flag/+merge/117249
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/remove-derived-series-ui-flag into lp:launchpad.
=== modified file 'lib/lp/registry/browser/distroseries.py'
--- lib/lp/registry/browser/distroseries.py	2012-06-29 05:38:35 +0000
+++ lib/lp/registry/browser/distroseries.py	2012-07-30 12:16:24 +0000
@@ -289,7 +289,6 @@
     @enabled_with_permission('launchpad.Edit')
     def initseries(self):
         enabled = (
-             getFeatureFlag('soyuz.derived_series_ui.enabled') is not None and
              not self.context.isInitializing() and
              not self.context.isInitialized())
         text = 'Initialize series'
@@ -760,17 +759,8 @@
         """Stub for the Javascript in the page to use."""
 
     @cachedproperty
-    def is_derived_series_feature_enabled(self):
-        return getFeatureFlag("soyuz.derived_series_ui.enabled") is not None
-
-    @cachedproperty
-    def show_derivation_not_yet_available(self):
-        return not self.is_derived_series_feature_enabled
-
-    @cachedproperty
     def show_derivation_form(self):
         return (
-            self.is_derived_series_feature_enabled and
             not self.show_previous_series_empty_message and
             not self.show_already_initializing_message and
             not self.show_already_initialized_message and
@@ -783,30 +773,23 @@
         # The distribution already has initialized series and this
         # distroseries has no previous_series.
         return (
-            self.is_derived_series_feature_enabled and
             self.context.distribution.has_published_sources and
             self.context.previous_series is None)
 
     @cachedproperty
     def show_already_initialized_message(self):
-        return (
-            self.is_derived_series_feature_enabled and
-            self.context.isInitialized())
+        return self.context.isInitialized()
 
     @cachedproperty
     def show_already_initializing_message(self):
-        return (
-            self.is_derived_series_feature_enabled and
-            self.context.isInitializing())
+        return self.context.isInitializing()
 
     @cachedproperty
     def show_no_publisher_message(self):
         distribution = self.context.distribution
         publisherconfigset = getUtility(IPublisherConfigSet)
         pub_config = publisherconfigset.getByDistribution(distribution)
-        return (
-            self.is_derived_series_feature_enabled and
-            pub_config is None)
+        return pub_config is None
 
     @property
     def next_url(self):
@@ -910,13 +893,6 @@
     # Search vocabulary.
     search_higher_parent_option = False
 
-    def initialize(self):
-        """Redirect to the derived series if the feature is not enabled."""
-        if not getFeatureFlag('soyuz.derived_series_ui.enabled'):
-            self.request.response.redirect(canonical_url(self.context))
-            return
-        super(DistroSeriesDifferenceBaseView, self).initialize()
-
     def initialize_sync_label(self, label):
         # Owing to the design of Action/Actions in zope.formlib.form - actions
         # is actually a descriptor that copies itself and its actions when

=== modified file 'lib/lp/registry/browser/tests/test_distroseries.py'
--- lib/lp/registry/browser/tests/test_distroseries.py	2012-06-04 16:13:51 +0000
+++ lib/lp/registry/browser/tests/test_distroseries.py	2012-07-30 12:16:24 +0000
@@ -55,10 +55,7 @@
 from lp.services.config import config
 from lp.services.database.constants import UTC_NOW
 from lp.services.database.sqlbase import flush_database_caches
-from lp.services.features import (
-    get_relevant_feature_controller,
-    getFeatureFlag,
-    )
+from lp.services.features import getFeatureFlag
 from lp.services.features.testing import FeatureFixture
 from lp.services.propertycache import get_property_cache
 from lp.services.utils import utc_now
@@ -125,16 +122,9 @@
 from lp.testing.views import create_initialized_view
 
 
-def set_derived_series_ui_feature_flag(test_case):
-    test_case.useFixture(FeatureFixture({
-        u'soyuz.derived_series_ui.enabled': u'on',
-        }))
-
-
 def set_derived_series_sync_feature_flag(test_case):
     test_case.useFixture(FeatureFixture({
         u'soyuz.derived_series_sync.enabled': u'on',
-        u'soyuz.derived_series_ui.enabled': u'on',
         }))
 
 
@@ -315,30 +305,9 @@
                 parent_series=first_parent_series)
         return derived_series
 
-    def test_differences_no_flag_no_portlet(self):
-        # The portlet is not displayed if the feature flag is not enabled.
-        derived_series = self._setupDifferences('deri', 'sid', 1, 2, 2)
-        portlet_header = soupmatchers.HTMLContains(
-            soupmatchers.Tag(
-                'Derivation portlet header', 'h2',
-                text='Derived from Sid'),
-            )
-
-        with person_logged_in(self.simple_user):
-            view = create_initialized_view(
-                derived_series,
-                '+index',
-                principal=self.simple_user)
-            html_content = view()
-
-        self.assertEqual(
-            None, getFeatureFlag('soyuz.derived_series_ui.enabled'))
-        self.assertThat(html_content, Not(portlet_header))
-
     def test_differences_portlet_all_differences(self):
         # The difference portlet shows the differences with the parent
         # series.
-        set_derived_series_ui_feature_flag(self)
         derived_series = self._setupDifferences('deri', 'sid', 1, 2, 3)
         portlet_display = soupmatchers.HTMLContains(
             soupmatchers.Tag(
@@ -350,9 +319,6 @@
                 derived_series,
                 '+index',
                 principal=self.simple_user)
-            # XXX rvb 2011-04-12 bug=758649: LaunchpadTestRequest overrides
-            # self.features to NullFeatureController.
-            view.request.features = get_relevant_feature_controller()
             html_content = view()
 
         self.assertThat(html_content, portlet_display)
@@ -360,7 +326,6 @@
     def test_differences_portlet_all_differences_multiple_parents(self):
         # The difference portlet shows the differences with the multiple
         # parent series.
-        set_derived_series_ui_feature_flag(self)
         derived_series = self._setupDifferences(
             'deri', ['sid1', 'sid2'], 0, 1, 0)
         portlet_display = soupmatchers.HTMLContains(soupmatchers.Tag(
@@ -372,9 +337,6 @@
                 derived_series,
                 '+index',
                 principal=self.simple_user)
-            # XXX rvb 2011-04-12 bug=758649: LaunchpadTestRequest overrides
-            # self.features to NullFeatureController.
-            view.request.features = get_relevant_feature_controller()
             html_text = view()
 
         self.assertThat(html_text, portlet_display)
@@ -382,7 +344,6 @@
     def test_differences_portlet_no_differences(self):
         # The difference portlet displays 'No differences' if there is no
         # differences with the parent.
-        set_derived_series_ui_feature_flag(self)
         derived_series = self._setupDifferences('deri', 'sid', 0, 0, 0)
         portlet_display = soupmatchers.HTMLContains(
             soupmatchers.Tag(
@@ -398,9 +359,6 @@
                 derived_series,
                 '+index',
                 principal=self.simple_user)
-            # XXX rvb 2011-04-12 bug=758649: LaunchpadTestRequest overrides
-            # self.features to NullFeatureController.
-            view.request.features = get_relevant_feature_controller()
             html_content = view()
 
         self.assertThat(html_content, portlet_display)
@@ -408,7 +366,6 @@
     def test_differences_portlet_initializing(self):
         # The difference portlet displays 'The series is initializing.' if
         # there is an initializing job for the series.
-        set_derived_series_ui_feature_flag(self)
         derived_series = self.factory.makeDistroSeries()
         parent_series = self.factory.makeDistroSeries()
         self.simple_user = self.factory.makePerson()
@@ -428,9 +385,6 @@
                 derived_series,
                 '+index',
                 principal=self.simple_user)
-            # XXX rvb 2011-04-12 bug=758649: LaunchpadTestRequest overrides
-            # self.features to NullFeatureController.
-            view.request.features = get_relevant_feature_controller()
             html_content = view()
 
         self.assertTrue(derived_series.isInitializing())
@@ -439,7 +393,6 @@
     def test_differences_portlet_initialization_failed(self):
         # The difference portlet displays a failure message if initialization
         # for the series has failed.
-        set_derived_series_ui_feature_flag(self)
         derived_series = self.factory.makeDistroSeries()
         parent_series = self.factory.makeDistroSeries()
         self.simple_user = self.factory.makePerson()
@@ -488,17 +441,8 @@
         else:
             self.assertThat(html_content, Not(init_link_matcher))
 
-    def test_differences_init_link_no_feature(self):
-        # The link to +initseries is not displayed if the feature flag
-        # is not enabled.
-        series = self.factory.makeDistroSeries()
-
-        self.assertInitSeriesLinkNotPresent(series, 'admin')
-
     def test_differences_init_link_admin(self):
-        # The link to +initseries is displayed to admin users if the
-        # feature flag is enabled.
-        set_derived_series_ui_feature_flag(self)
+        # The link to +initseries is displayed to admin users.
         series = self.factory.makeDistroSeries()
 
         self.assertInitSeriesLinkPresent(series, 'admin')
@@ -506,7 +450,6 @@
     def test_differences_init_link_series_driver(self):
         # The link to +initseries is displayed to the distroseries's
         # drivers.
-        set_derived_series_ui_feature_flag(self)
         distroseries = self.factory.makeDistroSeries()
         driver = self.factory.makePerson()
         with celebrity_logged_in('admin'):
@@ -517,7 +460,6 @@
     def test_differences_init_link_not_admin(self):
         # The link to +initseries is not displayed to not admin users if the
         # feature flag is enabled.
-        set_derived_series_ui_feature_flag(self)
         series = self.factory.makeDistroSeries()
         person = self.factory.makePerson()
 
@@ -526,7 +468,6 @@
     def test_differences_init_link_initialized(self):
         # The link to +initseries is not displayed if the series is
         # already initialized (i.e. has any published package).
-        set_derived_series_ui_feature_flag(self)
         series = self.factory.makeDistroSeries()
         self.factory.makeSourcePackagePublishingHistory(
             archive=series.main_archive,
@@ -537,7 +478,6 @@
     def test_differences_init_link_series_initializing(self):
         # The link to +initseries is not displayed if the series is
         # initializing.
-        set_derived_series_ui_feature_flag(self)
         series = self.factory.makeDistroSeries()
         parent_series = self.factory.makeDistroSeries()
         job_source = getUtility(IInitializeDistroSeriesJobSource)
@@ -557,7 +497,6 @@
     def test_initialization_failed_can_retry(self):
         # When initialization has failed and the user has the ability to retry
         # it prompts the user to try again.
-        set_derived_series_ui_feature_flag(self)
         series = self.factory.makeDistroSeries()
         parent = self.factory.makeDistroSeries()
         job = self.job_source.create(series, [parent.id])
@@ -574,7 +513,6 @@
     def test_initialization_failed_cannot_retry(self):
         # When initialization has failed and the user does not have the
         # ability to retry it suggests contacting someone who can.
-        set_derived_series_ui_feature_flag(self)
         series = self.factory.makeDistroSeries()
         parent = self.factory.makeDistroSeries()
         job = self.job_source.create(series, [parent.id])
@@ -625,7 +563,6 @@
         # When initialization has failed an explanation of the failure can be
         # displayed. It depends on the nature of the failure; only some error
         # types are displayed.
-        set_derived_series_ui_feature_flag(self)
         series = self.factory.makeDistroSeries()
         parent = self.factory.makeDistroSeries()
         job = self.job_source.create(series, [parent.id])
@@ -755,54 +692,21 @@
         view = create_initialized_view(distroseries, "+initseries")
         self.assertTrue(view)
 
-    def test_is_derived_series_feature_disabled(self):
-        # The feature is disabled by default.
-        distroseries = self.factory.makeDistroSeries()
-        view = create_initialized_view(distroseries, "+initseries")
-        with FeatureFixture({}):
-            self.assertFalse(view.is_derived_series_feature_enabled)
-
-    def test_is_derived_series_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()
-        flags = {u"soyuz.derived_series_ui.enabled": u"true"}
-        with FeatureFixture(flags):
-            view = create_initialized_view(distroseries, "+initseries")
-            self.assertTrue(view.is_derived_series_feature_enabled)
-
-    def test_form_hidden_when_derived_series_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 FeatureFixture({}):
-            root = html.fromstring(view())
-            self.assertEqual(
-                [], root.cssselect("#initseries-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_derived_series_feature_enabled(self):
-        # The form is shown when the feature flag is set.
-        distroseries = self.factory.makeDistroSeries()
-        view = create_initialized_view(distroseries, "+initseries")
-        flags = {u"soyuz.derived_series_ui.enabled": u"true"}
-        with FeatureFixture(flags):
-            root = html.fromstring(view())
-            self.assertNotEqual(
-                [], root.cssselect("#initseries-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())
+    def test_form_shown(self):
+        # The form is shown.
+        distroseries = self.factory.makeDistroSeries()
+        view = create_initialized_view(distroseries, "+initseries")
+        root = html.fromstring(view())
+        self.assertNotEqual([], root.cssselect("#initseries-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())
 
     def test_seriesToVocab(self):
         distroseries = self.factory.makeDistroSeries()
@@ -857,42 +761,34 @@
             cache['previous_parents'][1])
 
     def test_form_hidden_when_distroseries_is_initialized(self):
-        # The form is hidden when the feature flag is set but the series has
-        # already been initialized.
+        # The form is hidden when the series has already been initialized.
         distroseries = self.factory.makeDistroSeries(
             previous_series=self.factory.makeDistroSeries())
         self.factory.makeSourcePackagePublishingHistory(
             distroseries=distroseries, archive=distroseries.main_archive)
         view = create_initialized_view(distroseries, "+initseries")
-        flags = {u"soyuz.derived_series_ui.enabled": u"true"}
-        with FeatureFixture(flags):
-            root = html.fromstring(view())
-            self.assertEqual(
-                [], root.cssselect("#initseries-form-container"))
-            # Instead an explanatory message is shown.
-            [message] = root.cssselect("p.error.message")
-            self.assertThat(
-                message.text, EqualsIgnoringWhitespace(
-                    u"This series already contains source packages "
-                    u"and cannot be initialized again."))
+        root = html.fromstring(view())
+        self.assertEqual([], root.cssselect("#initseries-form-container"))
+        # Instead an explanatory message is shown.
+        [message] = root.cssselect("p.error.message")
+        self.assertThat(
+            message.text, EqualsIgnoringWhitespace(
+                u"This series already contains source packages "
+                u"and cannot be initialized again."))
 
     def test_form_hidden_when_distroseries_is_being_initialized(self):
-        # The form is hidden when the feature flag is set but the series has
-        # already been derived.
+        # The form is hidden when the series has already been derived.
         distroseries = self.factory.makeDistroSeries()
         getUtility(IInitializeDistroSeriesJobSource).create(
             distroseries, [self.factory.makeDistroSeries().id])
         view = create_initialized_view(distroseries, "+initseries")
-        flags = {u"soyuz.derived_series_ui.enabled": u"true"}
-        with FeatureFixture(flags):
-            root = html.fromstring(view())
-            self.assertEqual(
-                [], root.cssselect("#initseries-form-container"))
-            # Instead an explanatory message is shown.
-            [message] = root.cssselect("p.error.message")
-            self.assertThat(
-                message.text, EqualsIgnoringWhitespace(
-                    u"This series is already being initialized."))
+        root = html.fromstring(view())
+        self.assertEqual([], root.cssselect("#initseries-form-container"))
+        # Instead an explanatory message is shown.
+        [message] = root.cssselect("p.error.message")
+        self.assertThat(
+            message.text, EqualsIgnoringWhitespace(
+                u"This series is already being initialized."))
 
     def test_form_hidden_when_previous_series_none(self):
         # If the distribution has an initialized series and the
@@ -905,18 +801,15 @@
         self.factory.makeSourcePackagePublishingHistory(
             distroseries=another_distroseries)
         view = create_initialized_view(distroseries, "+initseries")
-        flags = {u"soyuz.derived_series_ui.enabled": u"true"}
-        with FeatureFixture(flags):
-            root = html.fromstring(view())
-            self.assertEqual(
-                [], root.cssselect("#initseries-form-container"))
-            # Instead an explanatory message is shown.
-            [message] = root.cssselect("p.error.message")
-            self.assertThat(
-                message.text, EqualsIgnoringWhitespace(
-                    u'Unable to initialize series: the distribution '
-                    u'already has initialized series and this distroseries '
-                    u'has no previous series.'))
+        root = html.fromstring(view())
+        self.assertEqual([], root.cssselect("#initseries-form-container"))
+        # Instead an explanatory message is shown.
+        [message] = root.cssselect("p.error.message")
+        self.assertThat(
+            message.text, EqualsIgnoringWhitespace(
+                u'Unable to initialize series: the distribution '
+                u'already has initialized series and this distroseries '
+                u'has no previous series.'))
 
     def test_form_hidden_when_no_publisher_config_set_up(self):
         # If the distribution has no publisher config set up:
@@ -926,18 +819,14 @@
         distroseries = self.factory.makeDistroSeries(
             distribution=distribution)
         view = create_initialized_view(distroseries, "+initseries")
-        flags = {u"soyuz.derived_series_ui.enabled": u"true"}
-        with FeatureFixture(flags):
-            root = html.fromstring(view())
-            self.assertEqual(
-                [], root.cssselect("#initseries-form-container"))
-            # Instead an explanatory message is shown.
-            [message] = root.cssselect("p.error.message")
-            self.assertThat(
-                message.text, EqualsIgnoringWhitespace(
-                    u"The series' distribution has no publisher "
-                    u"configuration. Please ask an administrator to set "
-                    "this up."))
+        root = html.fromstring(view())
+        self.assertEqual([], root.cssselect("#initseries-form-container"))
+        # Instead an explanatory message is shown.
+        [message] = root.cssselect("p.error.message")
+        self.assertThat(
+            message.text, EqualsIgnoringWhitespace(
+                u"The series' distribution has no publisher configuration. "
+                u"Please ask an administrator to set this up."))
 
 
 class TestDistroSeriesInitializeViewAccess(TestCaseWithFactory):
@@ -948,7 +837,6 @@
     def setUp(self):
         super(TestDistroSeriesInitializeViewAccess,
               self).setUp('foo.bar@xxxxxxxxxxxxx')
-        set_derived_series_ui_feature_flag(self)
 
     def test_initseries_access_anon(self):
         # Anonymous users cannot access +initseries.
@@ -1030,7 +918,6 @@
     def setUp(self):
         super(TestDistroSeriesLocalDiffPerformance,
              self).setUp('foo.bar@xxxxxxxxxxxxx')
-        set_derived_series_ui_feature_flag(self)
         self.simple_user = self.factory.makePerson()
 
     def _assertQueryCount(self, derived_series):
@@ -1193,7 +1080,6 @@
         self.factory.makeDistroSeriesDifference(
             derived_series=derived_series)
 
-        set_derived_series_ui_feature_flag(self)
         view = create_initialized_view(
             derived_series, '+localpackagediffs', principal=simple_user)
 
@@ -1210,7 +1096,6 @@
                 packages=[ds_diff.source_package_name],
                 distroseries=ds_diff.derived_series)
 
-        set_derived_series_ui_feature_flag(self)
         simple_user = self.factory.makePerson()
         with person_logged_in(simple_user):
             view = create_initialized_view(
@@ -1235,7 +1120,6 @@
                     packages=[ds_diff.source_package_name],
                     distroseries=ds_diff.derived_series)
 
-        set_derived_series_ui_feature_flag(self)
         simple_user = self.factory.makePerson()
         with person_logged_in(simple_user):
             view = create_initialized_view(
@@ -1250,20 +1134,6 @@
             html_content, packageset_text, 'packagesets',
             'Packagesets')
 
-    def test_view_redirects_without_feature_flag(self):
-        # If the feature flag soyuz.derived_series_ui.enabled is not set the
-        # view simply redirects to the derived series.
-        derived_series, parent_series = self._createChildAndParent()
-
-        self.assertIs(
-            None, getFeatureFlag('soyuz.derived_series_ui.enabled'))
-        view = self.makeView(derived_series)
-
-        response = view.request.response
-        self.assertEqual(302, response.getStatus())
-        self.assertEqual(
-            canonical_url(derived_series), response.getHeader('location'))
-
     def test_label(self):
         # The view label includes the names of both series.
         derived_series, parent_series = self._createChildAndParent()
@@ -1321,7 +1191,6 @@
     def test_template_includes_help_link(self):
         # The help link for popup help is included.
         derived_series, parent_series = self._createChildAndParent()
-        set_derived_series_ui_feature_flag(self)
         view = self.makeView(derived_series)
 
         soup = BeautifulSoup(view())
@@ -1338,7 +1207,6 @@
             difference.addComment(difference.owner, "Earlier comment")
             difference.addComment(difference.owner, "Latest comment")
 
-        set_derived_series_ui_feature_flag(self)
         view = self.makeView(derived_series)
 
         # Find all the rows within the body of the table
@@ -1357,7 +1225,6 @@
         difference = self.factory.makeDistroSeriesDifference(
             derived_series=derived_series)
 
-        set_derived_series_ui_feature_flag(self)
         view = self.makeView(derived_series)
         soup = BeautifulSoup(view())
         diff_table = soup.find('table', {'class': 'listing'})
@@ -1388,7 +1255,6 @@
             parent_series=parent_series,
             source_package_name_str=package_name,
             derived_series=derived_series)
-        set_derived_series_ui_feature_flag(self)
         view = create_initialized_view(
             derived_series, '+localpackagediffs')
         multiple_parents_matches = soupmatchers.HTMLContains(
@@ -1430,7 +1296,6 @@
             distroseries=derived_series,
             version=new_version)
 
-        set_derived_series_ui_feature_flag(self)
         view = self.makeView(derived_series)
         soup = BeautifulSoup(view())
         diff_table = soup.find('table', {'class': 'listing'})
@@ -1474,7 +1339,6 @@
         # Flush out the changes and invalidate caches (esp. property caches).
         flush_database_caches()
 
-        set_derived_series_ui_feature_flag(self)
         view = self.makeView(derived_series)
         soup = BeautifulSoup(view())
         diff_table = soup.find('table', {'class': 'listing'})
@@ -1495,7 +1359,6 @@
     def test_diff_row_last_changed(self):
         # The SPR creator (i.e. who make the package change, rather than the
         # uploader) is shown on each difference row.
-        set_derived_series_ui_feature_flag(self)
         dsd = self.makePackageUpgrade()
         view = self.makeView(dsd.derived_series)
         root = html.fromstring(view())
@@ -1509,7 +1372,6 @@
     def test_diff_row_last_changed_also_shows_uploader_if_different(self):
         # When the SPR creator and uploader are different both are named on
         # each difference row.
-        set_derived_series_ui_feature_flag(self)
         dsd = self.makePackageUpgrade()
         uploader = self.factory.makePerson()
         removeSecurityProxy(dsd.source_package_release).dscsigningkey = (
@@ -1528,7 +1390,6 @@
         # After the parent's version, there should be text "(changelog)"
         # linked to the parent distro source package +changelog page.  The
         # text is styled with "lesser".
-        set_derived_series_ui_feature_flag(self)
         dsd = self.makePackageUpgrade()
         view = self.makeView(dsd.derived_series)
         soup = BeautifulSoup(view())
@@ -1690,8 +1551,7 @@
 
     def test_higher_radio_mentions_parent(self):
         # The user is shown an option to display only the blacklisted
-        # package with a higer version than in the parent.
-        set_derived_series_ui_feature_flag(self)
+        # package with a higher version than in the parent.
         derived_series, parent_series = self._createChildAndParent()
         self.factory.makeDistroSeriesDifference(
             derived_series=derived_series,
@@ -1710,7 +1570,6 @@
         self.assertThat(view.render(), radio_option_matches)
 
     def test_higher_radio_mentions_parents(self):
-        set_derived_series_ui_feature_flag(self)
         derived_series, parent_series = self._createChildAndParents()
         self.factory.makeDistroSeriesDifference(
             derived_series=derived_series,
@@ -1737,7 +1596,6 @@
 
     def test_batch_filtered(self):
         # The name_filter parameter allows filtering of packages by name.
-        set_derived_series_ui_feature_flag(self)
         derived_series, parent_series = self._createChildAndParent()
         diff1 = self.factory.makeDistroSeriesDifference(
             derived_series=derived_series,
@@ -1761,7 +1619,6 @@
 
     def test_batch_non_blacklisted(self):
         # The default filter is all non blacklisted differences.
-        set_derived_series_ui_feature_flag(self)
         derived_series, parent_series = self._createChildAndParent()
         diff1 = self.factory.makeDistroSeriesDifference(
             derived_series=derived_series,
@@ -1789,7 +1646,6 @@
     def test_batch_all_packages(self):
         # field.package_type parameter allows to list all the
         # differences.
-        set_derived_series_ui_feature_flag(self)
         derived_series, parent_series = self._createChildAndParent()
         # Create differences of all possible statuses.
         diffs = []
@@ -1807,7 +1663,6 @@
     def test_batch_wrong_param(self):
         # If a wrong parameter is passed then an error is displayed
         # and no differences are shown.
-        set_derived_series_ui_feature_flag(self)
         derived_series, parent_series = self._createChildAndParent()
         self.factory.makeDistroSeriesDifference(
             derived_series=derived_series,
@@ -1824,7 +1679,6 @@
     def test_batch_blacklisted_differences_with_higher_version(self):
         # field.package_type parameter allows to list only
         # blacklisted differences with a child's version higher than parent's.
-        set_derived_series_ui_feature_flag(self)
         derived_series, parent_series = self._createChildAndParent()
         blacklisted_diff_higher = self.factory.makeDistroSeriesDifference(
             derived_series=derived_series,
@@ -1852,7 +1706,6 @@
     def test_batch_resolved_differences(self):
         # Test that we can search for differences that we marked
         # resolved.
-        set_derived_series_ui_feature_flag(self)
         derived_series, parent_series = self._createChildAndParent()
 
         self.factory.makeDistroSeriesDifference(
@@ -1891,7 +1744,6 @@
             difference_type=difference_type)
         sourcepackagename = self.factory.getOrMakeSourcePackageName(
             src_name)
-        set_derived_series_ui_feature_flag(self)
         return derived_series, parent_series, sourcepackagename, str(diff.id)
 
     def test_canPerformSync_anon(self):
@@ -2361,7 +2213,6 @@
     def test_specified_packagesets_filter_none_specified(self):
         # specified_packagesets_filter is None when there are no
         # field.packageset parameters in the query.
-        set_derived_series_ui_feature_flag(self)
         dsd = self.factory.makeDistroSeriesDifference()
         person = dsd.derived_series.owner
         with person_logged_in(person):
@@ -2373,7 +2224,6 @@
     def test_specified_packagesets_filter_specified(self):
         # specified_packagesets_filter returns a collection of Packagesets
         # when there are field.packageset query parameters.
-        set_derived_series_ui_feature_flag(self)
         dsd = self.factory.makeDistroSeriesDifference()
         person = dsd.derived_series.owner
         packageset1 = self.factory.makePackageset(
@@ -2392,7 +2242,6 @@
     def test_search_for_packagesets(self):
         # If packagesets are supplied in the query the resulting batch will
         # only contain packages in the given packagesets.
-        set_derived_series_ui_feature_flag(self)
         dsd = self.factory.makeDistroSeriesDifference()
         person = dsd.derived_series.owner
         packageset = self.factory.makePackageset(
@@ -2414,7 +2263,6 @@
     def test_specified_changed_by_filter_none_specified(self):
         # specified_changed_by_filter is None when there are no
         # field.changed_by parameters in the query.
-        set_derived_series_ui_feature_flag(self)
         dsd = self.factory.makeDistroSeriesDifference()
         person = dsd.derived_series.owner
         with person_logged_in(person):
@@ -2426,7 +2274,6 @@
     def test_specified_changed_by_filter_specified(self):
         # specified_changed_by_filter returns a collection of Person when
         # there are field.changed_by query parameters.
-        set_derived_series_ui_feature_flag(self)
         dsd = self.factory.makeDistroSeriesDifference()
         person = dsd.derived_series.owner
         changed_by1 = self.factory.makePerson()
@@ -2445,7 +2292,6 @@
     def test_search_for_changed_by(self):
         # If changed_by is specified the query the resulting batch will only
         # contain packages relating to those people or teams.
-        set_derived_series_ui_feature_flag(self)
         dsd = self.factory.makeDistroSeriesDifference()
         person = dsd.derived_series.owner
         ironhide = self.factory.makePersonByName("Ironhide")
@@ -2570,7 +2416,6 @@
     def setUp(self):
         super(DistroSeriesMissingPackagesPageTestCase,
               self).setUp('foo.bar@xxxxxxxxxxxxx')
-        set_derived_series_ui_feature_flag(self)
         self.simple_user = self.factory.makePerson()
 
     def test_parent_packagesets_missingpackages(self):
@@ -2671,7 +2516,6 @@
         # For a series derived from multiple parents, the parent for each
         # DSD is displayed; no parent version is displayed because we're
         # listing packages unique to the derived series.
-        set_derived_series_ui_feature_flag(self)
         derived_series, parent_series = self._createChildAndParents()
         missing_type = DistroSeriesDifferenceType.UNIQUE_TO_DERIVED_SERIES
         self.factory.makeDistroSeriesDifference(
@@ -2733,7 +2577,6 @@
     def setUp(self):
         super(DistroSeriesUniquePackagesPageTestCase,
               self).setUp('foo.bar@xxxxxxxxxxxxx')
-        set_derived_series_ui_feature_flag(self)
         self.simple_user = self.factory.makePerson()
 
     def test_packagesets_uniquepackages(self):

=== modified file 'lib/lp/registry/stories/distribution/xx-distribution-overview.txt'
--- lib/lp/registry/stories/distribution/xx-distribution-overview.txt	2012-06-11 00:03:25 +0000
+++ lib/lp/registry/stories/distribution/xx-distribution-overview.txt	2012-07-30 12:16:24 +0000
@@ -79,11 +79,7 @@
 The 5 latest derivatives are displayed on the home page
 along with a link to list all of them.
 
-   >>> from lp.services.features.testing import FeatureFixture
-   >>> derivation_enabled = FeatureFixture(
-   ...     {'soyuz.derived_series_ui.enabled': 'on'})
-   >>> with derivation_enabled:
-   ...     anon_browser.open('http://launchpad.dev/ubuntu')
+   >>> anon_browser.open('http://launchpad.dev/ubuntu')
    >>> print extract_text(find_tag_by_id(anon_browser.contents,
    ... 'derivatives'))
    Latest derivatives
@@ -107,11 +103,10 @@
     >>> anon_browser.getLink('All derivatives').url
     'http://launchpad.dev/ubuntu/+derivatives'
 
-If there is no derivatives, the link to the derivatives page is
+If there are no derivatives, the link to the derivatives page is
 not there.
 
-   >>> with derivation_enabled:
-   ...     anon_browser.open('http://launchpad.dev/ubuntutest')
+   >>> anon_browser.open('http://launchpad.dev/ubuntutest')
    >>> print extract_text(find_tag_by_id(anon_browser.contents,
    ... 'derivatives'))
    Latest derivatives

=== modified file 'lib/lp/registry/stories/distroseries/xx-distroseries-index.txt'
--- lib/lp/registry/stories/distroseries/xx-distroseries-index.txt	2012-02-22 21:42:44 +0000
+++ lib/lp/registry/stories/distroseries/xx-distroseries-index.txt	2012-07-30 12:16:24 +0000
@@ -16,11 +16,7 @@
 The distroseries pages presents the 'registering' information besides
 its main 'heading'.
 
-    >>> from lp.services.features.testing import FeatureFixture
-    >>> derivation_enabled = FeatureFixture(
-    ...     {'soyuz.derived_series_ui.enabled': 'on'})
-    >>> with derivation_enabled:
-    ...     anon_browser.open('http://launchpad.dev/ubuntu/warty')
+    >>> anon_browser.open('http://launchpad.dev/ubuntu/warty')
 
     >>> print extract_text(
     ...     find_tag_by_id(anon_browser.contents, 'registration'))
@@ -67,13 +63,13 @@
     Project drivers: Jeff Waugh, Mark Shuttleworth
     Release manager: Jeff Waugh
     Status: Pre-release Freeze
-    Successor to: Woody (3.0)
+    Derives from: Sarge (3.1) is not derived from another series.
+    Derived series: No derived series.
     Source packages: No sources imported or published.
     Binary packages: No binaries imported or published.
 
-The series' derivation parents - rather than the previous series - are
-shown when derivation is enabled, as are the series derived from this
-series:
+The series' derivation parents are shown when derivation is enabled, as are
+the series derived from this series:
 
     >>> from lp.registry.interfaces.distribution import IDistributionSet
     >>> from lp.testing import celebrity_logged_in
@@ -97,8 +93,7 @@
     ...             derived_series=child, parent_series=sarge)
     ...         for child in children]
 
-    >>> with derivation_enabled:
-    ...     anon_browser.open('http://launchpad.dev/debian/sarge')
+    >>> anon_browser.open('http://launchpad.dev/debian/sarge')
     >>> print extract_text(
     ...     find_portlet(anon_browser.contents, 'Series information'))
     Series information

=== modified file 'lib/lp/registry/templates/distribution-index.pt'
--- lib/lp/registry/templates/distribution-index.pt	2012-02-06 21:51:57 +0000
+++ lib/lp/registry/templates/distribution-index.pt	2012-07-30 12:16:24 +0000
@@ -60,7 +60,7 @@
         <div class="yui-u">
           <tal:series replace="structure context/@@+series-and-milestones" />
         </div>
-        <div class="yui-u" tal:condition="features/soyuz.derived_series_ui.enabled">
+        <div class="yui-u">
           <tal:series replace="structure context/@@+derivatives-slot" />
         </div>
        </div>

=== modified file 'lib/lp/registry/templates/distroseries-details.pt'
--- lib/lp/registry/templates/distroseries-details.pt	2011-08-11 06:29:58 +0000
+++ lib/lp/registry/templates/distroseries-details.pt	2012-07-30 12:16:24 +0000
@@ -46,28 +46,6 @@
       </dd>
     </dl>
 
-    <tal:derivation-not-enabled
-        tal:condition="not:request/features/soyuz.derived_series_ui.enabled">
-
-    <dl>
-      <dt>Successor to:</dt>
-      <dd>
-        <a
-          tal:condition="context/previous_series"
-          tal:attributes="href context/previous_series/fmt:url"
-          tal:content="context/previous_series/named_version" />
-        <tal:none condition="not: context/previous_series">
-          <tal:name replace="context/named_version"/>
-          did not succeed any earlier series.
-        </tal:none>
-      </dd>
-    </dl>
-
-    </tal:derivation-not-enabled>
-
-    <tal:derivation-enabled
-        tal:condition="request/features/soyuz.derived_series_ui.enabled">
-
     <dl tal:define="parents context/getParentSeries">
       <dt>Derives from:</dt>
       <dd tal:condition="parents">
@@ -98,8 +76,6 @@
       </dd>
     </dl>
 
-    </tal:derivation-enabled>
-
     <dl tal:define="sourcecount context/sourcecount">
       <dt>Source packages:</dt>
       <dd

=== modified file 'lib/lp/registry/templates/distroseries-index.pt'
--- lib/lp/registry/templates/distroseries-index.pt	2012-02-01 15:31:32 +0000
+++ lib/lp/registry/templates/distroseries-index.pt	2012-07-30 12:16:24 +0000
@@ -63,14 +63,11 @@
           <div
             tal:replace="structure context/@@+portlet-details"/>
         </div>
-        <tal:derivation
-          tal:condition="request/features/soyuz.derived_series_ui.enabled">
-          <div class="yui-u"
-               tal:condition="python: context.isDerivedSeries() or
-                              context.getInitializationJob() is not None">
-            <div tal:replace="structure context/@@+portlet-derivation" />
-          </div>
-        </tal:derivation>
+        <div class="yui-u"
+             tal:condition="python: context.isDerivedSeries() or
+                            context.getInitializationJob() is not None">
+          <div tal:replace="structure context/@@+portlet-derivation" />
+        </div>
 
         <div class="yui-u">
           <div tal:replace="structure context/@@+portlet-package-summary" />

=== modified file 'lib/lp/registry/templates/distroseries-initialize.pt'
--- lib/lp/registry/templates/distroseries-initialize.pt	2012-07-07 14:00:30 +0000
+++ lib/lp/registry/templates/distroseries-initialize.pt	2012-07-30 12:16:24 +0000
@@ -39,16 +39,6 @@
       </p>
       </tal:enabled>
 
-      <tal:disabled condition="view/show_derivation_not_yet_available">
-      <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>
-
       <tal:previous_series_none
         condition="view/show_previous_series_empty_message">
       <p class="error message">

=== modified file 'lib/lp/services/features/__init__.py'
--- lib/lp/services/features/__init__.py	2012-06-14 08:35:39 +0000
+++ lib/lp/services/features/__init__.py	2012-07-30 12:16:24 +0000
@@ -116,12 +116,12 @@
 
 To simply check a boolean::
 
-    if features.getFeatureFlag('soyuz.derived_series_ui.enabled'):
+    if features.getFeatureFlag('example_flag.enabled'):
         ...
 
 and if you want to use the value ::
 
-     value = features.getFeatureFlag('soyuz.derived_series_ui.enabled')
+     value = features.getFeatureFlag('example_flag.enabled')
      if value:
         print value
 

=== modified file 'lib/lp/services/features/flags.py'
--- lib/lp/services/features/flags.py	2012-07-27 04:52:06 +0000
+++ lib/lp/services/features/flags.py	2012-07-30 12:16:24 +0000
@@ -166,12 +166,6 @@
      '100',
      '',
      ''),
-    ('soyuz.derived_series_ui.enabled',
-     'boolean',
-     'Enables derivative distributions pages.',
-     '',
-     '',
-     ''),
     ('soyuz.derived_series_sync.enabled',
      'boolean',
      'Enables syncing of packages on derivative distributions pages.',


Follow ups