Merge ~pappacena/launchpad:allow-mp-between-personal-repos into launchpad:master

Proposed by Thiago F. Pappacena
Status: Merged
Approved by: Thiago F. Pappacena
Approved revision: bbca8aaa77eec65e94f9655d7259379828225a91
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~pappacena/launchpad:allow-mp-between-personal-repos
Merge into: launchpad:master
Diff against target: 163 lines (+60/-12)
5 files modified
lib/lp/code/browser/gitref.py (+21/-1)
lib/lp/code/browser/tests/test_gitref.py (+12/-1)
lib/lp/code/model/gitnamespace.py (+1/-1)
lib/lp/code/model/tests/test_gitnamespace.py (+19/-9)
lib/lp/code/templates/gitref-pending-merges.pt (+7/-0)
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+387760@code.launchpad.net

Commit message

LP: #1888295 Allowing users to propose merge between personal git repositories

We are also adding a note on the UI, below the "create MP" button, to warn users about restrictions that may apply to the MP creation, in order to avoid misunderstanding and reduce support requests.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote :

Thanks! A few minor nits, but this seems mostly good.

I guess this MP should be explicitly linked to bug 1888295. (Ideally, do this in the commit message as described in https://help.launchpad.net/Code/Git#Linking_to_bugs, but failing that you can do it manually in the MP web UI.)

review: Approve
bbca8aa... by Thiago F. Pappacena

Coding style and better guard on merge proposal creation notes

Revision history for this message
Thiago F. Pappacena (pappacena) wrote :

Linked to the LP bug, and pushed the requested changes. I'll top-approve this.

Revision history for this message
Colin Watson (cjwatson) :
Revision history for this message
Thiago F. Pappacena (pappacena) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/lib/lp/code/browser/gitref.py b/lib/lp/code/browser/gitref.py
index 25021bc..a945fa0 100644
--- a/lib/lp/code/browser/gitref.py
+++ b/lib/lp/code/browser/gitref.py
@@ -1,4 +1,4 @@
1# Copyright 2015-2018 Canonical Ltd. This software is licensed under the1# Copyright 2015-2020 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Git reference views."""4"""Git reference views."""
@@ -47,6 +47,7 @@ from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal
47from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference47from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference
48from lp.code.interfaces.gitref import IGitRef48from lp.code.interfaces.gitref import IGitRef
49from lp.code.interfaces.gitrepository import IGitRepositorySet49from lp.code.interfaces.gitrepository import IGitRepositorySet
50from lp.registry.interfaces.person import IPerson
50from lp.services.helpers import english_list51from lp.services.helpers import english_list
51from lp.services.propertycache import cachedproperty52from lp.services.propertycache import cachedproperty
52from lp.services.scripts import log53from lp.services.scripts import log
@@ -135,6 +136,16 @@ class GitRefView(LaunchpadView, HasSnapsViewMixin):
135 """136 """
136 if not self.context.namespace.supports_merge_proposals:137 if not self.context.namespace.supports_merge_proposals:
137 return False138 return False
139 if IPerson.providedBy(self.context.namespace.target):
140 # XXX pappacena 2020-07-21: For personal repositories, we enable
141 # the link even if the user will only be allowed to merge
142 # their personal repositories' branch into another personal repo
143 # with the same name. But checking if there is another
144 # repository with the same name might be a bit expensive query for
145 # such a simple operation. Currently, we only have db index for
146 # repo's name when searching together with owner.
147 return True
148
138 repositories = self.context.namespace.collection.getRepositories()149 repositories = self.context.namespace.collection.getRepositories()
139 if repositories.count() > 1:150 if repositories.count() > 1:
140 return True151 return True
@@ -143,6 +154,15 @@ class GitRefView(LaunchpadView, HasSnapsViewMixin):
143 return False154 return False
144 return repository.refs.count() > 1155 return repository.refs.count() > 1
145156
157 @property
158 def propose_merge_notes(self):
159 messages = []
160 if IPerson.providedBy(self.context.namespace.target):
161 messages.append(
162 "You will only be able to propose a merge to another personal "
163 "repository with the same name.")
164 return messages
165
146 @cachedproperty166 @cachedproperty
147 def landing_targets(self):167 def landing_targets(self):
148 """Return a filtered list of landing targets."""168 """Return a filtered list of landing targets."""
diff --git a/lib/lp/code/browser/tests/test_gitref.py b/lib/lp/code/browser/tests/test_gitref.py
index 5712d0a..0268ca4 100644
--- a/lib/lp/code/browser/tests/test_gitref.py
+++ b/lib/lp/code/browser/tests/test_gitref.py
@@ -1,4 +1,4 @@
1# Copyright 2015-2018 Canonical Ltd. This software is licensed under the1# Copyright 2015-2020 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Unit tests for GitRefView."""4"""Unit tests for GitRefView."""
@@ -275,6 +275,17 @@ class TestGitRefView(BrowserTestCase):
275 self.assertThat(275 self.assertThat(
276 contents, Not(soupmatchers.HTMLContains(MissingCommitsNote())))276 contents, Not(soupmatchers.HTMLContains(MissingCommitsNote())))
277277
278 def test_show_merge_link_for_personal_repo(self):
279 person = self.factory.makePerson()
280 repo = self.factory.makeGitRepository(
281 owner=person, target=person)
282 [ref] = self.factory.makeGitRefs(
283 repository=repo, paths=["refs/heads/branch"])
284
285 view = create_initialized_view(ref, "+index")
286 self.assertTrue(view.show_merge_links)
287 self.assertEqual(1, len(view.propose_merge_notes))
288
278 def _test_all_commits_link(self, branch_name, encoded_branch_name=None):289 def _test_all_commits_link(self, branch_name, encoded_branch_name=None):
279 if encoded_branch_name is None:290 if encoded_branch_name is None:
280 encoded_branch_name = branch_name291 encoded_branch_name = branch_name
diff --git a/lib/lp/code/model/gitnamespace.py b/lib/lp/code/model/gitnamespace.py
index 2a358f6..8a08a97 100644
--- a/lib/lp/code/model/gitnamespace.py
+++ b/lib/lp/code/model/gitnamespace.py
@@ -330,7 +330,7 @@ class PersonalGitNamespace(_BaseGitNamespace):
330 if this.namespace != self:330 if this.namespace != self:
331 raise AssertionError(331 raise AssertionError(
332 "Namespace of %s is not %s." % (this.unique_name, self.name))332 "Namespace of %s is not %s." % (this.unique_name, self.name))
333 return this == other333 return this.name == other.name
334334
335 @property335 @property
336 def collection(self):336 def collection(self):
diff --git a/lib/lp/code/model/tests/test_gitnamespace.py b/lib/lp/code/model/tests/test_gitnamespace.py
index 5fed799..f873782 100644
--- a/lib/lp/code/model/tests/test_gitnamespace.py
+++ b/lib/lp/code/model/tests/test_gitnamespace.py
@@ -1,4 +1,4 @@
1# Copyright 2015-2019 Canonical Ltd. This software is licensed under the1# Copyright 2015-2020 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Tests for `IGitNamespace` implementations."""4"""Tests for `IGitNamespace` implementations."""
@@ -291,24 +291,34 @@ class TestPersonalGitNamespace(TestCaseWithFactory, NamespaceMixin):
291 repository.namespace.areRepositoriesMergeable(291 repository.namespace.areRepositoriesMergeable(
292 repository, repository))292 repository, repository))
293293
294 def test_areRepositoriesMergeable_same_namespace(self):294 def test_areRepositoriesMergeable_different_namespaces(self):
295 # A personal repository is not mergeable if the origin namespace is
296 # not the same as the namespacing checking the mergeability.
297 owner = self.factory.makePerson()
298 this = self.factory.makeGitRepository(owner=owner, target=owner)
299 other = self.factory.makeGitRepository(owner=owner, target=owner)
300 self.assertFalse(other.namespace.areRepositoriesMergeable(this, other))
301
302 def test_areRepositoriesMergeable_different_name(self):
295 # A personal repository is not mergeable into another personal303 # A personal repository is not mergeable into another personal
296 # repository, even if they are in the same namespace.304 # repository if they do not have the same name.
297 owner = self.factory.makePerson()305 owner = self.factory.makePerson()
298 this = self.factory.makeGitRepository(owner=owner, target=owner)306 this = self.factory.makeGitRepository(owner=owner, target=owner)
299 other = self.factory.makeGitRepository(owner=owner, target=owner)307 other = self.factory.makeGitRepository(owner=owner, target=owner)
300 self.assertFalse(this.namespace.areRepositoriesMergeable(this, other))308 self.assertFalse(this.namespace.areRepositoriesMergeable(this, other))
301309
302 def test_areRepositoriesMergeable_different_namespace(self):310 def test_areRepositoriesMergeable_same_name(self):
303 # A personal repository is not mergeable into another personal311 # A personal repository is mergeable into another personal
304 # repository with a different namespace.312 # repository if they have the same name, even if they target different
313 # people.
305 this_owner = self.factory.makePerson()314 this_owner = self.factory.makePerson()
315 repo_name = "my-personal-repository"
306 this = self.factory.makeGitRepository(316 this = self.factory.makeGitRepository(
307 owner=this_owner, target=this_owner)317 owner=this_owner, target=this_owner, name=repo_name)
308 other_owner = self.factory.makePerson()318 other_owner = self.factory.makePerson()
309 other = self.factory.makeGitRepository(319 other = self.factory.makeGitRepository(
310 owner=other_owner, target=other_owner)320 owner=other_owner, target=other_owner, name=repo_name)
311 self.assertFalse(this.namespace.areRepositoriesMergeable(this, other))321 self.assertTrue(this.namespace.areRepositoriesMergeable(this, other))
312322
313 def test_areRepositoriesMergeable_project(self):323 def test_areRepositoriesMergeable_project(self):
314 # Project repositories are not mergeable into personal repositories.324 # Project repositories are not mergeable into personal repositories.
diff --git a/lib/lp/code/templates/gitref-pending-merges.pt b/lib/lp/code/templates/gitref-pending-merges.pt
index 9361354..5d41ce8 100644
--- a/lib/lp/code/templates/gitref-pending-merges.pt
+++ b/lib/lp/code/templates/gitref-pending-merges.pt
@@ -43,6 +43,13 @@
43 tal:condition="link/enabled"43 tal:condition="link/enabled"
44 tal:replace="structure link/render"44 tal:replace="structure link/render"
45 />45 />
46 <div tal:condition="python: view.propose_merge_notes and context_menu['register_merge'].enabled">
47 <ul>
48 <li tal:repeat="message view/propose_merge_notes" class="registered">
49 <spam tal:replace="message" />
50 </li>
51 </ul>
52 </div>
46 </div>53 </div>
4754
48</div>55</div>