launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #23053
[Merge] lp:~cjwatson/launchpad/snap-delete-with-build-requests into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/snap-delete-with-build-requests into lp:launchpad.
Commit message:
Delete associated build requests when deleting a snap.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1802089 in Launchpad itself: "OOPS when deleting snap build with snap jobs"
https://bugs.launchpad.net/launchpad/+bug/1802089
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/snap-delete-with-build-requests/+merge/358440
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/snap-delete-with-build-requests into lp:launchpad.
=== modified file 'lib/lp/snappy/model/snap.py'
--- lib/lp/snappy/model/snap.py 2018-10-09 09:25:19 +0000
+++ lib/lp/snappy/model/snap.py 2018-11-07 15:02:24 +0000
@@ -50,10 +50,7 @@
DateTimeFormatterAPI,
)
from lp.app.enums import PRIVATE_INFORMATION_TYPES
-from lp.app.errors import (
- IncompatibleArguments,
- NotFoundError,
- )
+from lp.app.errors import IncompatibleArguments
from lp.app.interfaces.security import IAuthorization
from lp.buildmaster.enums import BuildStatus
from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet
@@ -117,6 +114,7 @@
)
from lp.services.features import getFeatureFlag
from lp.services.job.interfaces.job import JobStatus
+from lp.services.job.model.job import Job
from lp.services.librarian.model import (
LibraryFileAlias,
LibraryFileContent,
@@ -162,6 +160,7 @@
from lp.snappy.interfaces.snappyseries import ISnappyDistroSeriesSet
from lp.snappy.interfaces.snapstoreclient import ISnapStoreClient
from lp.snappy.model.snapbuild import SnapBuild
+from lp.snappy.model.snapjob import SnapJob
from lp.soyuz.interfaces.archive import ArchiveDisabled
from lp.soyuz.model.archive import (
Archive,
@@ -879,6 +878,9 @@
SnapBuild.snap = ?
""", (self.id,))
store.find(SnapBuild, SnapBuild.snap == self).remove()
+ affected_jobs = Select(
+ [SnapJob.job_id], And(SnapJob.job == Job.id, SnapJob.snap == self))
+ store.find(Job, Job.id.is_in(affected_jobs)).remove()
getUtility(IWebhookSet).delete(self.webhooks)
store.remove(self)
store.find(
=== modified file 'lib/lp/snappy/tests/test_snap.py'
--- lib/lp/snappy/tests/test_snap.py 2018-10-09 09:25:19 +0000
+++ lib/lp/snappy/tests/test_snap.py 2018-11-07 15:02:24 +0000
@@ -111,6 +111,7 @@
from lp.snappy.model.snap import SnapSet
from lp.snappy.model.snapbuild import SnapFile
from lp.snappy.model.snapbuildjob import SnapBuildJob
+from lp.snappy.model.snapjob import SnapJob
from lp.testing import (
admin_logged_in,
ANONYMOUS,
@@ -961,6 +962,65 @@
other_build, getUtility(ISnapBuildSet).getByID(other_build.id))
self.assertIsNotNone(other_build.buildqueue_record)
+ def test_delete_with_build_requests(self):
+ # A snap package with build requests can be deleted.
+ owner = self.factory.makePerson()
+ distroseries = self.factory.makeDistroSeries()
+ processor = self.factory.makeProcessor(supports_virtualized=True)
+ das = self.factory.makeDistroArchSeries(
+ distroseries=distroseries, architecturetag=processor.name,
+ processor=processor)
+ das.addOrUpdateChroot(
+ self.factory.makeLibraryFileAlias(
+ filename="fake_chroot.tar.gz", db_only=True))
+ self.useFixture(GitHostingFixture(blob=dedent("""\
+ architectures:
+ - build-on: %s
+ """ % processor.name)))
+ [git_ref] = self.factory.makeGitRefs()
+ condemned_snap = self.factory.makeSnap(
+ registrant=owner, owner=owner, distroseries=distroseries,
+ name="condemned", git_ref=git_ref)
+ other_snap = self.factory.makeSnap(
+ registrant=owner, owner=owner, distroseries=distroseries,
+ git_ref=git_ref)
+ self.assertTrue(getUtility(ISnapSet).exists(owner, "condemned"))
+ with person_logged_in(owner):
+ requests = []
+ jobs = []
+ for snap in (condemned_snap, other_snap):
+ requests.append(snap.requestBuilds(
+ owner, distroseries.main_archive,
+ PackagePublishingPocket.UPDATES))
+ jobs.append(removeSecurityProxy(requests[-1])._job)
+ with dbuser(config.ISnapRequestBuildsJobSource.dbuser):
+ JobRunner(jobs).runAll()
+ for job in jobs:
+ self.assertEqual(JobStatus.COMPLETED, job.job.status)
+ for request in requests:
+ self.assertNotEqual([], request.builds)
+ store = Store.of(condemned_snap)
+ store.flush()
+ job_ids = [job.job_id for job in jobs]
+ build_ids = [
+ [build.id for build in request.builds] for request in requests]
+ with person_logged_in(condemned_snap.owner):
+ condemned_snap.destroySelf()
+ flush_database_caches()
+ # The deleted snap, its build requests, and its builds are gone.
+ self.assertFalse(getUtility(ISnapSet).exists(owner, "condemned"))
+ self.assertIsNone(store.get(SnapJob, job_ids[0]))
+ for build_id in build_ids[0]:
+ self.assertIsNone(getUtility(ISnapBuildSet).getByID(build_id))
+ # Unrelated build requests and builds are still present.
+ self.assertEqual(
+ removeSecurityProxy(jobs[1]).context,
+ store.get(SnapJob, job_ids[1]))
+ other_builds = [
+ getUtility(ISnapBuildSet).getByID(build_id)
+ for build_id in build_ids[1]]
+ self.assertEqual(list(requests[1].builds), other_builds)
+
def test_related_webhooks_deleted(self):
owner = self.factory.makePerson()
snap = self.factory.makeSnap(registrant=owner, owner=owner)
Follow ups