launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #15621
[Merge] lp:~stevenk/launchpad/deny-obsolete-series-uploads into lp:launchpad
Steve Kowalik has proposed merging lp:~stevenk/launchpad/deny-obsolete-series-uploads into lp:launchpad with lp:~stevenk/launchpad/db-add-archive-permit-obsolete as a prerequisite.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #902836 in Launchpad itself: "Building in a PPA for obsolete release Karmic Koala isn't disabled"
https://bugs.launchpad.net/launchpad/+bug/902836
For more details, see:
https://code.launchpad.net/~stevenk/launchpad/deny-obsolete-series-uploads/+merge/165515
Make use of the new Archive.permit_obsolete_series_uploads column by adding it to the model and rejecting any source upload or build against an obsolete series with the flag unset.
--
https://code.launchpad.net/~stevenk/launchpad/deny-obsolete-series-uploads/+merge/165515
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/deny-obsolete-series-uploads into lp:launchpad.
=== modified file 'lib/lp/soyuz/browser/archive.py'
--- lib/lp/soyuz/browser/archive.py 2013-05-14 08:27:03 +0000
+++ lib/lp/soyuz/browser/archive.py 2013-05-24 01:51:31 +0000
@@ -2034,6 +2034,7 @@
'require_virtualized',
'build_debug_symbols',
'publish_debug_symbols',
+ 'permit_obsolete_series_uploads',
'authorized_size',
'relative_build_score',
'external_dependencies',
=== modified file 'lib/lp/soyuz/configure.zcml'
--- lib/lp/soyuz/configure.zcml 2013-05-14 08:27:03 +0000
+++ lib/lp/soyuz/configure.zcml 2013-05-24 01:51:31 +0000
@@ -426,9 +426,11 @@
<require
permission="launchpad.Admin"
interface="lp.soyuz.interfaces.archive.IArchiveAdmin"
- set_attributes="name authorized_size build_debug_symbols
+ set_attributes="authorized_size build_debug_symbols
buildd_secret enabled_restricted_families
- external_dependencies private publish_debug_symbols
+ external_dependencies name
+ permit_obsolete_series_uploads
+ private publish_debug_symbols
require_virtualized"/>
<require
permission="launchpad.Moderate"
=== modified file 'lib/lp/soyuz/interfaces/archive.py'
--- lib/lp/soyuz/interfaces/archive.py 2013-05-14 08:27:03 +0000
+++ lib/lp/soyuz/interfaces/archive.py 2013-05-24 01:51:31 +0000
@@ -17,6 +17,7 @@
'CannotUploadToArchive',
'CannotUploadToPPA',
'CannotUploadToPocket',
+ 'CannotUploadToSeries',
'FULL_COMPONENT_SUPPORT',
'IArchive',
'IArchiveAdmin',
@@ -187,7 +188,7 @@
def __init__(self, **args):
"""Construct a `CannotUploadToArchive`."""
- Exception.__init__(self, self._fmt % args)
+ super(CannotUploadToArchive, self).__init__(self._fmt % args)
class InvalidPocketForPartnerArchive(CannotUploadToArchive):
@@ -201,7 +202,7 @@
"""Returned when a pocket is closed for uploads."""
def __init__(self, distroseries, pocket):
- Exception.__init__(self,
+ super(CannotUploadToPocket, self).__init__(
"Not permitted to upload to the %s pocket in a series in the "
"'%s' state." % (pocket.name, distroseries.status.name))
@@ -249,7 +250,7 @@
"Signer is not permitted to upload to the component '%(component)s'.")
def __init__(self, component):
- CannotUploadToArchive.__init__(self, component=component.name)
+ super(NoRightsForComponent, self).__init__(component=component.name)
class InvalidPocketForPPA(CannotUploadToArchive):
@@ -264,7 +265,17 @@
_fmt = ("%(archive_name)s is disabled.")
def __init__(self, archive_name):
- CannotUploadToArchive.__init__(self, archive_name=archive_name)
+ super(ArchiveDisabled, self).__init__(archive_name=archive_name)
+
+
+class CannotUploadToSeries(CannotUploadToArchive):
+ """Uploading to an obsolete series is not allowed."""
+
+ _fmt = ("%(distroseries)s is obsolete and will not accept new uploads.")
+
+ def __init__(self, distroseries):
+ super(CannotUploadToSeries, self).__init__(
+ distroseries=distroseries.name)
@error_status(httplib.BAD_REQUEST)
@@ -489,6 +500,11 @@
description=_(
"Publish debug symbol packages in the apt repository."))
+ permit_obsolete_series_uploads = Bool(
+ title=_("Permit uploads to obsolete series"), required=False,
+ description=_(
+ "Allow uploads targeted to obsolete series."))
+
authorized_size = exported(
Int(
title=_("Authorized size"), required=False,
=== modified file 'lib/lp/soyuz/model/archive.py'
--- lib/lp/soyuz/model/archive.py 2013-05-14 08:27:03 +0000
+++ lib/lp/soyuz/model/archive.py 2013-05-24 01:51:31 +0000
@@ -126,6 +126,7 @@
CannotSwitchPrivacy,
CannotUploadToPocket,
CannotUploadToPPA,
+ CannotUploadToSeries,
ComponentNotFound,
default_name_by_purpose,
FULL_COMPONENT_SUPPORT,
@@ -282,6 +283,9 @@
publish_debug_symbols = BoolCol(
dbName='publish_debug_symbols', notNull=False, default=False)
+ permit_obsolete_series_uploads = BoolCol(
+ dbName='permit_obsolete_series_uploads', notNull=True, default=False)
+
authorized_size = IntCol(
dbName='authorized_size', notNull=False, default=2048)
@@ -1286,6 +1290,13 @@
else:
return None
+ # If the target series is OBSOLETE and permit_obsolete_series_uploads
+ # is not set, reject.
+ if (
+ distroseries.status == SeriesStatus.OBSOLETE and
+ not self.permit_obsolete_series_uploads):
+ return CannotUploadToSeries(distroseries)
+
# Users with pocket upload permissions may upload to anything in the
# given pocket.
if pocket is not None and self.checkArchivePermission(person, pocket):
=== modified file 'lib/lp/soyuz/model/buildpackagejob.py'
--- lib/lp/soyuz/model/buildpackagejob.py 2013-01-30 01:41:33 +0000
+++ lib/lp/soyuz/model/buildpackagejob.py 2013-05-24 01:51:31 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
__metaclass__ = type
@@ -19,6 +19,7 @@
from lp.buildmaster.interfaces.builder import IBuilderSet
from lp.buildmaster.model.buildfarmjob import BuildFarmJobOld
from lp.registry.interfaces.pocket import PackagePublishingPocket
+from lp.registry.interfaces.series import SeriesStatus
from lp.services.database.bulk import load_related
from lp.services.database.lpstorm import IStore
from lp.services.database.sqlbase import sqlvalues
@@ -222,17 +223,21 @@
def postprocessCandidate(job, logger):
"""See `IBuildFarmJob`."""
# Mark build records targeted to old source versions as SUPERSEDED
- # and build records target to SECURITY pocket as FAILEDTOBUILD.
+ # and build records target to SECURITY pocket or against an OBSOLETE
+ # distroseries without a flag as FAILEDTOBUILD.
# Builds in those situation should not be built because they will
# be wasting build-time. In the former case, there is already a
# newer source; the latter case needs an overhaul of the way
# security builds are handled (by copying from a PPA) to avoid
# creating duplicate builds.
- build_set = getUtility(IBinaryPackageBuildSet)
-
- build = build_set.getByQueueEntry(job)
- if build.pocket == PackagePublishingPocket.SECURITY:
- # We never build anything in the security pocket.
+ build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
+ distroseries = build.distro_arch_series.distroseries
+ if (
+ build.pocket == PackagePublishingPocket.SECURITY or
+ (distroseries.status == SeriesStatus.OBSOLETE and
+ not build.archive.permit_obsolete_series_uploads)):
+ # We never build anything in the security pocket, or for obsolete
+ # series without the flag set.
logger.debug(
"Build %s FAILEDTOBUILD, queue item %s REMOVED"
% (build.id, job.id))
=== modified file 'lib/lp/soyuz/tests/test_archive.py'
--- lib/lp/soyuz/tests/test_archive.py 2013-05-10 05:30:11 +0000
+++ lib/lp/soyuz/tests/test_archive.py 2013-05-24 01:51:31 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Test Archive features."""
@@ -59,6 +59,7 @@
CannotCopy,
CannotUploadToPocket,
CannotUploadToPPA,
+ CannotUploadToSeries,
IArchiveSet,
InsufficientUploadRights,
InvalidPocketForPartnerArchive,
@@ -783,10 +784,26 @@
# can upload basically whatever they want to that component, even if
# the package doesn't exist yet.
archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
- person, component = self.makePersonWithComponentPermission(
- archive)
+ person, component = self.makePersonWithComponentPermission(archive)
self.assertCanUpload(archive, person, None, component=component)
+ def test_checkUpload_obsolete_series(self):
+ distroseries = self.factory.makeDistroSeries(
+ status=SeriesStatus.OBSOLETE)
+ self.assertCannotUpload(
+ CannotUploadToSeries, distroseries.distribution.main_archive,
+ self.factory.makePerson(), None, distroseries=distroseries)
+
+ def test_checkUpload_obsolete_series_with_flag(self):
+ distroseries = self.factory.makeDistroSeries(
+ status=SeriesStatus.OBSOLETE)
+ archive = distroseries.distribution.main_archive
+ person, component = self.makePersonWithComponentPermission(archive)
+ removeSecurityProxy(archive).permit_obsolete_series_uploads = True
+ self.assertCanUpload(
+ archive, person, None, distroseries=distroseries,
+ component=component)
+
def makePackageToUpload(self, distroseries):
sourcepackagename = self.factory.makeSourcePackageName()
return self.factory.makeSuiteSourcePackage(
=== modified file 'lib/lp/soyuz/tests/test_buildpackagejob.py'
--- lib/lp/soyuz/tests/test_buildpackagejob.py 2013-01-22 02:00:27 +0000
+++ lib/lp/soyuz/tests/test_buildpackagejob.py 2013-05-24 01:51:31 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Test BuildQueue features."""
@@ -13,17 +13,20 @@
from lp.buildmaster.enums import BuildStatus
from lp.buildmaster.interfaces.builder import IBuilderSet
from lp.registry.interfaces.pocket import PackagePublishingPocket
+from lp.registry.interfaces.series import SeriesStatus
from lp.registry.interfaces.sourcepackage import SourcePackageUrgency
from lp.services.database.interfaces import (
DEFAULT_FLAVOR,
IStoreSelector,
MAIN_STORE,
)
+from lp.services.log.logger import DevNullLogger
from lp.services.webapp.interfaces import OAuthPermission
from lp.soyuz.enums import (
ArchivePurpose,
PackagePublishingStatus,
)
+from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet
from lp.soyuz.interfaces.buildfarmbuildjob import IBuildFarmBuildJob
from lp.soyuz.interfaces.buildpackagejob import (
COPY_ARCHIVE_SCORE_PENALTY,
@@ -34,6 +37,7 @@
SCORE_BY_URGENCY,
)
from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
+from lp.soyuz.model.buildpackagejob import BuildPackageJob
from lp.soyuz.model.processor import ProcessorFamilySet
from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
from lp.testing import (
@@ -475,3 +479,42 @@
with anonymous_logged_in():
self.assertScoreWriteableByTeam(
archive, getUtility(ILaunchpadCelebrities).commercial_admin)
+
+
+class TestBuildPackageJobPostProcess(TestCaseWithFactory):
+
+ layer = DatabaseFunctionalLayer
+
+ def makeBuildJob(self, pocket="RELEASE"):
+ build = self.factory.makeBinaryPackageBuild(pocket=pocket)
+ return build.queueBuild()
+
+ def test_release_job(self):
+ job = self.makeBuildJob()
+ build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
+ self.assertTrue(BuildPackageJob.postprocessCandidate(job, None))
+ self.assertEqual(BuildStatus.NEEDSBUILD, build.status)
+
+ def test_security_job_is_failed(self):
+ job = self.makeBuildJob(pocket="SECURITY")
+ build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
+ BuildPackageJob.postprocessCandidate(job, DevNullLogger())
+ self.assertEqual(BuildStatus.FAILEDTOBUILD, build.status)
+
+ def test_obsolete_job_without_flag_is_failed(self):
+ job = self.makeBuildJob()
+ build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
+ distroseries = build.distro_arch_series.distroseries
+ removeSecurityProxy(distroseries).status = SeriesStatus.OBSOLETE
+ BuildPackageJob.postprocessCandidate(job, DevNullLogger())
+ self.assertEqual(BuildStatus.FAILEDTOBUILD, build.status)
+
+ def test_obsolete_job_with_flag_is_not_failed(self):
+ job = self.makeBuildJob()
+ build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job)
+ distroseries = build.distro_arch_series.distroseries
+ archive = build.archive
+ removeSecurityProxy(distroseries).status = SeriesStatus.OBSOLETE
+ removeSecurityProxy(archive).permit_obsolete_series_uploads = True
+ BuildPackageJob.postprocessCandidate(job, DevNullLogger())
+ self.assertEqual(BuildStatus.NEEDSBUILD, build.status)