← Back to team overview

launchpad-reviewers team mailing list archive

Re: [Merge] lp:~wgrant/launchpad/gitlisting into lp:launchpad

 

Review: Approve

Looks fine, just a few inline suggestions.

Diff comments:

> === modified file 'lib/lp/code/browser/branchlisting.py'
> --- lib/lp/code/browser/branchlisting.py	2015-06-02 10:53:52 +0000
> +++ lib/lp/code/browser/branchlisting.py	2015-06-04 09:15:20 +0000
> @@ -68,7 +68,6 @@
>  from lp.bugs.interfaces.bugbranch import IBugBranchSet
>  from lp.code.browser.branch import BranchMirrorMixin
>  from lp.code.browser.branchmergeproposallisting import ActiveReviewsView
> -from lp.code.browser.gitrepository import GitRefBatchNavigator
>  from lp.code.browser.summary import BranchCountSummaryView
>  from lp.code.enums import (
>      BranchLifecycleStatus,
> @@ -85,7 +84,6 @@
>  from lp.code.interfaces.branchcollection import IAllBranches
>  from lp.code.interfaces.branchnamespace import IBranchNamespacePolicy
>  from lp.code.interfaces.branchtarget import IBranchTarget
> -from lp.code.interfaces.gitrepository import IGitRepositorySet
>  from lp.code.interfaces.revision import IRevisionSet
>  from lp.code.interfaces.revisioncache import IRevisionCache
>  from lp.code.interfaces.seriessourcepackagebranch import (
> @@ -526,7 +524,6 @@
>      field_names = ['lifecycle', 'sort_by']
>      development_focus_branch = None
>      show_set_development_focus = False
> -    default_git_repository = None
>      custom_widget('lifecycle', LaunchpadDropdownWidget)
>      custom_widget('sort_by', LaunchpadDropdownWidget)
>      # Showing the series links is only really useful on product listing
> @@ -1098,26 +1095,6 @@
>          else:
>              return None
>  
> -    @cachedproperty
> -    def default_git_repository(self):
> -        repository = getUtility(IGitRepositorySet).getDefaultRepository(
> -            self.context)
> -        if repository is None:
> -            return None
> -        elif check_permission('launchpad.View', repository):
> -            return repository
> -        else:
> -            return None
> -
> -    def default_git_repository_branches(self):
> -        """All branches in the default Git repository, sorted for display."""
> -        return GitRefBatchNavigator(self, self.default_git_repository)
> -
> -    @property
> -    def has_default_git_repository(self):
> -        """Is there a default Git repository?"""
> -        return self.default_git_repository is not None
> -
>      @property
>      def no_branch_message(self):
>          if (self.selected_lifecycle_status is not None
> 
> === modified file 'lib/lp/code/browser/configure.zcml'
> --- lib/lp/code/browser/configure.zcml	2015-06-02 08:57:02 +0000
> +++ lib/lp/code/browser/configure.zcml	2015-06-04 09:15:20 +0000
> @@ -875,6 +875,24 @@
>          attribute_to_parent="repository"
>          rootsite="code"/>
>  
> +    <browser:page
> +        for="lp.registry.interfaces.product.IProduct"
> +        class="lp.code.browser.gitlisting.TargetGitListingView"
> +        permission="zope.Public"
> +        name="+git"
> +        template="../templates/gitlisting.pt"/>
> +    <browser:page
> +        for="lp.registry.interfaces.personproduct.IPersonProduct"
> +        class="lp.code.browser.gitlisting.PersonTargetGitListingView"
> +        permission="zope.Public"
> +        name="+git"
> +        template="../templates/gitlisting.pt"/>
> +    <browser:page
> +        for="lp.code.browser.gitlisting.IGitRepositoryBatchNavigator"
> +        name="+gitrepository-listing"
> +        template="../templates/gitrepository-listing.pt"
> +        permission="zope.Public"/>
> +
>      <browser:menus
>          classes="ProductBranchesMenu"
>          module="lp.code.browser.branchlisting"/>
> 
> === added file 'lib/lp/code/browser/gitlisting.py'
> --- lib/lp/code/browser/gitlisting.py	1970-01-01 00:00:00 +0000
> +++ lib/lp/code/browser/gitlisting.py	2015-06-04 09:15:20 +0000
> @@ -0,0 +1,154 @@
> +# Copyright 2015 Canonical Ltd.  This software is licensed under the
> +# GNU Affero General Public License version 3 (see the file LICENSE).
> +
> +"""View classes for Git repository listings."""
> +
> +__metaclass__ = type
> +
> +__all__ = [
> +    'PersonTargetGitListingView',
> +    'TargetGitListingView',
> +    ]
> +
> +from storm.expr import Desc
> +from zope.component import getUtility
> +from zope.interface import (
> +    implements,
> +    Interface,
> +    )
> +
> +from lp.app.enums import PRIVATE_INFORMATION_TYPES
> +from lp.code.browser.gitrepository import GitRefBatchNavigator
> +from lp.code.interfaces.gitcollection import IGitCollection
> +from lp.code.interfaces.gitnamespace import (
> +    get_git_namespace,
> +    IGitNamespacePolicy,
> +    )
> +from lp.code.interfaces.gitrepository import IGitRepositorySet
> +from lp.code.model.gitrepository import GitRepository
> +from lp.registry.interfaces.personproduct import IPersonProduct
> +from lp.services.config import config
> +from lp.services.propertycache import cachedproperty
> +from lp.services.webapp.batching import TableBatchNavigator
> +from lp.services.webapp.publisher import LaunchpadView
> +from lp.services.webapp.authorization import check_permission
> +
> +
> +class IGitRepositoryBatchNavigator(Interface):
> +    pass
> +
> +
> +class GitRepositoryBatchNavigator(TableBatchNavigator):
> +    """Batch up Git repository listings."""
> +    implements(IGitRepositoryBatchNavigator)
> +
> +    variable_name_prefix = 'repo'
> +
> +    def __init__(self, view, repo_collection):
> +        super(GitRepositoryBatchNavigator, self).__init__(
> +            repo_collection.getRepositories().order_by(
> +                Desc(GitRepository.date_last_modified)),
> +            view.request, size=config.launchpad.branchlisting_batch_size)
> +        self.view = view
> +        self.column_count = 2
> +
> +
> +class BaseGitListingView(LaunchpadView):
> +
> +    @property
> +    def target(self):
> +        raise NotImplementedError()
> +
> +    @cachedproperty
> +    def default_git_repository(self):
> +        raise NotImplementedError()
> +
> +    @property
> +    def repo_collection(self):
> +        raise NotImplementedError()
> +
> +    def default_git_repository_branches(self):
> +        """All branches in the default Git repository, sorted for display."""
> +        return GitRefBatchNavigator(self, self.default_git_repository)
> +
> +    @cachedproperty
> +    def default_information_type(self):
> +        """The default information type for new repos."""
> +        if self.user is None:
> +            return None
> +        namespace = get_git_namespace(self.target, self.user)
> +        policy = IGitNamespacePolicy(namespace)
> +        return policy.getDefaultInformationType(self.user)
> +
> +    @property
> +    def default_information_type_title(self):
> +        """The title of the default information type for new branches."""
> +        information_type = self.default_information_type
> +        if information_type is None:
> +            return None
> +        return information_type.title
> +
> +    @property
> +    def default_information_type_is_private(self):
> +        """The title of the default information type for new branches."""
> +        return self.default_information_type in PRIVATE_INFORMATION_TYPES
> +
> +    @property
> +    def repos(self):
> +        return GitRepositoryBatchNavigator(self, self.repo_collection)
> +
> +
> +class TargetGitListingView(BaseGitListingView):
> +
> +    page_title = 'Git'
> +
> +    @property
> +    def target(self):
> +        return self.context
> +
> +    @cachedproperty
> +    def default_git_repository(self):
> +        repo = getUtility(IGitRepositorySet).getDefaultRepository(
> +            self.context)
> +        if repo is None:
> +            return None
> +        elif check_permission('launchpad.View', repo):
> +            return repo
> +        else:
> +            return None
> +
> +    @property
> +    def repo_collection(self):
> +        return IGitCollection(self.target).visibleByUser(self.user)
> +
> +
> +class PersonTargetGitListingView(BaseGitListingView):
> +
> +    page_title = 'Git'
> +
> +    @property
> +    def label(self):
> +        return 'Git repositories for %s' % self.target.displayname
> +
> +    @property
> +    def target(self):
> +        if IPersonProduct.providedBy(self.context):
> +            return self.context.product
> +        else:
> +            raise Exception("Unknown context: %r" % self.context)

Any reason not to preemptively handle IPersonDistributionSourcePackage here too?

> +
> +    @cachedproperty
> +    def default_git_repository(self):
> +        repo = getUtility(IGitRepositorySet).getDefaultRepositoryForOwner(
> +            self.context.person, self.target)
> +        if repo is None:
> +            return None
> +        elif check_permission('launchpad.View', repo):
> +            return repo
> +        else:
> +            return None
> +
> +    @property
> +    def repo_collection(self):
> +        return IGitCollection(self.target).ownedBy(
> +            self.context.person).visibleByUser(self.user)

You could just use IGitCollection(self.context).visibleByUser(self.user) here, which is shorter and works for both IPersonProduct and IPersonDistributionSourcePackage.

> 
> === added file 'lib/lp/code/browser/tests/test_gitlisting.py'
> --- lib/lp/code/browser/tests/test_gitlisting.py	1970-01-01 00:00:00 +0000
> +++ lib/lp/code/browser/tests/test_gitlisting.py	2015-06-04 09:15:20 +0000
> @@ -0,0 +1,271 @@
> +# Copyright 2015 Canonical Ltd.  This software is licensed under the
> +# GNU Affero General Public License version 3 (see the file LICENSE).
> +
> +"""Unit tests for Git listing views."""
> +
> +__metaclass__ = type
> +
> +from BeautifulSoup import BeautifulSoup
> +from zope.component import getUtility
> +
> +from lp.app.enums import InformationType
> +from lp.code.interfaces.gitrepository import IGitRepositorySet
> +from lp.registry.model.personproduct import PersonProduct
> +from lp.testing import (
> +    admin_logged_in,
> +    anonymous_logged_in,
> +    person_logged_in,
> +    TestCaseWithFactory,
> +    )
> +from lp.testing.layers import DatabaseFunctionalLayer
> +from lp.testing.views import create_initialized_view
> +
> +
> +class TestTargetGitListingView(TestCaseWithFactory):
> +
> +    layer = DatabaseFunctionalLayer
> +
> +    def test_rendering(self):
> +        owner = self.factory.makePerson(name=u"foowner")
> +        product = self.factory.makeProduct(name=u"foo", owner=owner)
> +        main_repo = self.factory.makeGitRepository(
> +            owner=owner, target=product, name=u"foo")
> +        self.factory.makeGitRefs(
> +            main_repo,
> +            paths=[u"refs/heads/master", u"refs/heads/1.0", u"refs/tags/1.1"])
> +
> +        other_repo = self.factory.makeGitRepository(
> +            owner=self.factory.makePerson(name=u"contributor"),
> +            target=product, name=u"foo")
> +        self.factory.makeGitRefs(other_repo, paths=[u"refs/heads/bug-1234"])
> +        self.factory.makeGitRepository(
> +            owner=self.factory.makePerson(name=u"random"),
> +            target=product, name=u"bar")
> +
> +        with admin_logged_in():
> +            getUtility(IGitRepositorySet).setDefaultRepository(
> +                target=product, repository=main_repo)
> +            getUtility(IGitRepositorySet).setDefaultRepositoryForOwner(
> +                owner=other_repo.owner, target=product, repository=other_repo,
> +                user=other_repo.owner)
> +
> +        view = create_initialized_view(product, '+git')
> +        self.assertEqual(main_repo, view.default_git_repository)
> +
> +        content = view()
> +        soup = BeautifulSoup(content)
> +
> +        # Clone instructions for the default repo are present.
> +        self.assertEqual(
> +            'git://git.launchpad.dev/foo',
> +            soup.find(attrs={'class': 'anon-url'}).find(text=True))
> +        self.assertEqual(
> +            'https://git.launchpad.dev/~foowner/foo/+git/foo',
> +            soup.find(text='Browse the code').parent['href'])
> +
> +        # The default repo's branches are shown, but not its tags.
> +        table = soup.find(
> +            'div', id='default-repository-branches').find('table')
> +        self.assertContentEqual(
> +            ['1.0', 'master'],
> +            [link.find(text=True) for link in table.findAll('a')])
> +        self.assertEndsWith(
> +            table.find(text="1.0").parent['href'],
> +            u"/~foowner/foo/+git/foo/+ref/1.0")
> +
> +        # Other repos are listed.
> +        table = soup.find(
> +            'div', id='gitrepositories-table-listing').find('table')
> +        self.assertContentEqual(
> +            ['lp:foo', 'lp:~random/foo/+git/bar', 'lp:~contributor/foo'],
> +            [link.find(text=True) for link in table.findAll('a')])
> +        self.assertEndsWith(
> +            table.find(text="lp:~contributor/foo").parent['href'],
> +            u"/~contributor/foo/+git/foo")
> +
> +        # But not their branches.
> +        self.assertNotIn('bug-1234', content)
> +
> +    def test_copes_with_no_default(self):
> +        owner = self.factory.makePerson(name=u"foowner")
> +        product = self.factory.makeProduct(name=u"foo", owner=owner)
> +
> +        self.factory.makeGitRepository(
> +            owner=self.factory.makePerson(name=u"contributor"),
> +            target=product, name=u"foo")
> +
> +        view = create_initialized_view(product, '+git')
> +        self.assertIs(None, view.default_git_repository)
> +
> +        content = view()
> +        soup = BeautifulSoup(content)
> +
> +        # No details about the non-existent default repo are shown.
> +        # XXX: This should show instructions to create one.
> +        self.assertNotIn('Branches', content)
> +        self.assertNotIn('Browse the code', content)
> +        self.assertNotIn('git clone', content)
> +
> +        # Other repos are listed.
> +        table = soup.find(
> +            'div', id='gitrepositories-table-listing').find('table')
> +        self.assertContentEqual(
> +            ['lp:~contributor/foo/+git/foo'],
> +            [link.find(text=True) for link in table.findAll('a')])
> +
> +    def test_copes_with_private_repos(self):
> +        product = self.factory.makeProduct()
> +        invisible_repo = self.factory.makeGitRepository(
> +            target=product, information_type=InformationType.PRIVATESECURITY)
> +        other_repo = self.factory.makeGitRepository(
> +            target=product, information_type=InformationType.PUBLIC)
> +        with admin_logged_in():
> +            getUtility(IGitRepositorySet).setDefaultRepository(
> +                target=product, repository=invisible_repo)
> +
> +        # An anonymous user can't see the default.
> +        with anonymous_logged_in():
> +            anon_view = create_initialized_view(product, '+git')
> +            self.assertIs(None, anon_view.default_git_repository)
> +            self.assertContentEqual(
> +                [other_repo], anon_view.repo_collection.getRepositories())
> +
> +        # Neither can a random unprivileged user.
> +        with person_logged_in(self.factory.makePerson()):
> +            anon_view = create_initialized_view(product, '+git')
> +            self.assertIs(None, anon_view.default_git_repository)
> +            self.assertContentEqual(
> +                [other_repo], anon_view.repo_collection.getRepositories())
> +
> +        # But someone who can see the repo gets the normal view.
> +        with person_logged_in(product.owner):
> +            owner_view = create_initialized_view(
> +                product, '+git', user=product.owner)
> +            self.assertEqual(invisible_repo, owner_view.default_git_repository)
> +            self.assertContentEqual(
> +                [invisible_repo, other_repo],
> +                owner_view.repo_collection.getRepositories())
> +
> +
> +class TestPersonTargetGitListingView(TestCaseWithFactory):
> +
> +    layer = DatabaseFunctionalLayer
> +
> +    def test_rendering(self):
> +        owner = self.factory.makePerson(name=u"dev")
> +        product = self.factory.makeProduct(name=u"foo")
> +        default_repo = self.factory.makeGitRepository(
> +            owner=owner, target=product, name=u"foo")
> +        self.factory.makeGitRefs(
> +            default_repo,
> +            paths=[u"refs/heads/master", u"refs/heads/bug-1234"])
> +
> +        other_repo = self.factory.makeGitRepository(
> +            owner=owner, target=product, name=u"bar")
> +        self.factory.makeGitRefs(other_repo, paths=[u"refs/heads/bug-2468"])
> +
> +        with admin_logged_in():
> +            getUtility(IGitRepositorySet).setDefaultRepositoryForOwner(
> +                owner=owner, target=product, repository=default_repo,
> +                user=owner)
> +
> +        view = create_initialized_view(PersonProduct(owner, product), '+git')
> +        self.assertEqual(default_repo, view.default_git_repository)
> +
> +        content = view()
> +        soup = BeautifulSoup(content)
> +
> +        # Clone instructions for the default repo are present.
> +        self.assertEqual(
> +            'git://git.launchpad.dev/~dev/foo',
> +            soup.find(attrs={'class': 'anon-url'}).find(text=True))
> +        self.assertEqual(
> +            'https://git.launchpad.dev/~dev/foo/+git/foo',
> +            soup.find(text='Browse the code').parent['href'])
> +
> +        # The default repo's branches are shown.
> +        table = soup.find(
> +            'div', id='default-repository-branches').find('table')
> +        self.assertContentEqual(
> +            ['master', 'bug-1234'],
> +            [link.find(text=True) for link in table.findAll('a')])
> +        self.assertEndsWith(
> +            table.find(text="bug-1234").parent['href'],
> +            u"/~dev/foo/+git/foo/+ref/bug-1234")
> +
> +        # Other repos are listed.
> +        table = soup.find(
> +            'div', id='gitrepositories-table-listing').find('table')
> +        self.assertContentEqual(
> +            ['lp:~dev/foo', 'lp:~dev/foo/+git/bar'],
> +            [link.find(text=True) for link in table.findAll('a')])
> +        self.assertEndsWith(
> +            table.find(text="lp:~dev/foo/+git/bar").parent['href'],
> +            u"/~dev/foo/+git/bar")
> +
> +        # But not their branches.
> +        self.assertNotIn('bug-2468', content)
> +
> +    def test_copes_with_no_default(self):
> +        owner = self.factory.makePerson(name=u"dev")
> +        product = self.factory.makeProduct(name=u"foo", owner=owner)
> +
> +        self.factory.makeGitRepository(
> +            owner=owner, target=product, name=u"foo")
> +
> +        view = create_initialized_view(PersonProduct(owner, product), '+git')
> +        self.assertIs(None, view.default_git_repository)
> +
> +        content = view()
> +        soup = BeautifulSoup(content)
> +
> +        # No details about the non-existent default repo are shown.
> +        # XXX: This should show instructions to create one.
> +        self.assertNotIn('Branches', content)
> +        self.assertNotIn('Browse the code', content)
> +        self.assertNotIn('git clone', content)
> +
> +        # Other repos are listed.
> +        table = soup.find(
> +            'div', id='gitrepositories-table-listing').find('table')
> +        self.assertContentEqual(
> +            ['lp:~dev/foo/+git/foo'],
> +            [link.find(text=True) for link in table.findAll('a')])
> +
> +    def test_copes_with_private_repos(self):
> +        owner = self.factory.makePerson(name=u"dev")
> +        product = self.factory.makeProduct()
> +        invisible_repo = self.factory.makeGitRepository(
> +            owner=owner, target=product,
> +            information_type=InformationType.PRIVATESECURITY)
> +        other_repo = self.factory.makeGitRepository(
> +            owner=owner, target=product,
> +            information_type=InformationType.PUBLIC)
> +        with admin_logged_in():
> +            getUtility(IGitRepositorySet).setDefaultRepositoryForOwner(
> +                owner=owner, target=product, repository=invisible_repo,
> +                user=owner)
> +
> +        pp = PersonProduct(owner, product)
> +
> +        # An anonymous user can't see the default.
> +        with anonymous_logged_in():
> +            anon_view = create_initialized_view(pp, '+git')
> +            self.assertIs(None, anon_view.default_git_repository)
> +            self.assertContentEqual(
> +                [other_repo], anon_view.repo_collection.getRepositories())
> +
> +        # Neither can a random unprivileged user.
> +        with person_logged_in(self.factory.makePerson()):
> +            anon_view = create_initialized_view(pp, '+git')
> +            self.assertIs(None, anon_view.default_git_repository)
> +            self.assertContentEqual(
> +                [other_repo], anon_view.repo_collection.getRepositories())
> +
> +        # But someone who can see the repo gets the normal view.
> +        with person_logged_in(owner):
> +            owner_view = create_initialized_view(pp, '+git', user=owner)
> +            self.assertEqual(invisible_repo, owner_view.default_git_repository)
> +            self.assertContentEqual(
> +                [invisible_repo, other_repo],
> +                owner_view.repo_collection.getRepositories())
> 
> === modified file 'lib/lp/code/browser/tests/test_product.py'
> --- lib/lp/code/browser/tests/test_product.py	2015-06-02 06:35:38 +0000
> +++ lib/lp/code/browser/tests/test_product.py	2015-06-04 09:15:20 +0000
> @@ -19,7 +19,6 @@
>      ServiceUsage,
>      )
>  from lp.code.enums import BranchType
> -from lp.code.interfaces.gitrepository import IGitRepositorySet
>  from lp.code.interfaces.revision import IRevisionSet
>  from lp.registry.enums import BranchSharingPolicy
>  from lp.services.webapp import canonical_url
> @@ -146,38 +145,6 @@
>          expected = 'There are no branches for %s' % product.displayname
>          self.assertIn(expected, html)
>  
> -    def test_no_default_git_repository(self):
> -        # If there is no default Git repository, Product:+branches does not
> -        # try to render one.
> -        product = self.factory.makeProduct()
> -        view = create_initialized_view(
> -            product, '+branches', rootsite='code', principal=product.owner)
> -        self.assertIsNone(view.default_git_repository)
> -        self.assertFalse(view.has_default_git_repository)
> -        content = view()
> -        self.assertNotIn('git clone', content)
> -
> -    def test_default_git_repository(self):
> -        # If there is a default Git repository, Product:+branches shows a
> -        # summary of its branches.
> -        product = self.factory.makeProduct()
> -        repository = self.factory.makeGitRepository(target=product)
> -        self.factory.makeGitRefs(
> -            repository=repository,
> -            paths=[u"refs/heads/master", u"refs/heads/another-branch"])
> -        with person_logged_in(product.owner):
> -            getUtility(IGitRepositorySet).setDefaultRepository(
> -                product, repository)
> -        view = create_initialized_view(
> -            product, '+branches', rootsite='code', principal=product.owner)
> -        self.assertEqual(repository, view.default_git_repository)
> -        self.assertTrue(view.has_default_git_repository)
> -        content = view()
> -        self.assertIn('git clone', content)
> -        # XXX cjwatson 2015-04-30: These tests are not very precise.
> -        self.assertIn('master', content)
> -        self.assertIn('another-branch', content)
> -
>  
>  class TestProductBranchesServiceUsages(ProductTestBase, BrowserTestCase):
>      """Tests for the product code page, especially the usage messasges."""
> 
> === added file 'lib/lp/code/templates/gitlisting.pt'
> --- lib/lp/code/templates/gitlisting.pt	1970-01-01 00:00:00 +0000
> +++ lib/lp/code/templates/gitlisting.pt	2015-06-04 09:15:20 +0000
> @@ -0,0 +1,72 @@
> +<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"
> +>
> +<head>
> +  <tal:head-epilogue metal:fill-slot="head_epilogue">
> +    <meta tal:condition="view/target/codehosting_usage/enumvalue:UNKNOWN"
> +      name="robots" content="noindex,nofollow" />
> +  </tal:head-epilogue>
> +</head>
> +
> +<body>
> +  <metal:side fill-slot="side" tal:define="context_menu context/menu:context">
> +    <div id="branch-portlet"
> +         tal:condition="not: view/target/codehosting_usage/enumvalue:UNKNOWN">
> +      <div id="privacy"
> +           tal:define="private_class python: 'private' if view.default_information_type_is_private else 'public'"
> +           tal:attributes="class string:first portlet ${private_class}">
> +        <span tal:condition="not: view/default_information_type"
> +           id="privacy-text">
> +          You can't create new repositories for
> +          <tal:name replace="context/displayname"/>.
> +          <tal:sharing-link condition="context/required:launchpad.Edit">
> +          <br/>This can be fixed by changing the branch sharing policy on the
> +          <a tal:attributes="href string:${view/target/fmt:url:mainsite}/+sharing">sharing page</a>.
> +          </tal:sharing-link>
> +        </span>
> +
> +        <span tal:condition="view/default_information_type"
> +           tal:attributes="class string:sprite ${private_class}"
> +           id="privacy-text">
> +          New repositories for <tal:name replace="view/target/displayname"/> are
> +          <strong tal:content="view/default_information_type_title" />.
> +        </span>
> +      </div>
> +    </div>
> +  </metal:side>
> +  <metal:main fill-slot="main">
> +    <tal:default-repository
> +        condition="view/default_git_repository"
> +        define="repository view/default_git_repository">

Perhaps show repository/description here too, like lib/lp/code/templates/gitrepository-index.pt.

> +      <div class="yui-g first">
> +        <div id="default-repository-management" class="top-portlet">
> +          <tal:repository-management
> +            replace="structure repository/@@++repository-management" />
> +        </div>
> +      </div>
> +
> +      <div class="yui-g">
> +        <div id="default-repository-branches" class="portlet"
> +            tal:define="branches view/default_git_repository_branches">
> +          <h2>Branches</h2>
> +          <tal:default-repository-branches
> +            replace="structure branches/@@+ref-listing" />
> +        </div>
> +      </div>
> +    </tal:default-repository>
> +
> +    <div class="yui-g">
> +      <div id="other-repositories" class="portlet">
> +        <h2>Other repositories</h2>
> +        <tal:other-repos
> +          content="structure view/repos/@@+gitrepository-listing" />
> +      </div>
> +    </div>
> +  </metal:main>
> +</body>
> +</html>
> 
> === added file 'lib/lp/code/templates/gitrepository-listing.pt'
> --- lib/lp/code/templates/gitrepository-listing.pt	1970-01-01 00:00:00 +0000
> +++ lib/lp/code/templates/gitrepository-listing.pt	2015-06-04 09:15:20 +0000
> @@ -0,0 +1,30 @@
> +<div id="gitrepositories-table-listing"
> +  xmlns:tal="http://xml.zope.org/namespaces/tal";
> +  xmlns:metal="http://xml.zope.org/namespaces/metal";
> +  >
> +  <tal:needs-batch condition="context/has_multiple_pages">
> +    <div id="branch-batch-links">
> +      <tal:navigation replace="structure context/@@+navigation-links-upper" />
> +    </div>
> +  </tal:needs-batch>
> +  <table class="listing">
> +    <thead>
> +      <tr>
> +        <th>Name</th>
> +        <th>Last Modified</th>
> +      </tr>
> +    </thead>
> +    <tbody>
> +      <tr tal:repeat="repo context/currentBatch">
> +        <td>
> +          <a tal:content="repo/display_name"
> +              tal:attributes="href repo/fmt:url">lp:foo</a>
> +        </td>
> +        <td tal:content="repo/date_last_modified/fmt:approximatedate">
> +          2 hours ago
> +        </td>
> +      </tr>
> +    </tbody>
> +  </table>
> +  <tal:navigation replace="structure context/@@+navigation-links-lower" />
> +</div>
> 
> === modified file 'lib/lp/code/templates/product-branch-summary.pt'
> --- lib/lp/code/templates/product-branch-summary.pt	2015-05-01 13:20:09 +0000
> +++ lib/lp/code/templates/product-branch-summary.pt	2015-06-04 09:15:20 +0000
> @@ -57,7 +57,7 @@
>    </div>
>  
>    <tal:no-branches
> -      condition="python: not view.branch_count and not view.has_default_git_repository">
> +      condition="not: view/branch_count">
>      There are no branches for <tal:project-name replace="context/displayname"/>
>      in Launchpad.
>      <tal:can-configure condition="view/can_configure_branches">
> @@ -79,23 +79,6 @@
>      </tal:can-configure>
>    </tal:no-branches>
>  
> -  <div tal:condition="view/has_default_git_repository"
> -       style="margin: 1em 0"
> -       tal:define="repository view/default_git_repository">
> -    You can
> -    <a tal:attributes="href repository/getCodebrowseUrl">browse the
> -      source code</a>
> -    for the default Git repository or get a copy of the repository using
> -    the command:<br/>
> -    <tt class="command">git clone
> -    <tal:logged-in condition="view/user">
> -      <tal:git-ssh-url replace="repository/ssh_url"/>
> -    </tal:logged-in>
> -    <tal:not-logged-in condition="not: view/user">
> -      <tal:git-anon-url replace="repository/anon_url"/>
> -    </tal:not-logged-in></tt>
> -  </div>
> -
>    <tal:has-branches condition="view/branch_count">
>      <div tal:condition="view/has_development_focus_branch"
>           style="margin: 1em 0"
> 
> === modified file 'lib/lp/code/templates/product-branches.pt'
> --- lib/lp/code/templates/product-branches.pt	2015-06-01 08:43:09 +0000
> +++ lib/lp/code/templates/product-branches.pt	2015-06-04 09:15:20 +0000
> @@ -60,16 +60,6 @@
>        condition="not: view/context/codehosting_usage/enumvalue:UNKNOWN"
>        replace="structure context/@@+portlet-product-branchstatistics" />
>  
> -    <tal:has-default-git-repository condition="view/has_default_git_repository">
> -      <div id="default-repository-branches" class="portlet"
> -           tal:define="repository view/default_git_repository;
> -                       branches view/default_git_repository_branches">
> -        <h2>Git branches</h2>
> -        <tal:default-repository-branches
> -          replace="structure branches/@@+ref-listing" />
> -      </div>
> -    </tal:has-default-git-repository>
> -
>      <tal:has-branches condition="view/branch_count"
>                        define="branches view/branches">
>        <div class="portlet">

Is it worth removing the "Bazaar branches" heading and the surrounding portlet that I added here when I put the temporary hack in place?  It might look a bit odd now that the page will only show Bazaar branches again.

> 


-- 
https://code.launchpad.net/~wgrant/launchpad/gitlisting/+merge/261066
Your team Launchpad code reviewers is subscribed to branch lp:launchpad.


References