launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #24459
[Merge] ~pappacena/launchpad:package-publishing-copied-from-archive into launchpad:master
Thiago F. Pappacena has proposed merging ~pappacena/launchpad:package-publishing-copied-from-archive into launchpad:master.
Commit message:
Keeping track of the original archives of source and binary package copies on [Source|Binary]PackagePublishingHistory.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~pappacena/launchpad/+git/launchpad/+merge/380382
The tracking of "copied_from_archive" seems to be working fine, but it's missing showing this information on S/BPackagePublishingHistory page.
On the page, it's shown as "Previous archive was <archive>" text, right below where we show that the package was copied today. I'm not sure this is the right text to show to the user, but I couldn't think of anything different.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~pappacena/launchpad:package-publishing-copied-from-archive into launchpad:master.
diff --git a/lib/lp/_schema_circular_imports.py b/lib/lp/_schema_circular_imports.py
index 70c5b72..1bc1a06 100644
--- a/lib/lp/_schema_circular_imports.py
+++ b/lib/lp/_schema_circular_imports.py
@@ -361,6 +361,10 @@ patch_reference_property(
patch_reference_property(
ISourcePackagePublishingHistory, 'archive', IArchive)
patch_reference_property(
+ IBinaryPackagePublishingHistory, 'copied_from_archive', IArchive)
+patch_reference_property(
+ ISourcePackagePublishingHistory, 'copied_from_archive', IArchive)
+patch_reference_property(
ISourcePackagePublishingHistory, 'ancestor',
ISourcePackagePublishingHistory)
patch_reference_property(
diff --git a/lib/lp/soyuz/browser/publishing.py b/lib/lp/soyuz/browser/publishing.py
index 1a23bc3..9547600 100644
--- a/lib/lp/soyuz/browser/publishing.py
+++ b/lib/lp/soyuz/browser/publishing.py
@@ -1,4 +1,4 @@
-# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Browser views for Soyuz publishing records."""
@@ -265,6 +265,14 @@ class SourcePublishingRecordView(BasePublishingRecordView):
return False
+ def rootOriginArchive(self):
+ """Get the original archive from this binary build if this was a
+ copied publishing.
+ """
+ if not self.wasCopied():
+ return None
+ return self.context.sourcepackagerelease.upload_archive
+
@property
def allow_selection(self):
"""Do not render the checkbox corresponding to this record."""
@@ -406,3 +414,11 @@ class BinaryPublishingRecordView(BasePublishingRecordView):
return True
return False
+
+ def rootOriginArchive(self):
+ """Get the original archive from this binary build if this was a
+ copied publishing.
+ """
+ if not self.wasCopied():
+ return None
+ return self.context.binarypackagerelease.build.archive
diff --git a/lib/lp/soyuz/interfaces/publishing.py b/lib/lp/soyuz/interfaces/publishing.py
index 02c3615..fab8a76 100644
--- a/lib/lp/soyuz/interfaces/publishing.py
+++ b/lib/lp/soyuz/interfaces/publishing.py
@@ -1,4 +1,4 @@
-# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Publishing interfaces."""
@@ -269,6 +269,13 @@ class ISourcePackagePublishingHistoryPublic(IPublishingView):
Interface,
title=_('Archive ID'), required=True, readonly=True,
))
+ copied_from_archive = exported(
+ Reference(
+ # Really IArchive (fixed in _schema_circular_imports.py).
+ Interface,
+ title=_('Original archive ID where this package was copied from.'),
+ required=False, readonly=True,
+ ))
supersededby = Int(
title=_('The sourcepackagerelease which superseded this one'),
required=False, readonly=False,
@@ -703,6 +710,13 @@ class IBinaryPackagePublishingHistoryPublic(IPublishingView):
description=_("The context archive for this publication."),
required=True, readonly=True,
))
+ copied_from_archive = exported(
+ Reference(
+ # Really IArchive (fixed in _schema_circular_imports.py).
+ Interface,
+ title=_('Original archive ID where this package was copied from.'),
+ required=False, readonly=True,
+ ))
removed_by = exported(
Reference(
IPerson,
@@ -865,7 +879,8 @@ class IBinaryPackagePublishingHistory(IBinaryPackagePublishingHistoryPublic,
class IPublishingSet(Interface):
"""Auxiliary methods for dealing with sets of publications."""
- def publishBinaries(archive, distroseries, pocket, binaries):
+ def publishBinaries(archive, distroseries, pocket, binaries,
+ copied_from_archives=None):
"""Efficiently publish multiple BinaryPackageReleases in an Archive.
Creates `IBinaryPackagePublishingHistory` records for each
@@ -879,6 +894,8 @@ class IPublishingSet(Interface):
:param binaries: A dict mapping `BinaryPackageReleases` to their
desired overrides as (`Component`, `Section`,
`PackagePublishingPriority`, `phased_update_percentage`) tuples.
+ :param copied_from_archives: A dict mapping `BinaryPackageReleases`
+ to their original archives (for copy operations).
:return: A list of new `IBinaryPackagePublishingHistory` records.
"""
@@ -903,7 +920,8 @@ class IPublishingSet(Interface):
def newSourcePublication(archive, sourcepackagerelease, distroseries,
component, section, pocket, ancestor,
- create_dsd_job=True):
+ create_dsd_job=True, copied_from_archive=None,
+ creator=None, sponsor=None, packageupload=None):
"""Create a new `SourcePackagePublishingHistory`.
:param archive: An `IArchive`
@@ -916,6 +934,8 @@ class IPublishingSet(Interface):
version of this publishing record
:param create_dsd_job: A boolean indicating whether or not a dsd job
should be created for the new source publication.
+ :param copied_from_archive: For copy operations, this should be the
+ source archive (from where this new publication is comming from).
:param creator: An optional `IPerson`. If this is None, the
sourcepackagerelease's creator will be used.
:param sponsor: An optional `IPerson` indicating the sponsor of this
diff --git a/lib/lp/soyuz/model/publishing.py b/lib/lp/soyuz/model/publishing.py
index 3e73e98..70007bb 100644
--- a/lib/lp/soyuz/model/publishing.py
+++ b/lib/lp/soyuz/model/publishing.py
@@ -1,4 +1,4 @@
-# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
__metaclass__ = type
@@ -258,6 +258,8 @@ class SourcePackagePublishingHistory(SQLBase, ArchivePublisherBase):
default=PackagePublishingPocket.RELEASE,
notNull=True)
archive = ForeignKey(dbName="archive", foreignKey="Archive", notNull=True)
+ copied_from_archive = ForeignKey(
+ dbName="copied_from_archive", foreignKey="Archive", notNull=False)
removed_by = ForeignKey(
dbName="removed_by", foreignKey="Person",
storm_validator=validate_public_person, default=None)
@@ -529,6 +531,9 @@ class SourcePackagePublishingHistory(SQLBase, ArchivePublisherBase):
component = override.component
if override.section is not None:
section = override.section
+
+ copied_from_archive = self.archive if archive != self.archive else None
+
return getUtility(IPublishingSet).newSourcePublication(
archive,
self.sourcepackagerelease,
@@ -540,6 +545,7 @@ class SourcePackagePublishingHistory(SQLBase, ArchivePublisherBase):
create_dsd_job=create_dsd_job,
creator=creator,
sponsor=sponsor,
+ copied_from_archive=copied_from_archive,
packageupload=packageupload)
def getStatusSummaryForBuilds(self):
@@ -638,6 +644,8 @@ class BinaryPackagePublishingHistory(SQLBase, ArchivePublisherBase):
dateremoved = UtcDateTimeCol(default=None)
pocket = EnumCol(dbName='pocket', schema=PackagePublishingPocket)
archive = ForeignKey(dbName="archive", foreignKey="Archive", notNull=True)
+ copied_from_archive = ForeignKey(
+ dbName="copied_from_archive", foreignKey="Archive", notNull=False)
removed_by = ForeignKey(
dbName="removed_by", foreignKey="Person",
storm_validator=validate_public_person, default=None)
@@ -1016,8 +1024,11 @@ def expand_binary_requests(distroseries, binaries):
class PublishingSet:
"""Utilities for manipulating publications in batches."""
- def publishBinaries(self, archive, distroseries, pocket, binaries):
+ def publishBinaries(self, archive, distroseries, pocket, binaries,
+ copied_from_archives=None):
"""See `IPublishingSet`."""
+ if copied_from_archives is None:
+ copied_from_archives = {}
# Expand the dict of binaries into a list of tuples including the
# architecture.
if distroseries.distribution != archive.distribution:
@@ -1066,13 +1077,24 @@ class PublishingSet:
if not needed:
return []
+ def get_origin_archive(bpr):
+ """Returns the original archive of a BinaryPackageRelease
+ to be set on the newly created BinaryPackagePublishingHistory.
+ """
+ original_archive = copied_from_archives.get(bpr)
+ if original_archive == archive:
+ return None
+ return original_archive
+
BPPH = BinaryPackagePublishingHistory
return bulk.create(
- (BPPH.archive, BPPH.distroarchseries, BPPH.pocket,
+ (BPPH.archive, BPPH.copied_from_archive,
+ BPPH.distroarchseries, BPPH.pocket,
BPPH.binarypackagerelease, BPPH.binarypackagename,
BPPH.component, BPPH.section, BPPH.priority,
BPPH.phased_update_percentage, BPPH.status, BPPH.datecreated),
- [(archive, das, pocket, bpr, bpr.binarypackagename,
+ [(archive, get_origin_archive(bpr), das, pocket, bpr,
+ bpr.binarypackagename,
get_component(archive, das.distroseries, component),
section, priority, phased_update_percentage,
PackagePublishingStatus.PENDING, UTC_NOW)
@@ -1150,12 +1172,16 @@ class PublishingSet:
bpph.priority, None)) for bpph in bpphs)
if not with_overrides:
return list()
+ copied_from_archives = {
+ bpph.binarypackagerelease: bpph.archive for bpph in bpphs}
return self.publishBinaries(
- archive, distroseries, pocket, with_overrides)
+ archive, distroseries, pocket, with_overrides,
+ copied_from_archives)
def newSourcePublication(self, archive, sourcepackagerelease,
distroseries, component, section, pocket,
ancestor=None, create_dsd_job=True,
+ copied_from_archive=None,
creator=None, sponsor=None, packageupload=None):
"""See `IPublishingSet`."""
# Circular import.
@@ -1171,6 +1197,7 @@ class PublishingSet:
pub = SourcePackagePublishingHistory(
distroseries=distroseries,
pocket=pocket,
+ copied_from_archive=copied_from_archive,
archive=archive,
sourcepackagename=sourcepackagerelease.sourcepackagename,
sourcepackagerelease=sourcepackagerelease,
diff --git a/lib/lp/soyuz/scripts/tests/test_copypackage.py b/lib/lp/soyuz/scripts/tests/test_copypackage.py
index b5bd4c6..4406a96 100644
--- a/lib/lp/soyuz/scripts/tests/test_copypackage.py
+++ b/lib/lp/soyuz/scripts/tests/test_copypackage.py
@@ -1,4 +1,4 @@
-# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
__metaclass__ = type
@@ -11,6 +11,7 @@ from testtools.content import text_content
from testtools.matchers import (
Equals,
LessThan,
+ MatchesListwise,
MatchesStructure,
)
import transaction
@@ -1015,6 +1016,38 @@ class CopyCheckerTestCase(TestCaseWithFactory):
copied_source, copied_source.distroseries, copied_source.pocket,
None, False)
+ def test_copy_to_another_archive_tracks_source_archive(self):
+ """Checks that creating a copy of a package publishing keeps track
+ of origin archive.
+ """
+ # Create a source with binaries in ubuntutest/breezy-autotest.
+ source = self.test_publisher.getPubSource(architecturehintlist='i386')
+ binary = self.test_publisher.getPubBinaries(pub_source=source)[0]
+
+ hoary = self.test_publisher.ubuntutest.getSeries('hoary-test')
+ self.test_publisher.addFakeChroots(hoary)
+
+ target_archive = self.factory.makeArchive(
+ distribution=self.test_publisher.ubuntutest,
+ purpose=ArchivePurpose.PPA)
+
+ copied_source = source.copyTo(hoary, source.pocket, target_archive)
+ copied_source = removeSecurityProxy(copied_source)
+ self.assertThat(
+ copied_source, MatchesStructure.byEquality(
+ archive=target_archive,
+ copied_from_archive=source.archive))
+
+ copied_binaries = binary.copyTo(hoary, source.pocket, target_archive)
+ copied_binaries = removeSecurityProxy(copied_binaries)
+ self.assertEqual(1, len(copied_binaries))
+ self.assertThat(
+ copied_binaries, MatchesListwise([
+ MatchesStructure.byEquality(
+ archive=target_archive,
+ copied_from_archive=binary.archive),
+ ]))
+
class BaseDoCopyTests:
diff --git a/lib/lp/soyuz/stories/ppa/xx-copy-packages.txt b/lib/lp/soyuz/stories/ppa/xx-copy-packages.txt
index 8159d2d..95bec1a 100644
--- a/lib/lp/soyuz/stories/ppa/xx-copy-packages.txt
+++ b/lib/lp/soyuz/stories/ppa/xx-copy-packages.txt
@@ -289,6 +289,7 @@ context.
Publishing details
Copied from ubuntu hoary in Primary Archive for Ubuntu Linux by James
Blackwell
+ Previous archive was PPA for Celso Providelo
Changelog
pmount (0.1-1) hoary; urgency=low
* Fix description (Malone #1)
diff --git a/lib/lp/soyuz/stories/soyuz/xx-packagepublishinghistory.txt b/lib/lp/soyuz/stories/soyuz/xx-packagepublishinghistory.txt
index 31e98b7..e62ede7 100644
--- a/lib/lp/soyuz/stories/soyuz/xx-packagepublishinghistory.txt
+++ b/lib/lp/soyuz/stories/soyuz/xx-packagepublishinghistory.txt
@@ -27,6 +27,61 @@ shows the complete history of a package in all series.
>>> print(table.findAll("tr")[2].td["colspan"])
8
+Copy the package to a new distribution named "foo-distro". The publishing
+history page of Foo-distro should show that the package was copied, but no
+intermediate archive information.
+
+ >>> login('foo.bar@xxxxxxxxxxxxx')
+ >>> from lp.soyuz.model.archive import ArchivePurpose
+ >>> new_distro = stp.factory.makeDistribution(name='foo-distro')
+ >>> new_distroseries = stp.factory.makeDistroSeries(
+ ... name='foo-series', distribution=new_distro)
+ >>> new_archive = stp.factory.makeArchive(
+ ... distribution=new_distro,
+ ... purpose=ArchivePurpose.PRIMARY)
+ >>> new_pub1 = source_pub.copyTo(
+ ... new_distroseries, source_pub.pocket, new_archive)
+ >>> logout()
+
+ >>> anon_browser.open(
+ ... 'http://launchpad.test/%s/+source/test-history/'
+ ... '+publishinghistory' % new_distro.name)
+
+ >>> table = find_tag_by_id(anon_browser.contents, 'publishing-summary')
+ >>> print(extract_text(table))
+ Date Status Target Pocket Component Section Version
+ ... UTC Pending Foo-series release main base 666
+ Copied from ubuntutest breezy-autotest in Primary Archive for Ubuntu Test
+
+
+Copying from "Foo-distro" to a new distribution "Another-distro". It should
+show the intermediate archive Foo-distro on Another-distro's history page,
+since we copied the package from there. It should also show that the
+original distribution was Ubuntutest breezy-autotest.
+
+ >>> login('foo.bar@xxxxxxxxxxxxx')
+ >>> from lp.soyuz.model.archive import ArchivePurpose
+ >>> new_distro = stp.factory.makeDistribution(name='another-distro')
+ >>> new_distroseries = stp.factory.makeDistroSeries(
+ ... name='another-series', distribution=new_distro)
+ >>> new_archive = stp.factory.makeArchive(
+ ... distribution=new_distro,
+ ... purpose=ArchivePurpose.PRIMARY)
+ >>> new_pub2 = new_pub1.copyTo(
+ ... new_distroseries, source_pub.pocket, new_archive)
+ >>> logout()
+
+ >>> anon_browser.open(
+ ... 'http://launchpad.test/%s/+source/test-history/'
+ ... '+publishinghistory' % new_distro.name)
+
+ >>> table = find_tag_by_id(anon_browser.contents, 'publishing-summary')
+ >>> print(extract_text(table))
+ Date Status Target Pocket Component Section Version
+ ... UTC Pending Another-series release main base 666
+ Copied from ubuntutest breezy-autotest in Primary Archive for Ubuntu Test
+ Previous archive was Primary Archive for Foo-distro
+
A publishing record will be shown as deleted in the publishing history after a
request for deletion by a user.
diff --git a/lib/lp/soyuz/stories/webservice/xx-binary-package-publishing.txt b/lib/lp/soyuz/stories/webservice/xx-binary-package-publishing.txt
index 81482f2..df1a485 100644
--- a/lib/lp/soyuz/stories/webservice/xx-binary-package-publishing.txt
+++ b/lib/lp/soyuz/stories/webservice/xx-binary-package-publishing.txt
@@ -71,6 +71,7 @@ Each binary publication exposes a number of properties:
binary_package_version: u'1.0'
build_link: u'http://.../~cprov/+archive/ubuntu/ppa/+build/28'
component_name: u'main'
+ copied_from_archive_link: None
date_created: u'2007-08-10T13:00:00+00:00'
date_made_pending: None
date_published: u'2007-08-10T13:00:01+00:00'
diff --git a/lib/lp/soyuz/templates/packagepublishing-details.pt b/lib/lp/soyuz/templates/packagepublishing-details.pt
index 0b0102c..ca90dc6 100644
--- a/lib/lp/soyuz/templates/packagepublishing-details.pt
+++ b/lib/lp/soyuz/templates/packagepublishing-details.pt
@@ -34,7 +34,16 @@
<span tal:attributes="title context/datepublished/fmt:datetime"
tal:content="context/datepublished/fmt:displaydate" />
</li>
- <li tal:condition="view/wasCopied">
+
+ <tal:comment condition="nothing">
+ For package copies, we have a distinction between what is the
+ "previous_archive" (the archive from where we directly copied a
+ publishing) and the "root_archive" (the archive where the package
+ was originally uploaded to).
+ </tal:comment>
+ <li tal:define="previous_archive context/copied_from_archive;
+ root_archive view/rootOriginArchive"
+ tal:condition="view/wasCopied">
Copied from
<tal:source_original_location condition="view/is_source">
<tal:define
@@ -46,12 +55,11 @@
message string:${distro/name} ${series/name} in "
replace="message" />
<a tal:condition="linkify_archive"
- tal:attributes="href source/upload_archive/fmt:url"
- tal:content="source/upload_archive/displayname" />
+ tal:attributes="href root_archive/fmt:url"
+ tal:content="root_archive/displayname" />
<tal:message
condition="not:linkify_archive"
- define="archive source/upload_archive;
- message string:${archive/displayname}"
+ define="message string:${root_archive/displayname}"
replace="message" />
</tal:define>
<tal:source_creator condition="context/creator">
@@ -64,15 +72,20 @@
<tal:binary_build_location condition="view/is_binary">
<tal:message
define="build context/binarypackagerelease/build;
- archive build/archive;
pocket build/pocket;
arch build/distro_arch_series;
series arch/distroseries;
distro series/distribution;
- message string:${distro/name} ${series/name}-${pocket/name/fmt:lower} ${arch/architecturetag} in ${archive/displayname}"
+ message string:${distro/name} ${series/name}-${pocket/name/fmt:lower} ${arch/architecturetag} in ${root_archive/displayname}"
replace="message" />
</tal:binary_build_location>
- </li>
+ <p tal:condition="python: previous_archive
+ and previous_archive != root_archive">
+ Previous archive was
+ <a tal:attributes="href previous_archive/fmt:url"
+ tal:content="previous_archive/displayname" />
+ </p>
+ </li>
</ul>
</tal:root>