launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #18124
[Merge] lp:~cjwatson/launchpad/git-ref-url into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/git-ref-url into lp:launchpad with lp:~cjwatson/launchpad/git-ref-scanner as a prerequisite.
Commit message:
Add basic navigation support for Git references.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/git-ref-url/+merge/252900
Add basic navigation support for Git references.
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/git-ref-url into lp:launchpad.
=== modified file 'lib/lp/app/browser/configure.zcml'
--- lib/lp/app/browser/configure.zcml 2014-11-29 01:33:59 +0000
+++ lib/lp/app/browser/configure.zcml 2015-03-13 14:20:26 +0000
@@ -1,4 +1,4 @@
-<!-- Copyright 2009-2014 Canonical Ltd. This software is licensed under the
+<!-- Copyright 2009-2015 Canonical Ltd. This software is licensed under the
GNU Affero General Public License version 3 (see the file LICENSE).
-->
@@ -729,6 +729,13 @@
/>
<adapter
+ for="lp.code.interfaces.gitrepository.IGitRepository"
+ provides="zope.traversing.interfaces.IPathAdapter"
+ factory="lp.app.browser.tales.GitRepositoryFormatterAPI"
+ name="fmt"
+ />
+
+ <adapter
for="lp.bugs.interfaces.bugbranch.IBugBranch"
provides="zope.traversing.interfaces.IPathAdapter"
factory="lp.app.browser.tales.BugBranchFormatterAPI"
=== modified file 'lib/lp/app/browser/tales.py'
--- lib/lp/app/browser/tales.py 2014-11-27 05:01:51 +0000
+++ lib/lp/app/browser/tales.py 2015-03-13 14:20:26 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2014 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2015 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Implementation of the lp: htmlform: fmt: namespaces in TALES."""
@@ -1674,6 +1674,15 @@
}
+class GitRepositoryFormatterAPI(CustomizableFormatter):
+ """Adapter for IGitRepository objects to a formatted string."""
+
+ _link_summary_template = '%(display_name)s'
+
+ def _link_summary_values(self):
+ return {'display_name': self._context.display_name}
+
+
class BugBranchFormatterAPI(CustomizableFormatter):
"""Adapter providing fmt support for BugBranch objects"""
=== modified file 'lib/lp/app/doc/tales.txt'
--- lib/lp/app/doc/tales.txt 2014-12-31 13:24:43 +0000
+++ lib/lp/app/doc/tales.txt 2015-03-13 14:20:26 +0000
@@ -394,6 +394,7 @@
* people / teams
* branches
+ * Git repositories
* bugs
* bug subscriptions
* bug tasks
@@ -520,6 +521,20 @@
<a href=".../~eric/fooix/bar" class="sprite branch">lp://dev/fooix</a>
+Git repositories
+................
+
+For Git repositories, fmt:link links to the branch page.
+
+ >>> from lp.code.interfaces.gitrepository import GIT_FEATURE_FLAG
+ >>> from lp.services.features.testing import FeatureFixture
+ >>> with FeatureFixture({GIT_FEATURE_FLAG: 'on'}):
+ ... repository = factory.makeGitRepository(
+ ... owner=eric, target=fooix, name=u'bar')
+ ... print test_tales("repository/fmt:link", repository=repository)
+ <a href=".../~eric/fooix/+git/bar">lp:~eric/fooix/+git/bar</a>
+
+
Bugs
....
=== modified file 'lib/lp/code/browser/configure.zcml'
--- lib/lp/code/browser/configure.zcml 2015-03-05 16:23:26 +0000
+++ lib/lp/code/browser/configure.zcml 2015-03-13 14:20:26 +0000
@@ -771,6 +771,9 @@
<browser:url
for="lp.code.interfaces.gitrepository.IGitRepository"
urldata="lp.code.browser.gitrepository.GitRepositoryURL"/>
+ <browser:navigation
+ module="lp.code.browser.gitrepository"
+ classes="GitRepositoryNavigation"/>
<browser:menus
module="lp.code.browser.gitrepository"
classes="
@@ -795,6 +798,21 @@
factory="lp.code.browser.gitrepository.GitRepositoryBreadcrumb"
permission="zope.Public"/>
+ <browser:defaultView
+ for="lp.code.interfaces.gitref.IGitRef"
+ name="+index"/>
+ <browser:url
+ for="lp.code.interfaces.gitref.IGitRef"
+ path_expression="string:+ref/${path}"
+ attribute_to_parent="repository"
+ rootsite="code"/>
+ <browser:page
+ for="lp.code.interfaces.gitref.IGitRef"
+ class="lp.code.browser.gitref.GitRefView"
+ permission="launchpad.View"
+ name="+index"
+ template="../templates/gitref-index.pt"/>
+
<browser:menus
classes="ProductBranchesMenu"
module="lp.code.browser.branchlisting"/>
=== added file 'lib/lp/code/browser/gitref.py'
--- lib/lp/code/browser/gitref.py 1970-01-01 00:00:00 +0000
+++ lib/lp/code/browser/gitref.py 2015-03-13 14:20:26 +0000
@@ -0,0 +1,19 @@
+# Copyright 2015 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Git reference views."""
+
+__metaclass__ = type
+
+__all__ = [
+ 'GitRefView',
+ ]
+
+from lp.services.webapp import LaunchpadView
+
+
+class GitRefView(LaunchpadView):
+
+ @property
+ def label(self):
+ return self.context.display_name
=== modified file 'lib/lp/code/browser/gitrepository.py'
--- lib/lp/code/browser/gitrepository.py 2015-03-04 16:49:42 +0000
+++ lib/lp/code/browser/gitrepository.py 2015-03-13 14:20:26 +0000
@@ -8,6 +8,7 @@
__all__ = [
'GitRepositoryBreadcrumb',
'GitRepositoryContextMenu',
+ 'GitRepositoryNavigation',
'GitRepositoryURL',
'GitRepositoryView',
]
@@ -16,12 +17,15 @@
from zope.interface import implements
from lp.app.browser.informationtype import InformationTypePortletMixin
+from lp.app.errors import NotFoundError
from lp.code.interfaces.gitrepository import IGitRepository
from lp.services.config import config
from lp.services.webapp import (
ContextMenu,
LaunchpadView,
Link,
+ Navigation,
+ stepto,
)
from lp.services.webapp.authorization import (
check_permission,
@@ -54,6 +58,24 @@
return self.context.unique_name.split("/")[-1]
+class GitRepositoryNavigation(Navigation):
+
+ usedfor = IGitRepository
+
+ @stepto("+ref")
+ def traverse_ref(self):
+ segments = list(self.request.getTraversalStack())
+ ref_segments = []
+ while segments:
+ ref_segments.append(segments.pop())
+ ref = self.context.getRefByPath("/".join(ref_segments))
+ if ref is not None:
+ for _ in range(len(ref_segments)):
+ self.request.stepstogo.consume()
+ return ref
+ raise NotFoundError
+
+
class GitRepositoryContextMenu(ContextMenu):
"""Context menu for `IGitRepository`."""
=== modified file 'lib/lp/code/browser/tests/test_gitrepository.py'
--- lib/lp/code/browser/tests/test_gitrepository.py 2015-03-05 15:28:11 +0000
+++ lib/lp/code/browser/tests/test_gitrepository.py 2015-03-13 14:20:26 +0000
@@ -24,15 +24,36 @@
login_person,
logout,
person_logged_in,
+ TestCaseWithFactory,
)
from lp.testing.layers import DatabaseFunctionalLayer
from lp.testing.pages import (
setupBrowser,
setupBrowserForUser,
)
+from lp.testing.publication import test_traverse
from lp.testing.views import create_initialized_view
+class TestGitRepositoryNavigation(TestCaseWithFactory):
+
+ layer = DatabaseFunctionalLayer
+
+ def setUp(self):
+ super(TestGitRepositoryNavigation, self).setUp()
+ self.useFixture(FeatureFixture({GIT_FEATURE_FLAG: u"on"}))
+
+ def test_traverse_ref(self):
+ [ref] = self.factory.makeGitRefs()
+ url = "%s/+ref/%s" % (canonical_url(ref.repository), ref.path)
+ self.assertEqual(ref, test_traverse(url)[0])
+
+ def test_traverse_ref_missing(self):
+ repository = self.factory.makeGitRepository()
+ url = "%s/+ref/refs/heads/master" % canonical_url(repository)
+ self.assertRaises(NotFound, test_traverse, url)
+
+
class TestGitRepositoryView(BrowserTestCase):
layer = DatabaseFunctionalLayer
=== modified file 'lib/lp/code/interfaces/gitref.py'
--- lib/lp/code/interfaces/gitref.py 2015-03-13 14:20:26 +0000
+++ lib/lp/code/interfaces/gitref.py 2015-03-13 14:20:26 +0000
@@ -41,3 +41,7 @@
object_type = Choice(
title=_("Object type"), required=True, readonly=True,
vocabulary=GitObjectType)
+
+ display_name = TextLine(
+ title=_("Display name"), required=True, readonly=True,
+ description=_("Display name of the reference."))
=== modified file 'lib/lp/code/model/gitref.py'
--- lib/lp/code/model/gitref.py 2015-03-13 14:20:26 +0000
+++ lib/lp/code/model/gitref.py 2015-03-13 14:20:26 +0000
@@ -35,3 +35,7 @@
commit_sha1 = Unicode(name='commit_sha1', allow_none=False)
object_type = EnumCol(enum=GitObjectType, notNull=True)
+
+ @property
+ def display_name(self):
+ return self.path.split("/", 2)[-1]
=== added file 'lib/lp/code/model/tests/test_gitref.py'
--- lib/lp/code/model/tests/test_gitref.py 1970-01-01 00:00:00 +0000
+++ lib/lp/code/model/tests/test_gitref.py 2015-03-13 14:20:26 +0000
@@ -0,0 +1,24 @@
+# Copyright 2015 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Tests for Git references."""
+
+__metaclass__ = type
+
+from lp.code.interfaces.gitrepository import GIT_FEATURE_FLAG
+from lp.services.features.testing import FeatureFixture
+from lp.testing import TestCaseWithFactory
+from lp.testing.layers import DatabaseFunctionalLayer
+
+
+class TestGitRef(TestCaseWithFactory):
+
+ layer = DatabaseFunctionalLayer
+
+ def test_display_name(self):
+ self.useFixture(FeatureFixture({GIT_FEATURE_FLAG: u"on"}))
+ [master, personal] = self.factory.makeGitRefs(
+ paths=[u"refs/heads/master", u"refs/heads/people/foo/bar"])
+ self.assertEqual(
+ ["master", "people/foo/bar"],
+ [ref.display_name for ref in (master, personal)])
=== added file 'lib/lp/code/templates/gitref-index.pt'
--- lib/lp/code/templates/gitref-index.pt 1970-01-01 00:00:00 +0000
+++ lib/lp/code/templates/gitref-index.pt 2015-03-13 14:20:26 +0000
@@ -0,0 +1,34 @@
+<html
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ metal:use-macro="view/macro:page/main_side"
+ i18n:domain="launchpad"
+>
+
+<body>
+
+<div metal:fill-slot="main">
+
+ <div class="yui-g">
+ <div id="ref-info" class="portlet">
+ <h2>Branch information</h2>
+ <div class="two-column-list">
+ <dl id="name">
+ <dt>Name:</dt>
+ <dd tal:content="context/display_name" />
+ </dl>
+
+ <dl id="repository">
+ <dt>Repository:</dt>
+ <dd tal:content="structure context/repository/fmt:link" />
+ </dl>
+ </div>
+ </div>
+ </div>
+
+</div>
+
+</body>
+</html>
=== modified file 'lib/lp/registry/browser/person.py'
--- lib/lp/registry/browser/person.py 2015-03-09 15:04:54 +0000
+++ lib/lp/registry/browser/person.py 2015-03-13 14:20:26 +0000
@@ -379,7 +379,8 @@
iter_segments, owner=self.context)
if repository is None:
raise NotFoundError
- for i in range(num_segments - len(list(iter_segments))):
+ # Subtract one because the pillar has already been traversed.
+ for _ in range(num_segments - len(list(iter_segments)) - 1):
self.request.stepstogo.consume()
if IProduct.providedBy(target):
Follow ups