launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #19867
[Merge] lp:~cjwatson/launchpad/git-recipe-browser-listing into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/git-recipe-browser-listing into lp:launchpad with lp:~cjwatson/launchpad/recipe-name-policy as a prerequisite.
Commit message:
Add views to list existing Git recipes.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1453022 in Launchpad itself: "Please support daily builds via git"
https://bugs.launchpad.net/launchpad/+bug/1453022
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/git-recipe-browser-listing/+merge/282321
Add views to list existing Git recipes.
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/git-recipe-browser-listing into lp:launchpad.
=== modified file 'lib/lp/code/browser/configure.zcml'
--- lib/lp/code/browser/configure.zcml 2015-11-23 11:34:15 +0000
+++ lib/lp/code/browser/configure.zcml 2016-01-12 15:24:34 +0000
@@ -1,4 +1,4 @@
-<!-- Copyright 2009-2015 Canonical Ltd. This software is licensed under the
+<!-- Copyright 2009-2016 Canonical Ltd. This software is licensed under the
GNU Affero General Public License version 3 (see the file LICENSE).
-->
@@ -800,6 +800,9 @@
<browser:page
name="++repository-management"
template="../templates/gitrepository-management.pt"/>
+ <browser:page
+ name="++repository-recipes"
+ template="../templates/gitrepository-recipes.pt"/>
</browser:pages>
<browser:page
for="lp.code.interfaces.gitrepository.IGitRepository"
@@ -884,11 +887,14 @@
name="++ref-commits"
template="../templates/gitref-commits.pt"/>
<browser:page
+ name="++ref-management"
+ template="../templates/gitref-management.pt"/>
+ <browser:page
name="++ref-pending-merges"
template="../templates/gitref-pending-merges.pt"/>
<browser:page
- name="++ref-management"
- template="../templates/gitref-management.pt"/>
+ name="++ref-recipes"
+ template="../templates/gitref-recipes.pt"/>
</browser:pages>
<browser:page
for="lp.code.interfaces.gitref.IGitRef"
@@ -1232,6 +1238,18 @@
name="+recipes"
template="../templates/sourcepackagerecipe-listing.pt"/>
<browser:page
+ for="lp.code.interfaces.gitrepository.IGitRepository"
+ class="lp.code.browser.sourcepackagerecipelisting.BranchRecipeListingView"
+ permission="zope.Public"
+ name="+recipes"
+ template="../templates/sourcepackagerecipe-listing.pt"/>
+ <browser:page
+ for="lp.code.interfaces.gitref.IGitRef"
+ class="lp.code.browser.sourcepackagerecipelisting.BranchRecipeListingView"
+ permission="zope.Public"
+ name="+recipes"
+ template="../templates/sourcepackagerecipe-listing.pt"/>
+ <browser:page
for="lp.registry.interfaces.product.IProduct"
class="lp.code.browser.sourcepackagerecipelisting.ProductRecipeListingView"
permission="zope.Public"
=== modified file 'lib/lp/code/browser/gitref.py'
--- lib/lp/code/browser/gitref.py 2015-11-30 03:03:14 +0000
+++ lib/lp/code/browser/gitref.py 2016-01-12 15:24:34 +0000
@@ -1,4 +1,4 @@
-# Copyright 2015 Canonical Ltd. This software is licensed under the
+# Copyright 2015-2016 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Git reference views."""
@@ -35,6 +35,7 @@
from lp.code.browser.branchmergeproposal import (
latest_proposals_for_each_branch,
)
+from lp.code.browser.sourcepackagerecipelisting import HasRecipesMenuMixin
from lp.code.errors import InvalidBranchMergeProposal
from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal
from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference
@@ -49,18 +50,19 @@
Link,
)
from lp.services.webapp.authorization import check_permission
+from lp.services.webapp.escaping import structured
from lp.snappy.browser.hassnaps import (
HasSnapsMenuMixin,
HasSnapsViewMixin,
)
-class GitRefContextMenu(ContextMenu, HasSnapsMenuMixin):
+class GitRefContextMenu(ContextMenu, HasRecipesMenuMixin, HasSnapsMenuMixin):
"""Context menu for Git references."""
usedfor = IGitRef
facet = 'branches'
- links = ['create_snap', 'register_merge', 'source']
+ links = ['create_snap', 'register_merge', 'source', 'view_recipes']
def source(self):
"""Return a link to the branch's browsing interface."""
@@ -144,6 +146,24 @@
def dependent_landing_count_text(self):
return self._getBranchCountText(len(self.dependent_landings))
+ @property
+ def recipes_link(self):
+ """A link to recipes for this reference."""
+ count = self.context.recipes.count()
+ if count == 0:
+ # Nothing to link to.
+ return 'No recipes using this branch.'
+ elif count == 1:
+ # Link to the single recipe.
+ return structured(
+ '<a href="%s">1 recipe</a> using this branch.',
+ canonical_url(self.context.recipes.one())).escapedtext
+ else:
+ # Link to a recipe listing.
+ return structured(
+ '<a href="+recipes">%s recipes</a> using this branch.',
+ count).escapedtext
+
class GitRefRegisterMergeProposalSchema(Interface):
"""The schema to define the form for registering a new merge proposal."""
=== modified file 'lib/lp/code/browser/gitrepository.py'
--- lib/lp/code/browser/gitrepository.py 2015-10-07 16:14:42 +0000
+++ lib/lp/code/browser/gitrepository.py 2016-01-12 15:24:34 +0000
@@ -1,4 +1,4 @@
-# Copyright 2015 Canonical Ltd. This software is licensed under the
+# Copyright 2015-2016 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Git repository views."""
@@ -52,6 +52,7 @@
from lp.app.vocabularies import InformationTypeVocabulary
from lp.app.widgets.itemswidgets import LaunchpadRadioWidgetWithDescription
from lp.code.browser.branch import CodeEditOwnerMixin
+from lp.code.browser.sourcepackagerecipelisting import HasRecipesMenuMixin
from lp.code.browser.widgets.gitrepositorytarget import (
GitRepositoryTargetDisplayWidget,
GitRepositoryTargetWidget,
@@ -203,12 +204,14 @@
return Link("+delete", text, icon="trash-icon")
-class GitRepositoryContextMenu(ContextMenu):
+class GitRepositoryContextMenu(ContextMenu, HasRecipesMenuMixin):
"""Context menu for `IGitRepository`."""
usedfor = IGitRepository
facet = "branches"
- links = ["add_subscriber", "source", "subscription", "visibility"]
+ links = [
+ "add_subscriber", "source", "subscription",
+ "view_recipes", "visibility"]
@enabled_with_permission("launchpad.AnyPerson")
def subscription(self):
@@ -291,6 +294,24 @@
"""All branches in this repository, sorted for display."""
return GitRefBatchNavigator(self, self.context)
+ @property
+ def recipes_link(self):
+ """A link to recipes for this repository."""
+ count = self.context.recipes.count()
+ if count == 0:
+ # Nothing to link to.
+ return 'No recipes using this repository.'
+ elif count == 1:
+ # Link to the single recipe.
+ return structured(
+ '<a href="%s">1 recipe</a> using this repository.',
+ canonical_url(self.context.recipes.one())).escapedtext
+ else:
+ # Link to a recipe listing.
+ return structured(
+ '<a href="+recipes">%s recipes</a> using this repository.',
+ count).escapedtext
+
class GitRepositoryEditFormView(LaunchpadEditFormView):
"""Base class for forms that edit a Git repository."""
=== modified file 'lib/lp/code/browser/sourcepackagerecipelisting.py'
--- lib/lp/code/browser/sourcepackagerecipelisting.py 2015-10-05 13:36:06 +0000
+++ lib/lp/code/browser/sourcepackagerecipelisting.py 2016-01-12 15:24:34 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2015 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2016 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Base class view for sourcepackagerecipe listings."""
@@ -14,6 +14,7 @@
from lp.code.browser.decorations import DecoratedBranch
+from lp.code.interfaces.branch import IBranch
from lp.services.feeds.browser import FeedsMixin
from lp.services.webapp import (
LaunchpadView,
@@ -42,8 +43,8 @@
@property
def page_title(self):
- return 'Source Package Recipes for %(displayname)s' % {
- 'displayname': self.context.displayname}
+ return 'Source Package Recipes for %(display_name)s' % {
+ 'display_name': self.context.display_name}
class BranchRecipeListingView(RecipeListingView):
@@ -54,7 +55,8 @@
super(BranchRecipeListingView, self).initialize()
# Replace our context with a decorated branch, if it is not already
# decorated.
- if not isinstance(self.context, DecoratedBranch):
+ if (IBranch.providedBy(self.context) and
+ not isinstance(self.context, DecoratedBranch)):
self.context = DecoratedBranch(self.context)
=== modified file 'lib/lp/code/stories/sourcepackagerecipes/xx-recipe-listings.txt'
--- lib/lp/code/stories/sourcepackagerecipes/xx-recipe-listings.txt 2011-06-29 16:49:05 +0000
+++ lib/lp/code/stories/sourcepackagerecipes/xx-recipe-listings.txt 2016-01-12 15:24:34 +0000
@@ -52,18 +52,84 @@
>>> print nopriv_browser.url
http://code.launchpad.dev/%7Eperson-name.../product-name.../branch.../+recipes
-The "Base branch" column should not be shown.
-
- >>> print_recipe_listing_head(nopriv_browser)
- Name
- Owner
- Registered
-
-The branch page should have a list of all the recipes the branch is a
-base_branch for.
-
- >>> print_recipe_listing_contents(nopriv_browser)
- spr-name... Person-name...
+The "Base Source" column should not be shown.
+
+ >>> print_recipe_listing_head(nopriv_browser)
+ Name
+ Owner
+ Registered
+
+The recipe listing page should have a list of all the recipes the branch is
+a base for.
+
+ >>> print_recipe_listing_contents(nopriv_browser)
+ spr-name... Person-name...
+ spr-name... Person-name...
+ spr-name... Person-name...
+
+
+Git Recipe Listings
+===================
+
+Create a new sample repository, some branches in it, and some source package
+recipes to go along with them.
+
+ >>> login('foo.bar@xxxxxxxxxxxxx')
+ >>> repository = factory.makeGitRepository()
+ >>> ref1, ref2, ref3 = factory.makeGitRefs(
+ ... repository=repository,
+ ... paths=[u"refs/heads/a", u"refs/heads/b", u"refs/heads/c"])
+ >>> recipe1a = factory.makeSourcePackageRecipe(branches=[ref1])
+ >>> recipe1b = factory.makeSourcePackageRecipe(branches=[ref1])
+ >>> recipe2 = factory.makeSourcePackageRecipe(branches=[ref2])
+ >>> recipe3 = factory.makeSourcePackageRecipe(branches=[ref3])
+
+Keep these urls, including the target url. We'll use these later.
+
+ >>> repository_url = canonical_url(repository)
+ >>> ref1_url = canonical_url(ref1)
+ >>> target_url = canonical_url(repository.target)
+
+ >>> logout()
+
+Since there are 4 recipes associated with this repository now, the link
+should now read "4 recipes." Let's click through.
+
+ >>> nopriv_browser.open(repository_url)
+ >>> nopriv_browser.getLink('4 recipes').click()
+ >>> print nopriv_browser.url
+ http://code.launchpad.dev/%7Eperson-name.../product-name.../+git/gitrepository.../+recipes
+
+The "Base Source" column should not be shown.
+
+ >>> print_recipe_listing_head(nopriv_browser)
+ Name
+ Owner
+ Registered
+
+The recipe listing page should have a list of all the recipes the repository
+is a base for.
+
+ >>> print_recipe_listing_contents(nopriv_browser)
+ spr-name... Person-name...
+ spr-name... Person-name...
+ spr-name... Person-name...
+ spr-name... Person-name...
+
+If we start from one of the branches instead, then only two recipes are
+listed.
+
+ >>> nopriv_browser.open(ref1_url)
+ >>> nopriv_browser.getLink('2 recipes').click()
+ >>> print nopriv_browser.url
+ http://code.launchpad.dev/%7Eperson-name.../product-name.../+git/gitrepository.../+ref/a/+recipes
+
+ >>> print_recipe_listing_head(nopriv_browser)
+ Name
+ Owner
+ Registered
+
+ >>> print_recipe_listing_contents(nopriv_browser)
spr-name... Person-name...
spr-name... Person-name...
@@ -81,7 +147,7 @@
>>> print_recipe_listing_head(nopriv_browser)
Name
Owner
- Base Branch
+ Base Source
Registered
The listings should now show all recipes whose base branch is a branch from
@@ -92,6 +158,25 @@
spr-name... Person-name... lp://dev/... ...
spr-name... Person-name... lp://dev/... ...
+The same thing works for the target of the former Git repository test.
+
+ >>> nopriv_browser.open(target_url)
+ >>> nopriv_browser.getLink('View source package recipes').click()
+ >>> print nopriv_browser.url
+ http://code.launchpad.dev/product-name.../+recipes
+
+ >>> print_recipe_listing_head(nopriv_browser)
+ Name
+ Owner
+ Base Source
+ Registered
+
+ >>> print_recipe_listing_contents(nopriv_browser)
+ spr-name... Person-name... lp:~.../+git/... ...
+ spr-name... Person-name... lp:~.../+git/... ...
+ spr-name... Person-name... lp:~.../+git/... ...
+ spr-name... Person-name... lp:~.../+git/... ...
+
Person Recipe Listings
======================
@@ -115,7 +200,7 @@
>>> print_recipe_listing_head(nopriv_browser)
Name
- Base Branch
+ Base Source
Registered
The listings should now show all recipes whose base branch is a branch from
=== modified file 'lib/lp/code/templates/branch-recipes.pt'
--- lib/lp/code/templates/branch-recipes.pt 2015-10-05 13:36:06 +0000
+++ lib/lp/code/templates/branch-recipes.pt 2016-01-12 15:24:34 +0000
@@ -3,7 +3,7 @@
xmlns:metal="http://xml.zope.org/namespaces/metal"
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
tal:define="context_menu view/context/menu:context"
- id="related-bugs-and-blueprints">
+ id="related-recipes">
<h3>Related source package recipes</h3>
=== modified file 'lib/lp/code/templates/gitref-index.pt'
--- lib/lp/code/templates/gitref-index.pt 2015-09-18 15:41:08 +0000
+++ lib/lp/code/templates/gitref-index.pt 2016-01-12 15:24:34 +0000
@@ -7,6 +7,15 @@
i18n:domain="launchpad"
>
+<metal:block fill-slot="head_epilogue">
+ <style type="text/css">
+ #merge-summary, #recipe-summary {
+ margin-top: .5em;
+ margin-bottom: .1em;
+ }
+ </style>
+</metal:block>
+
<body>
<tal:registering metal:fill-slot="registering">
@@ -24,10 +33,10 @@
</div>
<div class="yui-g">
- <div id="ref-relations" class="portlet"
- tal:condition="python: view.show_merge_links or view.show_snap_information">
+ <div id="ref-relations" class="portlet">
<tal:ref-pending-merges
replace="structure context/@@++ref-pending-merges" />
+ <tal:ref-recipes replace="structure context/@@++ref-recipes" />
<div metal:use-macro="context/@@+snap-macros/related-snaps" />
</div>
</div>
=== added file 'lib/lp/code/templates/gitref-recipes.pt'
--- lib/lp/code/templates/gitref-recipes.pt 1970-01-01 00:00:00 +0000
+++ lib/lp/code/templates/gitref-recipes.pt 2016-01-12 15:24:34 +0000
@@ -0,0 +1,19 @@
+<div
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ id="related-recipes">
+
+ <h3>Related source package recipes</h3>
+
+ <div id="recipe-links" class="actions">
+ <div id="recipe-summary">
+ <img src="/@@/source-package-recipe" />
+ <tal:recipes replace="structure view/recipes_link" />
+
+ <a href="/+help-code/related-recipes.html" target="help"
+ class="sprite maybe action-icon">(?)</a>
+ </div>
+ </div>
+
+</div>
=== modified file 'lib/lp/code/templates/gitrepository-index.pt'
--- lib/lp/code/templates/gitrepository-index.pt 2015-12-04 15:48:39 +0000
+++ lib/lp/code/templates/gitrepository-index.pt 2016-01-12 15:24:34 +0000
@@ -9,6 +9,10 @@
<metal:block fill-slot="head_epilogue">
<style type="text/css">
+ #merge-summary, #recipe-summary {
+ margin-top: .5em;
+ margin-bottom: .1em;
+ }
#clone-url dt {
font-weight: strong;
}
@@ -41,8 +45,9 @@
</div>
<div class="yui-g">
- <div id="repository-relations" class="portlet"
- tal:condition="view/show_snap_information">
+ <div id="repository-relations" class="portlet">
+ <tal:repository-recipes
+ replace="structure context/@@++repository-recipes" />
<div metal:use-macro="context/@@+snap-macros/related-snaps">
<metal:context-type fill-slot="context_type">repository</metal:context-type>
</div>
=== added file 'lib/lp/code/templates/gitrepository-recipes.pt'
--- lib/lp/code/templates/gitrepository-recipes.pt 1970-01-01 00:00:00 +0000
+++ lib/lp/code/templates/gitrepository-recipes.pt 2016-01-12 15:24:34 +0000
@@ -0,0 +1,19 @@
+<div
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ id="related-recipes">
+
+ <h3>Related source package recipes</h3>
+
+ <div id="recipe-links" class="actions">
+ <div id="recipe-summary">
+ <img src="/@@/source-package-recipe" />
+ <tal:recipes replace="structure view/recipes_link" />
+
+ <a href="/+help-code/related-recipes.html" target="help"
+ class="sprite maybe action-icon">(?)</a>
+ </div>
+ </div>
+
+</div>
=== modified file 'lib/lp/code/templates/sourcepackagerecipe-listing.pt'
--- lib/lp/code/templates/sourcepackagerecipe-listing.pt 2011-02-23 01:24:09 +0000
+++ lib/lp/code/templates/sourcepackagerecipe-listing.pt 2016-01-12 15:24:34 +0000
@@ -15,7 +15,7 @@
<tr>
<th colspan="2">Name</th>
<th tal:condition="view/owner_enabled">Owner</th>
- <th tal:condition="view/branch_enabled">Base Branch</th>
+ <th tal:condition="view/branch_enabled">Base Source</th>
<th>Registered</th>
</tr>
</thead>
@@ -32,8 +32,8 @@
</a>
</td>
<td tal:condition="view/branch_enabled">
- <a tal:replace="structure recipe/base_branch/fmt:link">
- Branch
+ <a tal:replace="structure recipe/base/fmt:link">
+ Source
</a>
</td>
<td tal:content="recipe/date_created/fmt:datetime" />
Follow ups