launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #11834
[Merge] lp:~stevenk/launchpad/destroy-plus-daily-builds into lp:launchpad
Steve Kowalik has proposed merging lp:~stevenk/launchpad/destroy-plus-daily-builds into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #905792 in Launchpad itself: "Timeout on /+daily-builds"
https://bugs.launchpad.net/launchpad/+bug/905792
Bug #968998 in Launchpad itself: "RootObject:+daily-builds times out"
https://bugs.launchpad.net/launchpad/+bug/968998
For more details, see:
https://code.launchpad.net/~stevenk/launchpad/destroy-plus-daily-builds/+merge/123888
Destroy RootObject:+daily-builds. Its main query is horrible with eight joins, takes 5 *minutes* on DF with a cold cache, has been visited for 120 for the past month and has been broken for at least 12 months. It is time for it die, so remove it.
--
https://code.launchpad.net/~stevenk/launchpad/destroy-plus-daily-builds/+merge/123888
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/destroy-plus-daily-builds into lp:launchpad.
=== modified file 'lib/lp/code/browser/configure.zcml'
--- lib/lp/code/browser/configure.zcml 2012-08-28 04:16:32 +0000
+++ lib/lp/code/browser/configure.zcml 2012-09-12 06:19:27 +0000
@@ -141,14 +141,6 @@
name="+index"
template="../templates/bazaar-index.pt" />
<browser:page
- for="lp.services.webapp.interfaces.ILaunchpadRoot"
- layer="lp.code.publisher.CodeLayer"
- permission="zope.Public"
- class="lp.code.browser.recipebuildslisting.CompletedDailyBuildsView"
- name="+daily-builds"
- template="../templates/daily-builds-listing.pt" />
-
- <browser:page
for="lp.code.interfaces.branchmergeproposal.IBranchMergeProposal"
layer="lp.code.publisher.CodeLayer"
name="+hierarchy"
=== removed file 'lib/lp/code/browser/recipebuildslisting.py'
--- lib/lp/code/browser/recipebuildslisting.py 2012-01-01 02:58:52 +0000
+++ lib/lp/code/browser/recipebuildslisting.py 1970-01-01 00:00:00 +0000
@@ -1,91 +0,0 @@
-# Copyright 2010-2011 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""View for daily builds listings."""
-
-__metaclass__ = type
-
-__all__ = [
- 'CompletedDailyBuildsView',
- ]
-
-from lazr.enum import (
- EnumeratedType,
- Item,
- )
-from zope.component import getUtility
-from zope.interface import Interface
-from zope.schema import Choice
-
-from lp import _
-from lp.app.browser.launchpadform import (
- custom_widget,
- LaunchpadFormView,
- )
-from lp.app.widgets.itemswidgets import LaunchpadDropdownWidget
-from lp.code.interfaces.recipebuild import IRecipeBuildRecordSet
-from lp.services.webapp.batching import BatchNavigator
-
-
-class RecipeBuildFilter(EnumeratedType):
- """Choices for how to filter recipe build listings."""
-
- ALL = Item("""
- at any time
-
- Show all most recently completed recipe builds.
- """)
-
- WITHIN_30_DAYS = Item("""
- within last 30 days
-
- Show only recently completed recipe builds from within the last
- 30 days.
- """)
-
-
-class RecipeBuildBatchNavigator(BatchNavigator):
- """A Batch Navigator turn activate table sorting for single page views."""
-
- @property
- def table_class(self):
- if self.has_multiple_pages:
- return "listing"
- else:
- return "listing sortable"
-
-
-class CompletedDailyBuildsView(LaunchpadFormView):
- """The view to show completed builds for source package recipes."""
-
- class schema(Interface):
- when_completed_filter = Choice(
- title=_('Recipe Build Filter'), vocabulary=RecipeBuildFilter,
- default=RecipeBuildFilter.ALL,
- description=_(
- "Filter for selecting when recipe builds have completed."))
- field_names = ['when_completed_filter']
- custom_widget('when_completed_filter', LaunchpadDropdownWidget)
-
- @property
- def page_title(self):
- return 'Packages Built Daily With Recipes'
-
- def initialize(self):
- LaunchpadFormView.initialize(self)
- self.dailybuilds = self.getDailyBuilds()
- self.batchnav = RecipeBuildBatchNavigator(
- self.dailybuilds, self.request)
-
- def getDailyBuilds(self):
- widget = self.widgets['when_completed_filter']
- if widget.hasValidInput():
- when_completed = widget.getInputValue()
- if when_completed == RecipeBuildFilter.WITHIN_30_DAYS:
- epoch_days = 30
- else:
- epoch_days = None
- else:
- epoch_days = None
- recipe_build_set = getUtility(IRecipeBuildRecordSet)
- return recipe_build_set.findCompletedDailyBuilds(epoch_days)
=== removed file 'lib/lp/code/browser/tests/test_recipebuildslisting.py'
--- lib/lp/code/browser/tests/test_recipebuildslisting.py 2012-01-01 02:58:52 +0000
+++ lib/lp/code/browser/tests/test_recipebuildslisting.py 1970-01-01 00:00:00 +0000
@@ -1,214 +0,0 @@
-# Copyright 2010 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Tests for recipe build listings."""
-
-__metaclass__ = type
-
-
-from zope.component import getUtility
-
-from lp.services.webapp.interfaces import ILaunchpadRoot
-from lp.services.webapp.publisher import canonical_url
-from lp.testing import (
- ANONYMOUS,
- BrowserTestCase,
- login,
- TestCaseWithFactory,
- )
-from lp.testing.layers import DatabaseFunctionalLayer
-from lp.testing.matchers import BrowsesWithQueryLimit
-from lp.testing.pages import (
- extract_text,
- find_tag_by_id,
- )
-from lp.testing.views import create_initialized_view
-
-
-class TestRecipeBuildView(TestCaseWithFactory):
- """Tests for `CompletedDailyBuildsView`."""
-
- layer = DatabaseFunctionalLayer
-
- def test_recipebuildrecords(self):
- all_records, recent_records = (
- self.factory.makeRecipeBuildRecords(10, 5))
- login(ANONYMOUS)
- root = getUtility(ILaunchpadRoot)
- view = create_initialized_view(root, "+daily-builds", rootsite='code')
- # It's easier to do it this way than sorted() since __lt__ doesn't
- # work properly on zope proxies.
- self.assertEqual(15, view.dailybuilds.count())
- # By default, all build records will be included in the view.
- self.assertEqual(set(all_records), set(view.dailybuilds))
-
-
-class TestRecipeBuildListing(BrowserTestCase):
- """Browser tests for the Recipe Build Listing page."""
- layer = DatabaseFunctionalLayer
-
- def _extract_view_text(self, recipe_build_record):
- text = '\n'.join(str(item) for item in (
- recipe_build_record.sourcepackagename.name,
- recipe_build_record.recipe.name,
- recipe_build_record.recipeowner.displayname,
- recipe_build_record.archive.displayname,
- recipe_build_record.most_recent_build_time.strftime(
- '%Y-%m-%d %H:%M:%S')))
- return text
-
- def _test_recipebuild_listing(self, no_login=False):
- # Test the text on a recipe build listing page is as expected.
- all_records, [recent_record] = (
- self.factory.makeRecipeBuildRecords(1, 5))
- record_text = self._extract_view_text(recent_record)
- root = getUtility(ILaunchpadRoot)
- text = self.getMainText(
- root, '+daily-builds', rootsite='code', no_login=no_login)
- expected_text = """
- Packages Built Daily With Recipes
- .*
- Source Package
- Recipe
- Recipe Owner
- Archive
- Most Recent Build Time
- """ + record_text
- self.assertTextMatchesExpressionIgnoreWhitespace(expected_text, text)
-
- def test_recipebuild_listing_no_records(self):
- # Test the expected text when there is no data.
- root = getUtility(ILaunchpadRoot)
- text = self.getMainText(root, '+daily-builds', rootsite='code')
- expected_text = "No recently completed daily builds found."
- self.assertTextMatchesExpressionIgnoreWhitespace(expected_text, text)
-
- def test_recipebuild_listing_anonymous(self):
- # Ensure we can see the listing when we are not logged in.
- self._test_recipebuild_listing(no_login=True)
-
- def test_recipebuild_listing_with_user(self):
- # Ensure we can see the listing when we are logged in.
- self._test_recipebuild_listing()
-
- def test_recipebuild_listing_querycount(self):
- # The query count on the recipe build listing page is small enough.
- # There's a base query count of approx 30, but if the page template
- # is not set up right, the query count can increases linearly with the
- # number of records.
- self.factory.makeRecipeBuildRecords(5, 0)
- root = getUtility(ILaunchpadRoot)
- browser_query_limit = BrowsesWithQueryLimit(
- 35, self.user, view_name='+daily-builds', rootsite='code')
- self.assertThat(root, browser_query_limit)
-
- def test_recipebuild_url(self):
- # Check the browser URL is as expected.
- root_url = self.layer.appserver_root_url(facet='code')
- user_browser = self.getUserBrowser("%s/+daily-builds" % root_url)
- self.assertEqual(
- user_browser.url, "%s/+daily-builds" % root_url)
-
- def test_recentbuild_filter(self):
- login(ANONYMOUS)
- all_records, recent_records = (
- self.factory.makeRecipeBuildRecords(3, 2))
- records_text = set()
- for record in recent_records:
- record_text = self._extract_view_text(
- record).replace(' ', '').replace('\n', '')
- records_text.add(record_text)
-
- root_url = self.layer.appserver_root_url(facet='code')
- browser = self.getUserBrowser("%s/+daily-builds" % root_url)
- status_control = browser.getControl(
- name='field.when_completed_filter')
-
- status_control.value = ['WITHIN_30_DAYS']
- browser.getControl('Filter').click()
- table = find_tag_by_id(browser.contents, 'daily-build-listing')
-
- view_records_text = set()
- for row in table.tbody.fetch('tr'):
- text = extract_text(row)
- view_records_text.add(text.replace(' ', '').replace('\n', ''))
- self.assertEquals(records_text, view_records_text)
-
- def test_recentbuild_filter_with_no_records(self):
- # This test ensures that the filter control works properly when the
- # filtered record set contains no records. We should be able to
- # select All again and have the page re-display all records."
-
- login(ANONYMOUS)
- # Create records all outside the filter time window.
- all_records, recent_records = (
- self.factory.makeRecipeBuildRecords(0, 2))
- records_text = set()
- for record in all_records:
- record_text = self._extract_view_text(
- record).replace(' ', '').replace('\n', '')
- records_text.add(record_text)
-
- def check_build_records(table):
- view_records_text = set()
- for row in table.tbody.fetch('tr'):
- text = extract_text(row)
- view_records_text.add(text.replace(' ', '').replace('\n', ''))
- self.assertEquals(records_text, view_records_text)
-
- # Initial rendering has all records.
- root_url = self.layer.appserver_root_url(facet='code')
- browser = self.getUserBrowser("%s/+daily-builds" % root_url)
- table = find_tag_by_id(browser.contents, 'daily-build-listing')
- check_build_records(table)
-
- # There are no filtered records.
- status_control = browser.getControl(
- name='field.when_completed_filter')
- status_control.value = ['WITHIN_30_DAYS']
- browser.getControl('Filter').click()
- table = find_tag_by_id(browser.contents, 'daily-build-listing')
- self.assertIs(None, table)
-
- # We can click All and see the record again.
- status_control = browser.getControl(
- name='field.when_completed_filter')
- status_control.value = ['ALL']
- browser.getControl('Filter').click()
- table = find_tag_by_id(browser.contents, 'daily-build-listing')
- check_build_records(table)
-
- def test_all_records_filter(self):
- login(ANONYMOUS)
- all_records, recent_records = (
- self.factory.makeRecipeBuildRecords(3, 2))
- records_text = set()
- for record in all_records:
- record_text = self._extract_view_text(
- record).replace(' ', '').replace('\n', '')
- records_text.add(record_text)
-
- root_url = self.layer.appserver_root_url(facet='code')
- browser = self.getUserBrowser("%s/+daily-builds" % root_url)
- status_control = browser.getControl(
- name='field.when_completed_filter')
-
- status_control.value = ['ALL']
- browser.getControl('Filter').click()
- table = find_tag_by_id(browser.contents, 'daily-build-listing')
-
- view_records_text = set()
- for row in table.tbody.fetch('tr'):
- text = extract_text(row)
- view_records_text.add(text.replace(' ', '').replace('\n', ''))
- self.assertEquals(records_text, view_records_text)
-
- def test_one_recipe_redirects_to_recipe_page(self):
- # Ensure that if the product or person has only one recipe, they are
- # redirected right to the recipe page.
- recipe = self.factory.makeSourcePackageRecipe()
- root_url = self.layer.appserver_root_url(facet='code')
- recipes_url = '%s/~%s/+recipes' % (root_url, recipe.owner.name)
- expected_url = canonical_url(recipe)
- browser = self.getUserBrowser(recipes_url)
- self.assertEquals(expected_url, browser.url)
=== modified file 'lib/lp/code/stories/branches/xx-bazaar-home.txt'
--- lib/lp/code/stories/branches/xx-bazaar-home.txt 2012-03-01 17:42:28 +0000
+++ lib/lp/code/stories/branches/xx-bazaar-home.txt 2012-09-12 06:19:27 +0000
@@ -152,16 +152,3 @@
Project
Last Modified
Last Commit
-
-
-Recently built recipes
-......................
-
-Source package recipes have their own section on the home page.
-
- >>> browser.open('http://code.launchpad.dev/')
- >>> changed = find_tag_by_id(browser.contents, 'build-recipes')
- >>> print changed.fetch('a')[0]['href']
- /+daily-builds
- >>> print changed.fetch('a')[-1]['href']
- https://help.launchpad.net/Packaging/SourceBuilds
=== modified file 'lib/lp/code/templates/bazaar-index.pt'
--- lib/lp/code/templates/bazaar-index.pt 2012-06-11 00:47:38 +0000
+++ lib/lp/code/templates/bazaar-index.pt 2012-09-12 06:19:27 +0000
@@ -53,8 +53,7 @@
</p>
<p id="build-recipes" class="application-summary" style="padding-top: 0.25em;">
Launchpad can build Ubuntu packages directly from branches using recipes.
- We currently build over <a href="/+daily-builds">100 different packages</a>
- into PPAs automatically using this method.
+ We currently build over 100 different packages into PPAs automatically using this method.
(<a href="https://help.launchpad.net/Packaging/SourceBuilds">Learn more about recipes</a>)
</p>
Follow ups