← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~twom/launchpad/git-active-review-on-more-git-repo into lp:launchpad

 

Tom Wardill has proposed merging lp:~twom/launchpad/git-active-review-on-more-git-repo into lp:launchpad.

Commit message:
Add available review targets and proposals to the git repository overview page

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~twom/launchpad/git-active-review-on-more-git-repo/+merge/353884
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~twom/launchpad/git-active-review-on-more-git-repo into lp:launchpad.
=== modified file 'lib/lp/_schema_circular_imports.py'
--- lib/lp/_schema_circular_imports.py	2018-05-01 16:08:03 +0000
+++ lib/lp/_schema_circular_imports.py	2018-08-28 15:42:29 +0000
@@ -521,6 +521,8 @@
     IGitRepository, '_api_landing_candidates', IBranchMergeProposal)
 patch_collection_property(
     IGitRepository, 'dependent_landings', IBranchMergeProposal)
+patch_collection_return_type(
+    IGitRepository, 'getMergeProposals', IBranchMergeProposal)
 
 # ILiveFSFile
 patch_reference_property(ILiveFSFile, 'livefsbuild', ILiveFSBuild)

=== modified file 'lib/lp/code/browser/configure.zcml'
--- lib/lp/code/browser/configure.zcml	2018-08-20 23:33:01 +0000
+++ lib/lp/code/browser/configure.zcml	2018-08-28 15:42:29 +0000
@@ -819,6 +819,9 @@
             name="++repository-recipes"
             template="../templates/gitrepository-recipes.pt"/>
         <browser:page
+            name="++ref-pending-merges"
+            template="../templates/gitrepository-pending-merges.pt"/>
+        <browser:page
             name="++repository-import-details"
             template="../templates/import-details.pt"/>
     </browser:pages>
@@ -902,6 +905,13 @@
         permission="launchpad.AnyAllowedPerson"
         name="+try-again"
         template="../templates/inline-form-only-buttons.pt"/>
+    <browser:page
+        for="lp.code.interfaces.gitrepository.IGitRepository"
+        class="lp.code.browser.branchmergeproposallisting.BranchActiveReviewsView"
+        permission="zope.Public"
+        name="+activereviews"
+        template="../templates/active-reviews.pt"/>
+
     <adapter
         provides="lp.services.webapp.interfaces.IBreadcrumb"
         for="lp.code.interfaces.gitrepository.IGitRepository"

=== modified file 'lib/lp/code/browser/gitrepository.py'
--- lib/lp/code/browser/gitrepository.py	2018-08-24 16:52:27 +0000
+++ lib/lp/code/browser/gitrepository.py	2018-08-28 15:42:29 +0000
@@ -57,6 +57,9 @@
 from lp.app.vocabularies import InformationTypeVocabulary
 from lp.app.widgets.itemswidgets import LaunchpadRadioWidgetWithDescription
 from lp.code.browser.branch import CodeEditOwnerMixin
+from lp.code.browser.branchmergeproposal import (
+    latest_proposals_for_each_branch,
+    )
 from lp.code.browser.codeimport import CodeImportTargetMixin
 from lp.code.browser.sourcepackagerecipelisting import HasRecipesMenuMixin
 from lp.code.browser.widgets.gitrepositorytarget import (
@@ -369,6 +372,44 @@
         """Is this an imported repository?"""
         return self.context.repository_type == GitRepositoryType.IMPORTED
 
+    @property
+    def show_merge_links(self):
+        return True
+
+    @cachedproperty
+    def landing_candidates(self):
+        candidates = self.context.getPrecachedLandingCandidates(self.user)
+        return [proposal for proposal in candidates
+                if check_permission("launchpad.View", proposal)]
+
+    def _getBranchCountText(self, count):
+        """Help to show user friendly text."""
+        if count == 0:
+            return 'No branches'
+        elif count == 1:
+            return '1 branch'
+        else:
+            return '%s branches' % coun
+
+    @cachedproperty
+    def landing_candidate_count_text(self):
+        return self._getBranchCountText(len(self.landing_candidates))
+
+    @cachedproperty
+    def dependent_landings(self):
+        return [proposal for proposal in self.context.dependent_landings
+                if check_permission("launchpad.View", proposal)]
+
+    @cachedproperty
+    def dependent_landing_count_text(self):
+        return self._getBranchCountText(len(self.dependent_landings))
+
+    @property
+    def landing_targets(self):
+        """Return a filtered list of landing targets."""
+        targets = self.context.getPrecachedLandingTargets(self.user)
+        return latest_proposals_for_each_branch(targets)
+
 
 class GitRepositoryEditFormView(LaunchpadEditFormView):
     """Base class for forms that edit a Git repository."""

=== modified file 'lib/lp/code/browser/tests/test_gitrepository.py'
--- lib/lp/code/browser/tests/test_gitrepository.py	2018-08-24 16:52:27 +0000
+++ lib/lp/code/browser/tests/test_gitrepository.py	2018-08-28 15:42:29 +0000
@@ -24,10 +24,10 @@
 from lp.app.enums import InformationType
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
 from lp.app.interfaces.services import IService
-from lp.code.enums import GitRepositoryType
+from lp.code.enums import BranchMergeProposalStatus, GitRepositoryType
 from lp.code.interfaces.revision import IRevisionSet
 from lp.code.tests.helpers import GitHostingFixture
-from lp.registry.enums import BranchSharingPolicy
+from lp.registry.enums import BranchSharingPolicy, VCSType
 from lp.registry.interfaces.accesspolicy import IAccessPolicySource
 from lp.registry.interfaces.person import PersonVisibility
 from lp.services.beautifulsoup import BeautifulSoup
@@ -246,6 +246,39 @@
         browser = self.getUserBrowser(url, user=user)
         self.assertIn(project_name, browser.contents)
 
+    def test_view_with_active_reviews(self):
+        repository = self.factory.makeGitRepository()
+        git_refs = self.factory.makeGitRefs(
+            repository,
+            paths=["refs/heads/master", "refs/heads/1.0", "refs/tags/1.1"])
+        self.factory.makeBranchMergeProposalForGit(
+            target_ref=git_refs[0],
+            set_state=BranchMergeProposalStatus.NEEDS_REVIEW)
+        with person_logged_in(repository.owner):
+            browser = self.getViewBrowser(repository)
+            self.assertIsNotNone(
+                find_tag_by_id(browser.contents, 'landing-candidates'))
+
+    def test_view_with_landing_targets(self):
+        product = self.factory.makeProduct(name="foo", vcs=VCSType.GIT)
+        target_repository = self.factory.makeGitRepository(target=product)
+        source_repository = self.factory.makeGitRepository(target=product)
+        target_git_refs = self.factory.makeGitRefs(
+            target_repository,
+            paths=["refs/heads/master", "refs/heads/1.0", "refs/tags/1.1"])
+        source_git_refs = self.factory.makeGitRefs(
+            source_repository,
+            paths=["refs/heads/master"])
+        self.factory.makeBranchMergeProposalForGit(
+            target_ref=target_git_refs[0],
+            source_ref=source_git_refs[0],
+            set_state=BranchMergeProposalStatus.NEEDS_REVIEW)
+        with person_logged_in(target_repository.owner):
+            browser = self.getViewBrowser(
+                source_repository, user=source_repository.owner)
+            self.assertIsNotNone(
+                find_tag_by_id(browser.contents, 'landing-targets'))
+
 
 class TestGitRepositoryViewPrivateArtifacts(BrowserTestCase):
     """Tests that Git repositories with private team artifacts can be viewed.

=== modified file 'lib/lp/code/interfaces/gitrepository.py'
--- lib/lp/code/interfaces/gitrepository.py	2017-11-06 09:32:45 +0000
+++ lib/lp/code/interfaces/gitrepository.py	2018-08-28 15:42:29 +0000
@@ -58,6 +58,7 @@
 from lp.app.enums import InformationType
 from lp.app.validators import LaunchpadValidationError
 from lp.code.enums import (
+    BranchMergeProposalStatus,
     BranchSubscriptionDiffSize,
     BranchSubscriptionNotificationLevel,
     CodeReviewNotificationLevel,
@@ -531,6 +532,21 @@
         Source and prerequisite repositories are preloaded.
         """
 
+    @operation_parameters(
+        status=List(
+            title=_("A list of merge proposal statuses to filter by."),
+            value_type=Choice(vocabulary=BranchMergeProposalStatus)),
+        merged_revision_ids=List(TextLine(
+            title=_('The target revision ID of the merge.'))))
+    @call_with(visible_by_user=REQUEST_USER)
+    # Really IBranchMergeProposal, patched in _schema_circular_imports.py.
+    @operation_returns_collection_of(Interface)
+    @export_read_operation()
+    @operation_for_version("devel")
+    def getMergeProposals(status=None, visible_by_user=None,
+                          merged_revision_ids=None, eager_load=False):
+        """Return matching BranchMergeProposals."""
+
     def getMergeProposalByID(id):
         """Return this repository's merge proposal with this id, or None."""
 

=== modified file 'lib/lp/code/model/gitrepository.py'
--- lib/lp/code/model/gitrepository.py	2018-07-24 11:57:33 +0000
+++ lib/lp/code/model/gitrepository.py	2018-08-28 15:42:29 +0000
@@ -942,6 +942,21 @@
             Not(BranchMergeProposal.queue_status.is_in(
                 BRANCH_MERGE_PROPOSAL_FINAL_STATES)))
 
+    def getMergeProposals(self, status=None, visible_by_user=None,
+                          merged_revision_ids=None, eager_load=False):
+        """See `IGitRef`."""
+        if not status:
+            status = (
+                BranchMergeProposalStatus.CODE_APPROVED,
+                BranchMergeProposalStatus.NEEDS_REVIEW,
+                BranchMergeProposalStatus.WORK_IN_PROGRESS)
+
+        collection = getUtility(IAllGitRepositories).visibleByUser(
+            visible_by_user)
+        return collection.getMergeProposals(
+            status, target_repository=self,
+            merged_revision_ids=merged_revision_ids, eager_load=eager_load)
+
     def getMergeProposalByID(self, id):
         """See `IGitRepository`."""
         return self.landing_targets.find(BranchMergeProposal.id == id).one()

=== modified file 'lib/lp/code/templates/gitrepository-index.pt'
--- lib/lp/code/templates/gitrepository-index.pt	2018-01-26 12:01:02 +0000
+++ lib/lp/code/templates/gitrepository-index.pt	2018-08-28 15:42:29 +0000
@@ -44,6 +44,13 @@
     </div>
   </div>
 
+  <div class="yui-g first">
+    <div id="repository-relations" class="portlet">
+      <tal:ref-pending-merges
+           replace="structure context/@@++ref-pending-merges" />
+    </div>
+  </div>
+
   <div class="yui-g">
     <div id="repository-relations" class="portlet">
       <tal:repository-recipes

=== added file 'lib/lp/code/templates/gitrepository-pending-merges.pt'
--- lib/lp/code/templates/gitrepository-pending-merges.pt	1970-01-01 00:00:00 +0000
+++ lib/lp/code/templates/gitrepository-pending-merges.pt	2018-08-28 15:42:29 +0000
@@ -0,0 +1,35 @@
+<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";
+  tal:define="
+      context_menu view/context/menu:context;
+      features request/features"
+  tal:condition="view/show_merge_links">
+
+  <h3>Branch merges</h3>
+  <div id="merge-links"
+       class="actions">
+    <div id="merge-summary">
+
+      <div id="landing-candidates"
+           tal:condition="view/landing_candidates">
+        <img src="/@@/merge-proposal-icon" />
+        <a href="+activereviews" tal:content="structure view/landing_candidate_count_text">
+          1 branch
+        </a>
+        proposed for merging into this repository.
+
+      </div>
+
+      <div id="landing-targets" tal:condition="view/landing_targets">
+        <tal:landing-candidates repeat="mergeproposal view/landing_targets">
+          <tal:merge-fragment
+              tal:replace="structure mergeproposal/@@+summary-fragment"/>
+        </tal:landing-candidates>
+      </div>
+
+    </div>
+  </div>
+
+</div>


Follow ups