Merge ~cjwatson/launchpad:fix-cibuild-deletion into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 5721a104512416403b09eaf7bc25d252ba04d86a
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:fix-cibuild-deletion
Merge into: launchpad:master
Diff against target: 116 lines (+49/-3)
2 files modified
lib/lp/code/model/cibuild.py (+32/-3)
lib/lp/code/model/tests/test_cibuild.py (+17/-0)
Reviewer Review Type Date Requested Status
Jürgen Gmach Approve
Review via email: mp+427772@code.launchpad.net

Commit message

Fix CI build deletion when deleting a Git repository

Description of the change

We need to delete associated `BuildQueue` and `BuildFarmJob` rows as well, otherwise various things break if there happens to be a running CI build for a repository that's being deleted.

To post a comment you must log in.
Revision history for this message
Jürgen Gmach (jugmac00) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/lib/lp/code/model/cibuild.py b/lib/lp/code/model/cibuild.py
index e65493d..7adcc0e 100644
--- a/lib/lp/code/model/cibuild.py
+++ b/lib/lp/code/model/cibuild.py
@@ -29,7 +29,11 @@ from lp.buildmaster.enums import (
29)29)
30from lp.buildmaster.interfaces.builder import CannotBuild30from lp.buildmaster.interfaces.builder import CannotBuild
31from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSource31from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSource
32from lp.buildmaster.model.buildfarmjob import SpecificBuildFarmJobSourceMixin32from lp.buildmaster.model.buildfarmjob import (
33 BuildFarmJob,
34 SpecificBuildFarmJobSourceMixin,
35)
36from lp.buildmaster.model.buildqueue import BuildQueue
33from lp.buildmaster.model.packagebuild import PackageBuildMixin37from lp.buildmaster.model.packagebuild import PackageBuildMixin
34from lp.code.errors import GitRepositoryBlobNotFound, GitRepositoryScanFault38from lp.code.errors import GitRepositoryBlobNotFound, GitRepositoryScanFault
35from lp.code.interfaces.cibuild import (39from lp.code.interfaces.cibuild import (
@@ -594,11 +598,18 @@ class CIBuildSet(SpecificBuildFarmJobSourceMixin):
594 store.flush()598 store.flush()
595 return cibuild599 return cibuild
596600
597 def findByGitRepository(self, git_repository, commit_sha1s=None):601 def _findByGitRepositoryClauses(self, git_repository, commit_sha1s=None):
598 """See `ICIBuildSet`."""602 """Return a list of Storm clauses to find builds for a repository."""
599 clauses = [CIBuild.git_repository == git_repository]603 clauses = [CIBuild.git_repository == git_repository]
600 if commit_sha1s is not None:604 if commit_sha1s is not None:
601 clauses.append(CIBuild.commit_sha1.is_in(commit_sha1s))605 clauses.append(CIBuild.commit_sha1.is_in(commit_sha1s))
606 return clauses
607
608 def findByGitRepository(self, git_repository, commit_sha1s=None):
609 """See `ICIBuildSet`."""
610 clauses = self._findByGitRepositoryClauses(
611 git_repository, commit_sha1s=commit_sha1s
612 )
602 return IStore(CIBuild).find(CIBuild, *clauses)613 return IStore(CIBuild).find(CIBuild, *clauses)
603614
604 def _isBuildableArchitectureAllowed(self, das):615 def _isBuildableArchitectureAllowed(self, das):
@@ -759,7 +770,25 @@ class CIBuildSet(SpecificBuildFarmJobSourceMixin):
759770
760 def deleteByGitRepository(self, git_repository):771 def deleteByGitRepository(self, git_repository):
761 """See `ICIBuildSet`."""772 """See `ICIBuildSet`."""
773 # Remove build jobs. There won't be many queued builds, so we can
774 # afford to do this the safe but slow way via BuildQueue.destroySelf
775 # rather than in bulk.
776 build_clauses = self._findByGitRepositoryClauses(git_repository)
777 store = IStore(CIBuild)
778 buildqueue_records = store.find(
779 BuildQueue,
780 BuildQueue._build_farm_job_id == CIBuild.build_farm_job_id,
781 *build_clauses,
782 )
783 for buildqueue_record in buildqueue_records:
784 buildqueue_record.destroySelf()
785 build_farm_job_ids = list(
786 store.find(CIBuild.build_farm_job_id, *build_clauses)
787 )
762 self.findByGitRepository(git_repository).remove()788 self.findByGitRepository(git_repository).remove()
789 store.find(
790 BuildFarmJob, BuildFarmJob.id.is_in(build_farm_job_ids)
791 ).remove()
763792
764793
765@implementer(IMacaroonIssuer)794@implementer(IMacaroonIssuer)
diff --git a/lib/lp/code/model/tests/test_cibuild.py b/lib/lp/code/model/tests/test_cibuild.py
index a72e744..8f555a1 100644
--- a/lib/lp/code/model/tests/test_cibuild.py
+++ b/lib/lp/code/model/tests/test_cibuild.py
@@ -32,6 +32,7 @@ from lp.buildmaster.enums import BuildQueueStatus, BuildStatus
32from lp.buildmaster.interfaces.buildqueue import IBuildQueue32from lp.buildmaster.interfaces.buildqueue import IBuildQueue
33from lp.buildmaster.interfaces.packagebuild import IPackageBuild33from lp.buildmaster.interfaces.packagebuild import IPackageBuild
34from lp.buildmaster.interfaces.processor import IProcessorSet34from lp.buildmaster.interfaces.processor import IProcessorSet
35from lp.buildmaster.model.buildfarmjob import BuildFarmJob
35from lp.buildmaster.model.buildqueue import BuildQueue36from lp.buildmaster.model.buildqueue import BuildQueue
36from lp.code.errors import GitRepositoryBlobNotFound, GitRepositoryScanFault37from lp.code.errors import GitRepositoryBlobNotFound, GitRepositoryScanFault
37from lp.code.interfaces.cibuild import (38from lp.code.interfaces.cibuild import (
@@ -54,6 +55,7 @@ from lp.registry.interfaces.series import SeriesStatus
54from lp.registry.interfaces.sourcepackage import SourcePackageType55from lp.registry.interfaces.sourcepackage import SourcePackageType
55from lp.services.authserver.xmlrpc import AuthServerAPIView56from lp.services.authserver.xmlrpc import AuthServerAPIView
56from lp.services.config import config57from lp.services.config import config
58from lp.services.database.sqlbase import flush_database_caches
57from lp.services.librarian.browser import ProxiedLibraryFileAlias59from lp.services.librarian.browser import ProxiedLibraryFileAlias
58from lp.services.log.logger import BufferLogger60from lp.services.log.logger import BufferLogger
59from lp.services.macaroons.interfaces import IMacaroonIssuer61from lp.services.macaroons.interfaces import IMacaroonIssuer
@@ -1158,16 +1160,31 @@ class TestCIBuildSet(TestCaseWithFactory):
1158 builds.extend(1160 builds.extend(
1159 [self.factory.makeCIBuild(repository) for _ in range(2)]1161 [self.factory.makeCIBuild(repository) for _ in range(2)]
1160 )1162 )
1163 build_queue = builds[0].queueBuild()
1164 other_build = self.factory.makeCIBuild()
1165 other_build.queueBuild()
1166 store = Store.of(builds[0])
1167 store.flush()
1168 build_queue_id = build_queue.id
1169 build_farm_job_id = removeSecurityProxy(builds[0]).build_farm_job_id
1161 ci_build_set = getUtility(ICIBuildSet)1170 ci_build_set = getUtility(ICIBuildSet)
11621171
1163 ci_build_set.deleteByGitRepository(repositories[0])1172 ci_build_set.deleteByGitRepository(repositories[0])
11641173
1174 flush_database_caches()
1175 # The deleted CI builds are gone.
1165 self.assertContentEqual(1176 self.assertContentEqual(
1166 [], ci_build_set.findByGitRepository(repositories[0])1177 [], ci_build_set.findByGitRepository(repositories[0])
1167 )1178 )
1168 self.assertContentEqual(1179 self.assertContentEqual(
1169 builds[2:], ci_build_set.findByGitRepository(repositories[1])1180 builds[2:], ci_build_set.findByGitRepository(repositories[1])
1170 )1181 )
1182 self.assertIsNone(store.get(BuildQueue, build_queue_id))
1183 self.assertIsNone(store.get(BuildFarmJob, build_farm_job_id))
1184 # Unrelated CI builds are still present.
1185 clear_property_cache(other_build)
1186 self.assertEqual(other_build, ci_build_set.getByID(other_build.id))
1187 self.assertIsNotNone(other_build.buildqueue_record)
11711188
11721189
1173class TestDetermineDASesToBuild(TestCaseWithFactory):1190class TestDetermineDASesToBuild(TestCaseWithFactory):

Subscribers

People subscribed via source and target branches

to status/vote changes: