Merge lp:~cjwatson/launchpad/livefs-personmerge into lp:launchpad

Proposed by Colin Watson
Status: Merged
Approved by: William Grant
Approved revision: no longer in the source branch.
Merged at revision: 17058
Proposed branch: lp:~cjwatson/launchpad/livefs-personmerge
Merge into: lp:launchpad
Prerequisite: lp:~cjwatson/launchpad/livefs
Diff against target: 182 lines (+82/-5)
5 files modified
lib/lp/registry/personmerge.py (+23/-4)
lib/lp/registry/tests/test_personmerge.py (+39/-1)
lib/lp/soyuz/interfaces/livefs.py (+3/-0)
lib/lp/soyuz/model/livefs.py (+4/-0)
lib/lp/soyuz/tests/test_livefs.py (+13/-0)
To merge this branch: bzr merge lp:~cjwatson/launchpad/livefs-personmerge
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+223654@code.launchpad.net

Commit message

Handle LiveFS.owner during person merging.

Description of the change

Handle LiveFS.owner during person merging. This reverts the temporary hack from https://code.launchpad.net/~cjwatson/launchpad/livefs-personmerge-whitelist/+merge/223537.

The main thing I was unsure about here was the manual flush I had to do at the end of _mergeLiveFS. It makes sense that I should have to flush database updates, given that merge_people calls store.invalidate() not long afterwards, and my tests failed when I didn't do that; but how come _mergeSourcePackageRecipes apparently doesn't need to do the same?

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/registry/personmerge.py'
--- lib/lp/registry/personmerge.py 2014-06-18 10:52:12 +0000
+++ lib/lp/registry/personmerge.py 2014-06-18 22:20:53 +0000
@@ -1,4 +1,4 @@
1# Copyright 2009-2013 Canonical Ltd. This software is licensed under the1# Copyright 2009-2014 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"""Person/team merger implementation."""4"""Person/team merger implementation."""
@@ -34,6 +34,7 @@
34from lp.services.mail.helpers import get_email_template34from lp.services.mail.helpers import get_email_template
35from lp.soyuz.enums import ArchiveStatus35from lp.soyuz.enums import ArchiveStatus
36from lp.soyuz.interfaces.archive import IArchiveSet36from lp.soyuz.interfaces.archive import IArchiveSet
37from lp.soyuz.interfaces.livefs import ILiveFSSet
3738
3839
39def _merge_person_decoration(to_person, from_person, skip,40def _merge_person_decoration(to_person, from_person, skip,
@@ -577,6 +578,24 @@
577 ''' % params)578 ''' % params)
578579
579580
581def _mergeLiveFS(cur, from_person, to_person):
582 # This shouldn't use removeSecurityProxy.
583 livefses = getUtility(ILiveFSSet).getByPerson(from_person)
584 existing_names = [
585 l.name for l in getUtility(ILiveFSSet).getByPerson(to_person)]
586 for livefs in livefses:
587 new_name = livefs.name
588 count = 1
589 while new_name in existing_names:
590 new_name = '%s-%s' % (livefs.name, count)
591 count += 1
592 naked_livefs = removeSecurityProxy(livefs)
593 naked_livefs.owner = to_person
594 naked_livefs.name = new_name
595 if not livefses.is_empty():
596 IStore(livefses[0]).flush()
597
598
580def _purgeUnmergableTeamArtifacts(from_team, to_team, reviewer):599def _purgeUnmergableTeamArtifacts(from_team, to_team, reviewer):
581 """Purge team artifacts that cannot be merged, but can be removed."""600 """Purge team artifacts that cannot be merged, but can be removed."""
582 # A team cannot have more than one mailing list.601 # A team cannot have more than one mailing list.
@@ -672,9 +691,6 @@
672 ('bugsummaryjournal', 'viewed_by'),691 ('bugsummaryjournal', 'viewed_by'),
673 ('latestpersonsourcepackagereleasecache', 'creator'),692 ('latestpersonsourcepackagereleasecache', 'creator'),
674 ('latestpersonsourcepackagereleasecache', 'maintainer'),693 ('latestpersonsourcepackagereleasecache', 'maintainer'),
675 # This needs handling before we deploy the livefs code, but can be
676 # ignored for the purpose of deploying the database tables.
677 ('livefs', 'owner'),
678 ]694 ]
679695
680 references = list(postgresql.listReferences(cur, 'person', 'id'))696 references = list(postgresql.listReferences(cur, 'person', 'id'))
@@ -799,6 +815,9 @@
799 _mergeCodeReviewInlineCommentDraft(cur, from_id, to_id)815 _mergeCodeReviewInlineCommentDraft(cur, from_id, to_id)
800 skip.append(('codereviewinlinecommentdraft', 'person'))816 skip.append(('codereviewinlinecommentdraft', 'person'))
801817
818 _mergeLiveFS(cur, from_person, to_person)
819 skip.append(('livefs', 'owner'))
820
802 # Sanity check. If we have a reference that participates in a821 # Sanity check. If we have a reference that participates in a
803 # UNIQUE index, it must have already been handled by this point.822 # UNIQUE index, it must have already been handled by this point.
804 # We can tell this by looking at the skip list.823 # We can tell this by looking at the skip list.
805824
=== modified file 'lib/lp/registry/tests/test_personmerge.py'
--- lib/lp/registry/tests/test_personmerge.py 2013-06-21 02:39:33 +0000
+++ lib/lp/registry/tests/test_personmerge.py 2014-06-18 22:20:53 +0000
@@ -1,4 +1,4 @@
1# Copyright 2009-2013 Canonical Ltd. This software is licensed under the1# Copyright 2009-2014 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 merge_people."""4"""Tests for merge_people."""
@@ -34,11 +34,16 @@
34from lp.registry.tests.test_person import KarmaTestMixin34from lp.registry.tests.test_person import KarmaTestMixin
35from lp.services.config import config35from lp.services.config import config
36from lp.services.database.sqlbase import cursor36from lp.services.database.sqlbase import cursor
37from lp.services.features.testing import FeatureFixture
37from lp.services.identity.interfaces.emailaddress import (38from lp.services.identity.interfaces.emailaddress import (
38 EmailAddressStatus,39 EmailAddressStatus,
39 IEmailAddressSet,40 IEmailAddressSet,
40 )41 )
41from lp.soyuz.enums import ArchiveStatus42from lp.soyuz.enums import ArchiveStatus
43from lp.soyuz.interfaces.livefs import (
44 ILiveFSSet,
45 LIVEFS_FEATURE_FLAG,
46 )
42from lp.testing import (47from lp.testing import (
43 celebrity_logged_in,48 celebrity_logged_in,
44 login_person,49 login_person,
@@ -488,6 +493,39 @@
488 self.assertEqual(0, inviting_team.invited_member_count)493 self.assertEqual(0, inviting_team.invited_member_count)
489 self.assertEqual(0, proposed_team.proposed_member_count)494 self.assertEqual(0, proposed_team.proposed_member_count)
490495
496 def test_merge_moves_livefses(self):
497 # When person/teams are merged, live filesystems owned by the from
498 # person are moved.
499 self.useFixture(FeatureFixture({LIVEFS_FEATURE_FLAG: u"on"}))
500 duplicate = self.factory.makePerson()
501 mergee = self.factory.makePerson()
502 self.factory.makeLiveFS(registrant=duplicate, owner=duplicate)
503 self._do_premerge(duplicate, mergee)
504 login_person(mergee)
505 duplicate, mergee = self._do_merge(duplicate, mergee)
506 self.assertEqual(1, getUtility(ILiveFSSet).getByPerson(mergee).count())
507
508 def test_merge_with_duplicated_livefses(self):
509 # If both the from and to people have live filesystems with the same
510 # name, merging renames the duplicate from the from person's side.
511 self.useFixture(FeatureFixture({LIVEFS_FEATURE_FLAG: u"on"}))
512 duplicate = self.factory.makePerson()
513 mergee = self.factory.makePerson()
514 self.factory.makeLiveFS(
515 registrant=duplicate, owner=duplicate, name=u'foo',
516 metadata={'project': 'FROM'})
517 self.factory.makeLiveFS(
518 registrant=mergee, owner=mergee, name=u'foo',
519 metadata={'project': 'TO'})
520 self._do_premerge(duplicate, mergee)
521 login_person(mergee)
522 duplicate, mergee = self._do_merge(duplicate, mergee)
523 livefses = getUtility(ILiveFSSet).getByPerson(mergee)
524 self.assertEqual(2, livefses.count())
525 project_names = [l.metadata['project'] for l in livefses]
526 self.assertEqual(['TO', 'FROM'], project_names)
527 self.assertEqual(u'foo-1', livefses[1].name)
528
491529
492class TestMergeMailingListSubscriptions(TestCaseWithFactory):530class TestMergeMailingListSubscriptions(TestCaseWithFactory):
493531
494532
=== modified file 'lib/lp/soyuz/interfaces/livefs.py'
--- lib/lp/soyuz/interfaces/livefs.py 2014-06-18 22:20:52 +0000
+++ lib/lp/soyuz/interfaces/livefs.py 2014-06-18 22:20:53 +0000
@@ -280,6 +280,9 @@
280 def interpret(owner_name, distribution_name, distro_series_name, name):280 def interpret(owner_name, distribution_name, distro_series_name, name):
281 """Like `getByName`, but takes names of objects."""281 """Like `getByName`, but takes names of objects."""
282282
283 def getByPerson(owner):
284 """Return all live filesystems with the given `owner`."""
285
283 @collection_default_content()286 @collection_default_content()
284 def getAll():287 def getAll():
285 """Return all of the live filesystems in Launchpad.288 """Return all of the live filesystems in Launchpad.
286289
=== modified file 'lib/lp/soyuz/model/livefs.py'
--- lib/lp/soyuz/model/livefs.py 2014-06-18 22:20:52 +0000
+++ lib/lp/soyuz/model/livefs.py 2014-06-18 22:20:53 +0000
@@ -283,6 +283,10 @@
283 getUtility(IDistroSeriesSet).queryByName, distribution)283 getUtility(IDistroSeriesSet).queryByName, distribution)
284 return self.getByName(owner, distro_series, name)284 return self.getByName(owner, distro_series, name)
285285
286 def getByPerson(self, owner):
287 """See `ILiveFSSet`."""
288 return IStore(LiveFS).find(LiveFS, LiveFS.owner == owner)
289
286 def getAll(self):290 def getAll(self):
287 """See `ILiveFSSet`."""291 """See `ILiveFSSet`."""
288 user = getUtility(ILaunchBag).user292 user = getUtility(ILaunchBag).user
289293
=== modified file 'lib/lp/soyuz/tests/test_livefs.py'
--- lib/lp/soyuz/tests/test_livefs.py 2014-06-18 22:20:52 +0000
+++ lib/lp/soyuz/tests/test_livefs.py 2014-06-18 22:20:53 +0000
@@ -301,6 +301,19 @@
301 getUtility(ILiveFSSet).exists(301 getUtility(ILiveFSSet).exists(
302 livefs.owner, livefs.distro_series, u"different"))302 livefs.owner, livefs.distro_series, u"different"))
303303
304 def test_getByPerson(self):
305 # ILiveFSSet.getByPerson returns all LiveFSes with the given owner.
306 owners = [self.factory.makePerson() for i in range(2)]
307 livefses = []
308 for owner in owners:
309 for i in range(2):
310 livefses.append(self.factory.makeLiveFS(
311 registrant=owner, owner=owner))
312 self.assertContentEqual(
313 livefses[:2], getUtility(ILiveFSSet).getByPerson(owners[0]))
314 self.assertContentEqual(
315 livefses[2:], getUtility(ILiveFSSet).getByPerson(owners[1]))
316
304 def test_getAll(self):317 def test_getAll(self):
305 # ILiveFSSet.getAll returns all LiveFSes.318 # ILiveFSSet.getAll returns all LiveFSes.
306 livefses = [self.factory.makeLiveFS() for i in range(3)]319 livefses = [self.factory.makeLiveFS() for i in range(3)]