launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #05795
[Merge] lp:~julian-edwards/launchpad/sponsor-syncs-bug-827555 into lp:launchpad
Julian Edwards has proposed merging lp:~julian-edwards/launchpad/sponsor-syncs-bug-827555 into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #827555 in Launchpad itself: "native syncs have no way to indicate sponsorship"
https://bugs.launchpad.net/launchpad/+bug/827555
For more details, see:
https://code.launchpad.net/~julian-edwards/launchpad/sponsor-syncs-bug-827555/+merge/84287
Make the Soyuz package copier accept a "sponsored" IPerson parameter which the Ubuntu guys need to use to show sponsored syncs from Debian. It will store the "sponsored" user as the creator on the source publication and then make sure that any announcement emails have that user as the From: address.
In addition, there are changes to packagecopyjob and the webservice API to support the new parameter.
UI changes will happen in a future branch.
--
https://code.launchpad.net/~julian-edwards/launchpad/sponsor-syncs-bug-827555/+merge/84287
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~julian-edwards/launchpad/sponsor-syncs-bug-827555 into lp:launchpad.
=== modified file 'lib/lp/soyuz/browser/tests/test_archive_webservice.py'
--- lib/lp/soyuz/browser/tests/test_archive_webservice.py 2011-08-12 11:37:08 +0000
+++ lib/lp/soyuz/browser/tests/test_archive_webservice.py 2011-12-02 16:46:47 +0000
@@ -322,6 +322,7 @@
def setup_data(self):
self.ws_version = "devel"
uploader_dude = self.factory.makePerson()
+ sponsored_dude = self.factory.makePerson()
source_archive = self.factory.makeArchive()
target_archive = self.factory.makeArchive(
purpose=ArchivePurpose.PRIMARY)
@@ -336,20 +337,22 @@
target_archive.newComponentUploader(uploader_dude, "universe")
transaction.commit()
return (source_archive, source_name, target_archive, to_pocket,
- to_series, uploader_dude, version)
+ to_series, uploader_dude, sponsored_dude, version)
def test_copyPackage(self):
"""Basic smoke test"""
(source_archive, source_name, target_archive, to_pocket, to_series,
- uploader_dude, version) = self.setup_data()
+ uploader_dude, sponsored_dude, version) = self.setup_data()
ws_target_archive = self.wsObject(target_archive, user=uploader_dude)
ws_source_archive = self.wsObject(source_archive)
+ ws_sponsored_dude = self.wsObject(sponsored_dude)
ws_target_archive.copyPackage(
source_name=source_name, version=version,
from_archive=ws_source_archive, to_pocket=to_pocket.name,
- to_series=to_series.name, include_binaries=False)
+ to_series=to_series.name, include_binaries=False,
+ sponsored=ws_sponsored_dude)
transaction.commit()
job_source = getUtility(IPlainPackageCopyJobSource)
@@ -359,15 +362,16 @@
def test_copyPackages(self):
"""Basic smoke test"""
(source_archive, source_name, target_archive, to_pocket, to_series,
- uploader_dude, version) = self.setup_data()
+ uploader_dude, sponsored_dude, version) = self.setup_data()
ws_target_archive = self.wsObject(target_archive, user=uploader_dude)
ws_source_archive = self.wsObject(source_archive)
+ ws_sponsored_dude = self.wsObject(sponsored_dude)
ws_target_archive.copyPackages(
source_names=[source_name], from_archive=ws_source_archive,
to_pocket=to_pocket.name, to_series=to_series.name,
- include_binaries=False)
+ include_binaries=False, sponsored = ws_sponsored_dude)
transaction.commit()
job_source = getUtility(IPlainPackageCopyJobSource)
=== modified file 'lib/lp/soyuz/interfaces/archive.py'
--- lib/lp/soyuz/interfaces/archive.py 2011-09-12 17:50:23 +0000
+++ lib/lp/soyuz/interfaces/archive.py 2011-12-02 16:46:47 +0000
@@ -1204,11 +1204,17 @@
title=_("Include Binaries"),
description=_("Whether or not to copy binaries already built for"
" this source"),
- required=False))
+ required=False),
+ sponsored=Reference(
+ schema=IPerson,
+ title=_("Sponsored Person"),
+ description=_("The person who is being sponsored for this copy."))
+ )
@export_write_operation()
@operation_for_version('devel')
def copyPackage(source_name, version, from_archive, to_pocket,
- person, to_series=None, include_binaries=False):
+ person, to_series=None, include_binaries=False,
+ sponsored=None):
"""Copy a single named source into this archive.
Asynchronously copy a specific version of a named source to the
@@ -1225,6 +1231,10 @@
the published binaries for each given source should also be
copied along with the source.
:param person: the `IPerson` who requests the sync.
+ :param sponsored: the `IPerson` who is being sponsored. Specifying
+ this will ensure that the person's email address is used as the
+ "From:" on the announcement email and will also be recorded as
+ the creator of the new source publication.
:raises NoSuchSourcePackageName: if the source name is invalid
:raises PocketNotFound: if the pocket name is invalid
@@ -1245,11 +1255,17 @@
title=_("Include Binaries"),
description=_("Whether or not to copy binaries already built for"
" this source"),
- required=False))
+ required=False),
+ sponsored=Reference(
+ schema=IPerson,
+ title=_("Sponsored Person"),
+ description=_("The person who is being sponsored for this copy."))
+ )
@export_write_operation()
@operation_for_version('devel')
def copyPackages(source_names, from_archive, to_pocket, person,
- to_series=None, include_binaries=False):
+ to_series=None, include_binaries=False,
+ sponsored=None):
"""Copy multiple named sources into this archive from another.
Asynchronously copy the most recent PUBLISHED versions of the named
@@ -1268,6 +1284,10 @@
the published binaries for each given source should also be
copied along with the source.
:param person: the `IPerson` who requests the sync.
+ :param sponsored: the `IPerson` who is being sponsored. Specifying
+ this will ensure that the person's email address is used as the
+ "From:" on the announcement email and will also be recorded as
+ the creator of the new source publication.
:raises NoSuchSourcePackageName: if the source name is invalid
:raises PocketNotFound: if the pocket name is invalid
=== modified file 'lib/lp/soyuz/interfaces/packagecopyjob.py'
--- lib/lp/soyuz/interfaces/packagecopyjob.py 2011-07-15 11:57:27 +0000
+++ lib/lp/soyuz/interfaces/packagecopyjob.py 2011-12-02 16:46:47 +0000
@@ -30,6 +30,7 @@
from canonical.launchpad import _
from lp.registry.interfaces.distroseries import IDistroSeries
+from lp.registry.interfaces.person import IPerson
from lp.services.job.interfaces.job import (
IJob,
IJobSource,
@@ -126,7 +127,8 @@
def create(package_name, source_archive,
target_archive, target_distroseries, target_pocket,
include_binaries=False, package_version=None,
- copy_policy=PackageCopyPolicy.INSECURE, requester=None):
+ copy_policy=PackageCopyPolicy.INSECURE, requester=None,
+ sponsored=None):
"""Create a new `IPlainPackageCopyJob`.
:param package_name: The name of the source package to copy.
@@ -142,6 +144,7 @@
that is to be copied.
:param copy_policy: Applicable `PackageCopyPolicy`.
:param requester: The user requesting the copy.
+ :param sponsored: The user who is being sponsored to make the copy.
"""
def createMultiple(target_distroseries, copy_tasks, requester,
@@ -190,6 +193,10 @@
title=_("Copy binaries"),
required=False, readonly=True)
+ sponsored = Reference(
+ schema=IPerson, title=_('Sponsored Person'),
+ required=False, readonly=True)
+
def addSourceOverride(override):
"""Add an `ISourceOverride` to the metadata."""
=== modified file 'lib/lp/soyuz/model/archive.py'
--- lib/lp/soyuz/model/archive.py 2011-09-12 17:50:23 +0000
+++ lib/lp/soyuz/model/archive.py 2011-12-02 16:46:47 +0000
@@ -1556,7 +1556,8 @@
"Not enabled for copying to PPAs yet.")
def copyPackage(self, source_name, version, from_archive, to_pocket,
- person, to_series=None, include_binaries=False):
+ person, to_series=None, include_binaries=False,
+ sponsored=None):
"""See `IArchive`."""
self._checkCopyPackageFeatureFlags()
@@ -1576,10 +1577,12 @@
target_archive=self, target_distroseries=series,
target_pocket=pocket,
package_version=version, include_binaries=include_binaries,
- copy_policy=PackageCopyPolicy.INSECURE, requester=person)
+ copy_policy=PackageCopyPolicy.INSECURE, requester=person,
+ sponsored=sponsored)
def copyPackages(self, source_names, from_archive, to_pocket,
- person, to_series=None, include_binaries=None):
+ person, to_series=None, include_binaries=None,
+ sponsored=None):
"""See `IArchive`."""
self._checkCopyPackageFeatureFlags()
@@ -1620,7 +1623,7 @@
job_source.createMultiple(
series, copy_tasks, person,
copy_policy=PackageCopyPolicy.MASS_SYNC,
- include_binaries=include_binaries)
+ include_binaries=include_binaries, sponsored=sponsored)
def _collectLatestPublishedSources(self, from_archive, source_names):
"""Private helper to collect the latest published sources for an
=== modified file 'lib/lp/soyuz/model/packagecopyjob.py'
--- lib/lp/soyuz/model/packagecopyjob.py 2011-11-14 08:30:52 +0000
+++ lib/lp/soyuz/model/packagecopyjob.py 2011-12-02 16:46:47 +0000
@@ -45,6 +45,7 @@
from lp.registry.interfaces.distroseriesdifferencecomment import (
IDistroSeriesDifferenceCommentSource,
)
+from lp.registry.interfaces.person import IPersonSet
from lp.registry.interfaces.pocket import PackagePublishingPocket
from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet
from lp.registry.model.distroseries import DistroSeries
@@ -236,24 +237,31 @@
classProvides(IPlainPackageCopyJobSource)
@classmethod
- def _makeMetadata(cls, target_pocket, package_version, include_binaries):
+ def _makeMetadata(cls, target_pocket, package_version,
+ include_binaries, sponsored=None):
"""Produce a metadata dict for this job."""
+ if sponsored:
+ sponsored_name = sponsored.name
+ else:
+ sponsored_name = None
return {
'target_pocket': target_pocket.value,
'package_version': package_version,
'include_binaries': bool(include_binaries),
+ 'sponsored': sponsored_name,
}
@classmethod
def create(cls, package_name, source_archive,
target_archive, target_distroseries, target_pocket,
include_binaries=False, package_version=None,
- copy_policy=PackageCopyPolicy.INSECURE, requester=None):
+ copy_policy=PackageCopyPolicy.INSECURE, requester=None,
+ sponsored=None):
"""See `IPlainPackageCopyJobSource`."""
assert package_version is not None, "No package version specified."
assert requester is not None, "No requester specified."
metadata = cls._makeMetadata(
- target_pocket, package_version, include_binaries)
+ target_pocket, package_version, include_binaries, sponsored)
job = PackageCopyJob(
job_type=cls.class_job_type,
source_archive=source_archive,
@@ -268,7 +276,8 @@
@classmethod
def _composeJobInsertionTuple(cls, target_distroseries, copy_policy,
- include_binaries, job_id, copy_task):
+ include_binaries, job_id, copy_task,
+ sponsored):
"""Create an SQL fragment for inserting a job into the database.
:return: A string representing an SQL tuple containing initializers
@@ -283,7 +292,7 @@
target_pocket,
) = copy_task
metadata = cls._makeMetadata(
- target_pocket, package_version, include_binaries)
+ target_pocket, package_version, include_binaries, sponsored)
data = (
cls.class_job_type, target_distroseries, copy_policy,
source_archive, target_archive, package_name, job_id,
@@ -294,14 +303,14 @@
@classmethod
def createMultiple(cls, target_distroseries, copy_tasks, requester,
copy_policy=PackageCopyPolicy.INSECURE,
- include_binaries=False):
+ include_binaries=False, sponsored=None):
"""See `IPlainPackageCopyJobSource`."""
store = IMasterStore(Job)
job_ids = Job.createMultiple(store, len(copy_tasks), requester)
job_contents = [
cls._composeJobInsertionTuple(
target_distroseries, copy_policy, include_binaries, job_id,
- task)
+ task, sponsored)
for job_id, task in zip(job_ids, copy_tasks)]
result = store.execute("""
INSERT INTO PackageCopyJob (
@@ -362,6 +371,13 @@
def include_binaries(self):
return self.metadata['include_binaries']
+ @property
+ def sponsored(self):
+ name = self.metadata['sponsored']
+ if name is None:
+ return None
+ return getUtility(IPersonSet).getByName(name)
+
def _createPackageUpload(self, unapproved=False):
pu = self.target_distroseries.createQueueEntry(
pocket=self.target_pocket, archive=self.target_archive,
@@ -510,7 +526,8 @@
series=self.target_distroseries, pocket=self.target_pocket,
include_binaries=self.include_binaries, check_permissions=True,
person=self.requester, overrides=[override],
- send_email=send_email, announce_from_person=self.requester)
+ send_email=send_email, announce_from_person=self.requester,
+ sponsored=self.sponsored)
# Add a PackageDiff for this new upload if it has ancestry.
if ancestry is not None:
=== modified file 'lib/lp/soyuz/scripts/packagecopier.py'
--- lib/lp/soyuz/scripts/packagecopier.py 2011-10-27 20:51:28 +0000
+++ lib/lp/soyuz/scripts/packagecopier.py 2011-12-02 16:46:47 +0000
@@ -532,7 +532,8 @@
def do_copy(sources, archive, series, pocket, include_binaries=False,
allow_delayed_copies=True, person=None, check_permissions=True,
overrides=None, send_email=False, strict_binaries=True,
- close_bugs=True, create_dsd_job=True, announce_from_person=None):
+ close_bugs=True, create_dsd_job=True, announce_from_person=None,
+ sponsored=None):
"""Perform the complete copy of the given sources incrementally.
Verifies if each copy can be performed using `CopyChecker` and
@@ -574,6 +575,10 @@
copied publications should be closed.
:param create_dsd_job: A boolean indicating whether or not a dsd job
should be created for the new source publication.
+ :param sponsored: An `IPerson` representing the person who is
+ being sponsored for this copy. May be None, but if present will
+ affect the "From:" address on notifications and the creator of the
+ publishing record will be set to this person.
:raise CannotCopy when one or more copies were not allowed. The error
@@ -644,11 +649,16 @@
old_version = existing.sourcepackagerelease.version
else:
old_version = None
+ if sponsored is not None:
+ announce_from_person = sponsored
+ creator = sponsored
+ else:
+ creator = person
sub_copies = _do_direct_copy(
source, archive, destination_series, pocket,
include_binaries, override, close_bugs=close_bugs,
create_dsd_job=create_dsd_job,
- close_bugs_since_version=old_version, creator=person)
+ close_bugs_since_version=old_version, creator=creator)
if send_email:
notify(
person, source.sourcepackagerelease, [], [], archive,
=== modified file 'lib/lp/soyuz/scripts/tests/test_copypackage.py'
--- lib/lp/soyuz/scripts/tests/test_copypackage.py 2011-10-27 16:04:00 +0000
+++ lib/lp/soyuz/scripts/tests/test_copypackage.py 2011-12-02 16:46:47 +0000
@@ -1499,6 +1499,33 @@
self.assertEqual(expected_text, body)
self.assertEqual(expected_text, body)
+ def test_sponsored_copy_notification(self):
+ # If it's a sponsored copy then the From: address on the
+ # notification is changed to the sponsored person and the
+ # SPPH.creator is set to the same person.
+ archive = self.test_publisher.ubuntutest.main_archive
+ source = self.test_publisher.getPubSource(
+ archive=archive, version='1.0-2', architecturehintlist='any')
+ changelog = self.factory.makeChangelog(spn="foo", versions=["1.0-2"])
+ source.sourcepackagerelease.changelog = changelog
+ # Copying to a primary archive reads the changes to close bugs.
+ transaction.commit()
+ nobby = self.createNobby(('i386', 'hppa'))
+ getUtility(ISourcePackageFormatSelectionSet).add(
+ nobby, SourcePackageFormat.FORMAT_1_0)
+ nobby.changeslist = 'nobby-changes@xxxxxxxxxxx'
+ sponsored_person = self.factory.makePerson(
+ displayname="Sponsored", email="sponsored@xxxxxxxxxxx")
+ [copied_source] = do_copy(
+ [source], archive, nobby, source.pocket, False,
+ person=source.sourcepackagerelease.creator,
+ check_permissions=False, send_email=True,
+ sponsored=sponsored_person)
+ [notification, announcement] = pop_notifications()
+ self.assertEquals(
+ 'Sponsored <sponsored@xxxxxxxxxxx>', announcement['From'])
+ self.assertEqual(sponsored_person, copied_source.creator)
+
def test_copy_notification_contains_aggregate_change_log(self):
# When copying a package that generates a notification,
# the changelog should contain all of the changelog_entry texts for
=== modified file 'lib/lp/soyuz/tests/test_archive.py'
--- lib/lp/soyuz/tests/test_archive.py 2011-09-12 17:50:23 +0000
+++ lib/lp/soyuz/tests/test_archive.py 2011-12-02 16:46:47 +0000
@@ -2122,11 +2122,12 @@
# parameters.
(source, source_archive, source_name, target_archive, to_pocket,
to_series, version) = self._setup_copy_data()
+ sponsored = self.factory.makePerson()
with person_logged_in(target_archive.owner):
target_archive.copyPackage(
source_name, version, source_archive, to_pocket.name,
to_series=to_series.name, include_binaries=False,
- person=target_archive.owner)
+ person=target_archive.owner, sponsored=sponsored)
# The source should not be published yet in the target_archive.
published = target_archive.getPublishedSources(
@@ -2146,6 +2147,7 @@
target_distroseries=to_series,
target_pocket=to_pocket,
include_binaries=False,
+ sponsored=sponsored,
copy_policy=PackageCopyPolicy.INSECURE))
def test_copyPackage_disallows_non_primary_archive_uploaders(self):
@@ -2206,11 +2208,12 @@
(source, source_archive, source_name, target_archive, to_pocket,
to_series, version) = self._setup_copy_data()
+ sponsored = self.factory.makePerson()
with person_logged_in(target_archive.owner):
target_archive.copyPackages(
[source_name], source_archive, to_pocket.name,
to_series=to_series.name, include_binaries=False,
- person=target_archive.owner)
+ person=target_archive.owner, sponsored=sponsored)
# The source should not be published yet in the target_archive.
published = target_archive.getPublishedSources(
@@ -2228,6 +2231,7 @@
target_distroseries=to_series,
target_pocket=to_pocket,
include_binaries=False,
+ sponsored=sponsored,
copy_policy=PackageCopyPolicy.MASS_SYNC))
def test_copyPackages_with_multiple_packages(self):
=== modified file 'lib/lp/soyuz/tests/test_packagecopyjob.py'
--- lib/lp/soyuz/tests/test_packagecopyjob.py 2011-11-03 15:58:26 +0000
+++ lib/lp/soyuz/tests/test_packagecopyjob.py 2011-12-02 16:46:47 +0000
@@ -136,6 +136,7 @@
archive1 = self.factory.makeArchive(distroseries.distribution)
archive2 = self.factory.makeArchive(distroseries.distribution)
requester = self.factory.makePerson()
+ sponsored = self.factory.makePerson()
source = getUtility(IPlainPackageCopyJobSource)
job = source.create(
package_name="foo", source_archive=archive1,
@@ -143,7 +144,7 @@
target_pocket=PackagePublishingPocket.RELEASE,
package_version="1.0-1", include_binaries=False,
copy_policy=PackageCopyPolicy.MASS_SYNC,
- requester=requester)
+ requester=requester, sponsored=sponsored)
self.assertProvides(job, IPackageCopyJob)
self.assertEquals(archive1.id, job.source_archive_id)
self.assertEquals(archive1, job.source_archive)
@@ -156,6 +157,7 @@
self.assertEquals(False, job.include_binaries)
self.assertEquals(PackageCopyPolicy.MASS_SYNC, job.copy_policy)
self.assertEqual(requester, job.requester)
+ self.assertEqual(sponsored, job.sponsored)
def test_createMultiple_creates_one_job_per_copy(self):
mother = self.factory.makeDistroSeriesParent()
Follow ups