Merge ~cjwatson/launchpad:stormify-branchmergeproposal into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: b6f4d067affc49737c6f4b0cbee3c8d55f56f1a5
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:stormify-branchmergeproposal
Merge into: launchpad:master
Diff against target: 817 lines (+204/-142)
9 files modified
lib/lp/code/interfaces/branchmergeproposal.py (+4/-4)
lib/lp/code/mail/codehandler.py (+5/-5)
lib/lp/code/model/branch.py (+14/-10)
lib/lp/code/model/branchcollection.py (+11/-7)
lib/lp/code/model/branchmergeproposal.py (+138/-93)
lib/lp/code/model/gitcollection.py (+6/-5)
lib/lp/code/model/gitrepository.py (+5/-5)
lib/lp/code/model/tests/test_branch.py (+9/-6)
lib/lp/code/model/tests/test_gitrepository.py (+12/-7)
Reviewer Review Type Date Requested Status
Guruprasad Approve
Review via email: mp+446309@code.launchpad.net

Commit message

Convert BranchMergeProposal to Storm

To post a comment you must log in.
Revision history for this message
Guruprasad (lgp171188) wrote :

LGTM 👍

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/interfaces/branchmergeproposal.py b/lib/lp/code/interfaces/branchmergeproposal.py
index 20b4ceb..e65eef6 100644
--- a/lib/lp/code/interfaces/branchmergeproposal.py
+++ b/lib/lp/code/interfaces/branchmergeproposal.py
@@ -93,16 +93,16 @@ class IBranchMergeProposalPublic(IPrivacy):
93 readonly=True,93 readonly=True,
94 description=_("The tracking number for this merge proposal."),94 description=_("The tracking number for this merge proposal."),
95 )95 )
96 source_branchID = Int(96 source_branch_id = Int(
97 title=_("Source branch ID"), required=False, readonly=True97 title=_("Source branch ID"), required=False, readonly=True
98 )98 )
99 source_git_repositoryID = Int(99 source_git_repository_id = Int(
100 title=_("Source Git repository ID"), required=False, readonly=True100 title=_("Source Git repository ID"), required=False, readonly=True
101 )101 )
102 prerequisite_branchID = Int(102 prerequisite_branch_id = Int(
103 title=_("Prerequisite branch ID"), required=False, readonly=True103 title=_("Prerequisite branch ID"), required=False, readonly=True
104 )104 )
105 prerequisite_git_repositoryID = Int(105 prerequisite_git_repository_id = Int(
106 title=_("Prerequisite Git repository ID"),106 title=_("Prerequisite Git repository ID"),
107 required=False,107 required=False,
108 readonly=True,108 readonly=True,
diff --git a/lib/lp/code/mail/codehandler.py b/lib/lp/code/mail/codehandler.py
index 7a8a3f0..6eb574a 100644
--- a/lib/lp/code/mail/codehandler.py
+++ b/lib/lp/code/mail/codehandler.py
@@ -10,12 +10,12 @@ from zope.component import getUtility
10from zope.interface import implementer10from zope.interface import implementer
11from zope.security.interfaces import Unauthorized11from zope.security.interfaces import Unauthorized
1212
13from lp.app.errors import NotFoundError
13from lp.code.adapters.branch import BranchMergeProposalNoPreviewDiffDelta14from lp.code.adapters.branch import BranchMergeProposalNoPreviewDiffDelta
14from lp.code.enums import CodeReviewVote15from lp.code.enums import CodeReviewVote
15from lp.code.errors import UserNotBranchReviewer16from lp.code.errors import UserNotBranchReviewer
16from lp.code.interfaces.branchmergeproposal import IBranchMergeProposalGetter17from lp.code.interfaces.branchmergeproposal import IBranchMergeProposalGetter
17from lp.services.config import config18from lp.services.config import config
18from lp.services.database.sqlobject import SQLObjectNotFound
19from lp.services.mail.commands import EmailCommand, EmailCommandCollection19from lp.services.mail.commands import EmailCommand, EmailCommandCollection
20from lp.services.mail.helpers import (20from lp.services.mail.helpers import (
21 IncomingEmailError,21 IncomingEmailError,
@@ -42,7 +42,7 @@ class InvalidBranchMergeProposalAddress(BadBranchMergeProposalAddress):
42 """The user-supplied address is not an acceptable value."""42 """The user-supplied address is not an acceptable value."""
4343
4444
45class NonExistantBranchMergeProposalAddress(BadBranchMergeProposalAddress):45class NonExistentBranchMergeProposalAddress(BadBranchMergeProposalAddress):
46 """The BranchMergeProposal specified by the address does not exist."""46 """The BranchMergeProposal specified by the address does not exist."""
4747
4848
@@ -310,7 +310,7 @@ class CodeHandler:
310 user = getUtility(ILaunchBag).user310 user = getUtility(ILaunchBag).user
311 try:311 try:
312 merge_proposal = self.getBranchMergeProposal(email_addr)312 merge_proposal = self.getBranchMergeProposal(email_addr)
313 except NonExistantBranchMergeProposalAddress:313 except NonExistentBranchMergeProposalAddress:
314 send_process_error_notification(314 send_process_error_notification(
315 str(user.preferredemail.email),315 str(user.preferredemail.email),
316 "Submit Request Failure",316 "Submit Request Failure",
@@ -375,5 +375,5 @@ class CodeHandler:
375 getter = getUtility(IBranchMergeProposalGetter)375 getter = getUtility(IBranchMergeProposalGetter)
376 try:376 try:
377 return getter.get(merge_proposal_id)377 return getter.get(merge_proposal_id)
378 except SQLObjectNotFound:378 except NotFoundError:
379 raise NonExistantBranchMergeProposalAddress(email_addr)379 raise NonExistentBranchMergeProposalAddress(email_addr)
diff --git a/lib/lp/code/model/branch.py b/lib/lp/code/model/branch.py
index b9cfedc..b9f9b5f 100644
--- a/lib/lp/code/model/branch.py
+++ b/lib/lp/code/model/branch.py
@@ -134,7 +134,7 @@ from lp.services.database.datetimecol import UtcDateTimeCol
134from lp.services.database.decoratedresultset import DecoratedResultSet134from lp.services.database.decoratedresultset import DecoratedResultSet
135from lp.services.database.enumcol import DBEnum135from lp.services.database.enumcol import DBEnum
136from lp.services.database.interfaces import IPrimaryStore, IStore136from lp.services.database.interfaces import IPrimaryStore, IStore
137from lp.services.database.sqlbase import SQLBase, sqlvalues137from lp.services.database.sqlbase import SQLBase
138from lp.services.database.sqlobject import ForeignKey, IntCol, StringCol138from lp.services.database.sqlobject import ForeignKey, IntCol, StringCol
139from lp.services.database.stormexpr import Array, ArrayAgg, ArrayIntersects139from lp.services.database.stormexpr import Array, ArrayAgg, ArrayIntersects
140from lp.services.helpers import shortlist140from lp.services.helpers import shortlist
@@ -559,12 +559,14 @@ class Branch(SQLBase, WebhookTargetMixin, BzrIdentityMixin):
559 @property559 @property
560 def dependent_branches(self):560 def dependent_branches(self):
561 """See `IBranch`."""561 """See `IBranch`."""
562 return BranchMergeProposal.select(562 return Store.of(self).find(
563 """563 BranchMergeProposal,
564 BranchMergeProposal.dependent_branch = %s AND564 BranchMergeProposal.prerequisite_branch == self,
565 BranchMergeProposal.queue_status NOT IN %s565 Not(
566 """566 BranchMergeProposal.queue_status.is_in(
567 % sqlvalues(self, BRANCH_MERGE_PROPOSAL_FINAL_STATES)567 BRANCH_MERGE_PROPOSAL_FINAL_STATES
568 )
569 ),
568 )570 )
569571
570 def getMergeProposals(572 def getMergeProposals(
@@ -942,7 +944,9 @@ class Branch(SQLBase, WebhookTargetMixin, BzrIdentityMixin):
942 )944 )
943 # Cannot use self.landing_candidates, because it ignores merged945 # Cannot use self.landing_candidates, because it ignores merged
944 # merge proposals.946 # merge proposals.
945 for merge_proposal in BranchMergeProposal.selectBy(target_branch=self):947 for merge_proposal in Store.of(self).find(
948 BranchMergeProposal, target_branch=self
949 ):
946 deletion_operations.append(950 deletion_operations.append(
947 DeletionCallable(951 DeletionCallable(
948 merge_proposal,952 merge_proposal,
@@ -953,8 +957,8 @@ class Branch(SQLBase, WebhookTargetMixin, BzrIdentityMixin):
953 merge_proposal.deleteProposal,957 merge_proposal.deleteProposal,
954 )958 )
955 )959 )
956 for merge_proposal in BranchMergeProposal.selectBy(960 for merge_proposal in Store.of(self).find(
957 prerequisite_branch=self961 BranchMergeProposal, prerequisite_branch=self
958 ):962 ):
959 alteration_operations.append(ClearDependentBranch(merge_proposal))963 alteration_operations.append(ClearDependentBranch(merge_proposal))
960964
diff --git a/lib/lp/code/model/branchcollection.py b/lib/lp/code/model/branchcollection.py
index 8ffbb63..55cbb0c 100644
--- a/lib/lp/code/model/branchcollection.py
+++ b/lib/lp/code/model/branchcollection.py
@@ -431,14 +431,16 @@ class GenericBranchCollection:
431 Join(431 Join(
432 BranchMergeProposal,432 BranchMergeProposal,
433 And(433 And(
434 Branch.id == BranchMergeProposal.source_branchID,434 Branch.id == BranchMergeProposal.source_branch_id,
435 *(435 *(
436 self._branch_filter_expressions436 self._branch_filter_expressions
437 + self._asymmetric_filter_expressions437 + self._asymmetric_filter_expressions
438 ),438 ),
439 ),439 ),
440 ),440 ),
441 Join(Target, Target.id == BranchMergeProposal.target_branchID),441 Join(
442 Target, Target.id == BranchMergeProposal.target_branch_id
443 ),
442 ]444 ]
443 )445 )
444 expressions = self._getBranchVisibilityExpression()446 expressions = self._getBranchVisibilityExpression()
@@ -446,7 +448,7 @@ class GenericBranchCollection:
446 if for_branches is not None:448 if for_branches is not None:
447 branch_ids = [branch.id for branch in for_branches]449 branch_ids = [branch.id for branch in for_branches]
448 expressions.append(450 expressions.append(
449 BranchMergeProposal.source_branchID.is_in(branch_ids)451 BranchMergeProposal.source_branch_id.is_in(branch_ids)
450 )452 )
451 if target_branch is not None:453 if target_branch is not None:
452 expressions.append(454 expressions.append(
@@ -467,7 +469,7 @@ class GenericBranchCollection:
467 == BranchRevision.sequence,469 == BranchRevision.sequence,
468 BranchRevision.revision_id == Revision.id,470 BranchRevision.revision_id == Revision.id,
469 BranchRevision.branch_id471 BranchRevision.branch_id
470 == BranchMergeProposal.target_branchID,472 == BranchMergeProposal.target_branch_id,
471 Revision.revision_id == merged_revision,473 Revision.revision_id == merged_revision,
472 ]474 ]
473 )475 )
@@ -512,7 +514,7 @@ class GenericBranchCollection:
512 # Need to filter on Branch beyond the with constraints.514 # Need to filter on Branch beyond the with constraints.
513 expressions += self._asymmetric_filter_expressions515 expressions += self._asymmetric_filter_expressions
514 expressions.append(516 expressions.append(
515 BranchMergeProposal.source_branchID == Branch.id517 BranchMergeProposal.source_branch_id == Branch.id
516 )518 )
517 tables.append(Branch)519 tables.append(Branch)
518 tables.extend(self._asymmetric_tables.values())520 tables.extend(self._asymmetric_tables.values())
@@ -568,12 +570,14 @@ class GenericBranchCollection:
568570
569 expressions = [571 expressions = [
570 CodeReviewVoteReference.reviewer == reviewer,572 CodeReviewVoteReference.reviewer == reviewer,
571 BranchMergeProposal.source_branchID.is_in(self._getBranchSelect()),573 BranchMergeProposal.source_branch_id.is_in(
574 self._getBranchSelect()
575 ),
572 ]576 ]
573 visibility = self._getBranchVisibilityExpression()577 visibility = self._getBranchVisibilityExpression()
574 if visibility:578 if visibility:
575 expressions.append(579 expressions.append(
576 BranchMergeProposal.target_branchID.is_in(580 BranchMergeProposal.target_branch_id.is_in(
577 Select(Branch.id, visibility)581 Select(Branch.id, visibility)
578 )582 )
579 )583 )
diff --git a/lib/lp/code/model/branchmergeproposal.py b/lib/lp/code/model/branchmergeproposal.py
index bf927c8..7fb2176 100644
--- a/lib/lp/code/model/branchmergeproposal.py
+++ b/lib/lp/code/model/branchmergeproposal.py
@@ -11,12 +11,13 @@ __all__ = [
1111
12import sys12import sys
13from collections import defaultdict13from collections import defaultdict
14from datetime import timezone
14from email.utils import make_msgid15from email.utils import make_msgid
15from operator import attrgetter16from operator import attrgetter
1617
17from lazr.lifecycle.event import ObjectCreatedEvent, ObjectDeletedEvent18from lazr.lifecycle.event import ObjectCreatedEvent, ObjectDeletedEvent
18from storm.expr import SQL, And, Desc, Join, LeftJoin, Not, Or, Select19from storm.expr import SQL, And, Desc, Join, LeftJoin, Not, Or, Select
19from storm.locals import Int, Reference20from storm.locals import DateTime, Int, Reference, Unicode
20from storm.store import Store21from storm.store import Store
21from zope.component import getUtility22from zope.component import getUtility
22from zope.error.interfaces import IErrorReportingUtility23from zope.error.interfaces import IErrorReportingUtility
@@ -82,11 +83,10 @@ from lp.registry.model.person import Person
82from lp.services.config import config83from lp.services.config import config
83from lp.services.database.bulk import load, load_referencing, load_related84from lp.services.database.bulk import load, load_referencing, load_related
84from lp.services.database.constants import DEFAULT, UTC_NOW85from lp.services.database.constants import DEFAULT, UTC_NOW
85from lp.services.database.datetimecol import UtcDateTimeCol
86from lp.services.database.enumcol import DBEnum86from lp.services.database.enumcol import DBEnum
87from lp.services.database.interfaces import IPrimaryStore, IStore87from lp.services.database.interfaces import IPrimaryStore, IStore
88from lp.services.database.sqlbase import SQLBase, quote88from lp.services.database.sqlbase import quote
89from lp.services.database.sqlobject import ForeignKey, IntCol, StringCol89from lp.services.database.stormbase import StormBase
90from lp.services.helpers import shortlist90from lp.services.helpers import shortlist
91from lp.services.job.interfaces.job import JobStatus91from lp.services.job.interfaces.job import JobStatus
92from lp.services.job.model.job import Job92from lp.services.job.model.job import Job
@@ -160,65 +160,62 @@ class TooManyRelatedBugs(Exception):
160160
161161
162@implementer(IBranchMergeProposal, IHasBranchTarget)162@implementer(IBranchMergeProposal, IHasBranchTarget)
163class BranchMergeProposal(SQLBase, BugLinkTargetMixin):163class BranchMergeProposal(StormBase, BugLinkTargetMixin):
164 """A relationship between a person and a branch."""164 """A relationship between a person and a branch."""
165165
166 _table = "BranchMergeProposal"166 __storm_table__ = "BranchMergeProposal"
167 _defaultOrder = ["-date_created", "id"]167 __storm_order__ = ("-date_created", "id")
168168
169 registrant = ForeignKey(169 id = Int(primary=True)
170 dbName="registrant",
171 foreignKey="Person",
172 storm_validator=validate_public_person,
173 notNull=True,
174 )
175170
176 source_branch = ForeignKey(171 registrant_id = Int(
177 dbName="source_branch", foreignKey="Branch", notNull=False172 name="registrant", validator=validate_public_person, allow_none=False
178 )173 )
179 source_git_repositoryID = Int(174 registrant = Reference(registrant_id, "Person.id")
175
176 source_branch_id = Int(name="source_branch", allow_none=True)
177 source_branch = Reference(source_branch_id, "Branch.id")
178 source_git_repository_id = Int(
180 name="source_git_repository", allow_none=True179 name="source_git_repository", allow_none=True
181 )180 )
182 source_git_repository = Reference(181 source_git_repository = Reference(
183 source_git_repositoryID, "GitRepository.id"182 source_git_repository_id, "GitRepository.id"
184 )183 )
185 source_git_path = StringCol(184 source_git_path = Unicode(
186 dbName="source_git_path", default=None, notNull=False185 name="source_git_path", default=None, allow_none=True
187 )186 )
188 source_git_commit_sha1 = StringCol(187 source_git_commit_sha1 = Unicode(
189 dbName="source_git_commit_sha1", default=None, notNull=False188 name="source_git_commit_sha1", default=None, allow_none=True
190 )189 )
191190
192 target_branch = ForeignKey(191 target_branch_id = Int(name="target_branch", allow_none=True)
193 dbName="target_branch", foreignKey="Branch", notNull=False192 target_branch = Reference(target_branch_id, "Branch.id")
194 )193 target_git_repository_id = Int(
195 target_git_repositoryID = Int(
196 name="target_git_repository", allow_none=True194 name="target_git_repository", allow_none=True
197 )195 )
198 target_git_repository = Reference(196 target_git_repository = Reference(
199 target_git_repositoryID, "GitRepository.id"197 target_git_repository_id, "GitRepository.id"
200 )198 )
201 target_git_path = StringCol(199 target_git_path = Unicode(
202 dbName="target_git_path", default=None, notNull=False200 name="target_git_path", default=None, allow_none=True
203 )201 )
204 target_git_commit_sha1 = StringCol(202 target_git_commit_sha1 = Unicode(
205 dbName="target_git_commit_sha1", default=None, notNull=False203 name="target_git_commit_sha1", default=None, allow_none=True
206 )204 )
207205
208 prerequisite_branch = ForeignKey(206 prerequisite_branch_id = Int(name="dependent_branch", allow_none=True)
209 dbName="dependent_branch", foreignKey="Branch", notNull=False207 prerequisite_branch = Reference(prerequisite_branch_id, "Branch.id")
210 )208 prerequisite_git_repository_id = Int(
211 prerequisite_git_repositoryID = Int(
212 name="dependent_git_repository", allow_none=True209 name="dependent_git_repository", allow_none=True
213 )210 )
214 prerequisite_git_repository = Reference(211 prerequisite_git_repository = Reference(
215 prerequisite_git_repositoryID, "GitRepository.id"212 prerequisite_git_repository_id, "GitRepository.id"
216 )213 )
217 prerequisite_git_path = StringCol(214 prerequisite_git_path = Unicode(
218 dbName="dependent_git_path", default=None, notNull=False215 name="dependent_git_path", default=None, allow_none=True
219 )216 )
220 prerequisite_git_commit_sha1 = StringCol(217 prerequisite_git_commit_sha1 = Unicode(
221 dbName="dependent_git_commit_sha1", default=None, notNull=False218 name="dependent_git_commit_sha1", default=None, allow_none=True
222 )219 )
223220
224 @property221 @property
@@ -303,9 +300,9 @@ class BranchMergeProposal(SQLBase, BugLinkTargetMixin):
303 else:300 else:
304 return self.source_git_repository301 return self.source_git_repository
305302
306 description = StringCol(default=None)303 description = Unicode(default=None)
307304
308 whiteboard = StringCol(default=None)305 whiteboard = Unicode(default=None)
309306
310 queue_status = DBEnum(307 queue_status = DBEnum(
311 enum=BranchMergeProposalStatus,308 enum=BranchMergeProposalStatus,
@@ -326,13 +323,13 @@ class BranchMergeProposal(SQLBase, BugLinkTargetMixin):
326 for obj in objects323 for obj in objects
327 )324 )
328325
329 reviewer = ForeignKey(326 reviewer_id = Int(
330 dbName="reviewer",327 name="reviewer",
331 foreignKey="Person",328 validator=validate_person,
332 storm_validator=validate_person,329 allow_none=True,
333 notNull=False,
334 default=None,330 default=None,
335 )331 )
332 reviewer = Reference(reviewer_id, "Person.id")
336333
337 @property334 @property
338 def next_preview_diff_job(self):335 def next_preview_diff_job(self):
@@ -356,13 +353,13 @@ class BranchMergeProposal(SQLBase, BugLinkTargetMixin):
356 else:353 else:
357 return None354 return None
358355
359 reviewed_revision_id = StringCol(default=None)356 reviewed_revision_id = Unicode(default=None)
360357
361 commit_message = StringCol(default=None)358 commit_message = Unicode(default=None)
362359
363 date_merged = UtcDateTimeCol(default=None)360 date_merged = DateTime(default=None, tzinfo=timezone.utc)
364 merged_revno = IntCol(default=None)361 merged_revno = Int(default=None)
365 merged_revision_id = StringCol(default=None)362 merged_revision_id = Unicode(default=None)
366363
367 @property364 @property
368 def merged_revision(self):365 def merged_revision(self):
@@ -372,13 +369,56 @@ class BranchMergeProposal(SQLBase, BugLinkTargetMixin):
372 else:369 else:
373 return self.merged_revision_id370 return self.merged_revision_id
374371
375 merge_reporter = ForeignKey(372 merge_reporter_id = Int(
376 dbName="merge_reporter",373 name="merge_reporter",
377 foreignKey="Person",374 validator=validate_public_person,
378 storm_validator=validate_public_person,375 allow_none=True,
379 notNull=False,
380 default=None,376 default=None,
381 )377 )
378 merge_reporter = Reference(merge_reporter_id, "Person.id")
379
380 def __init__(
381 self,
382 registrant,
383 source_branch=None,
384 source_git_repository=None,
385 source_git_path=None,
386 source_git_commit_sha1=None,
387 target_branch=None,
388 target_git_repository=None,
389 target_git_path=None,
390 target_git_commit_sha1=None,
391 prerequisite_branch=None,
392 prerequisite_git_repository=None,
393 prerequisite_git_path=None,
394 prerequisite_git_commit_sha1=None,
395 description=None,
396 whiteboard=None,
397 queue_status=DEFAULT,
398 commit_message=None,
399 date_created=DEFAULT,
400 date_review_requested=None,
401 ):
402 super().__init__()
403 self.registrant = registrant
404 self.source_branch = source_branch
405 self.source_git_repository = source_git_repository
406 self.source_git_path = source_git_path
407 self.source_git_commit_sha1 = source_git_commit_sha1
408 self.target_branch = target_branch
409 self.target_git_repository = target_git_repository
410 self.target_git_path = target_git_path
411 self.target_git_commit_sha1 = target_git_commit_sha1
412 self.prerequisite_branch = prerequisite_branch
413 self.prerequisite_git_repository = prerequisite_git_repository
414 self.prerequisite_git_path = prerequisite_git_path
415 self.prerequisite_git_commit_sha1 = prerequisite_git_commit_sha1
416 self.description = description
417 self.whiteboard = whiteboard
418 self.queue_status = queue_status
419 self.commit_message = commit_message
420 self.date_created = date_created
421 self.date_review_requested = date_review_requested
382422
383 @property423 @property
384 def bugs(self):424 def bugs(self):
@@ -557,22 +597,24 @@ class BranchMergeProposal(SQLBase, BugLinkTargetMixin):
557 def address(self):597 def address(self):
558 return "mp+%d@%s" % (self.id, config.launchpad.code_domain)598 return "mp+%d@%s" % (self.id, config.launchpad.code_domain)
559599
560 superseded_by = ForeignKey(600 superseded_by_id = Int(name="superseded_by", allow_none=True, default=None)
561 dbName="superseded_by",601 superseded_by = Reference(superseded_by_id, "BranchMergeProposal.id")
562 foreignKey="BranchMergeProposal",
563 notNull=False,
564 default=None,
565 )
566602
567 _supersedes = Reference("<primary key>", "superseded_by", on_remote=True)603 _supersedes = Reference("id", "superseded_by_id", on_remote=True)
568604
569 @cachedproperty605 @cachedproperty
570 def supersedes(self):606 def supersedes(self):
571 return self._supersedes607 return self._supersedes
572608
573 date_created = UtcDateTimeCol(notNull=True, default=DEFAULT)609 date_created = DateTime(
574 date_review_requested = UtcDateTimeCol(notNull=False, default=None)610 allow_none=False, default=DEFAULT, tzinfo=timezone.utc
575 date_reviewed = UtcDateTimeCol(notNull=False, default=None)611 )
612 date_review_requested = DateTime(
613 allow_none=True, default=None, tzinfo=timezone.utc
614 )
615 date_reviewed = DateTime(
616 allow_none=True, default=None, tzinfo=timezone.utc
617 )
576618
577 @property619 @property
578 def target(self):620 def target(self):
@@ -584,7 +626,7 @@ class BranchMergeProposal(SQLBase, BugLinkTargetMixin):
584 # although it has similar semantics.626 # although it has similar semantics.
585 return self.source_git_repository.namespace627 return self.source_git_repository.namespace
586628
587 root_message_id = StringCol(default=None)629 root_message_id = Unicode(default=None)
588630
589 @property631 @property
590 def title(self):632 def title(self):
@@ -923,10 +965,10 @@ class BranchMergeProposal(SQLBase, BugLinkTargetMixin):
923 self._transitionToState(965 self._transitionToState(
924 BranchMergeProposalStatus.SUPERSEDED, registrant966 BranchMergeProposalStatus.SUPERSEDED, registrant
925 )967 )
926 # This sync update is needed as the add landing target does968 # This flush is needed as the add landing target does a database
927 # a database query to identify if there are any active proposals969 # query to identify if there are any active proposals with the same
928 # with the same source and target branches.970 # source and target branches.
929 self.syncUpdate()971 Store.of(self).flush()
930 review_requests = list(972 review_requests = list(
931 {(vote.reviewer, vote.review_type) for vote in self.votes}973 {(vote.reviewer, vote.review_type) for vote in self.votes}
932 )974 )
@@ -941,10 +983,10 @@ class BranchMergeProposal(SQLBase, BugLinkTargetMixin):
941 )983 )
942 if not break_link:984 if not break_link:
943 self.superseded_by = proposal985 self.superseded_by = proposal
944 # This sync update is needed to ensure that the transitive986 # This flush is needed to ensure that the transitive properties of
945 # properties of supersedes and superseded_by are visible to987 # supersedes and superseded_by are visible to the old and the new
946 # the old and the new proposal.988 # proposal.
947 self.syncUpdate()989 Store.of(self).flush()
948 return proposal990 return proposal
949991
950 def _normalizeReviewType(self, review_type):992 def _normalizeReviewType(self, review_type):
@@ -1068,7 +1110,7 @@ class BranchMergeProposal(SQLBase, BugLinkTargetMixin):
1068 ):1110 ):
1069 job.destroySelf()1111 job.destroySelf()
1070 self._preview_diffs.remove()1112 self._preview_diffs.remove()
1071 self.destroySelf()1113 Store.of(self).remove(self)
10721114
1073 def getUnlandedSourceBranchRevisions(self):1115 def getUnlandedSourceBranchRevisions(self):
1074 """See `IBranchMergeProposal`."""1116 """See `IBranchMergeProposal`."""
@@ -1513,24 +1555,24 @@ class BranchMergeProposal(SQLBase, BugLinkTargetMixin):
1513 person_ids = set()1555 person_ids = set()
1514 for mp in branch_merge_proposals:1556 for mp in branch_merge_proposals:
1515 ids.add(mp.id)1557 ids.add(mp.id)
1516 if mp.source_branchID is not None:1558 if mp.source_branch_id is not None:
1517 source_branch_ids.add(mp.source_branchID)1559 source_branch_ids.add(mp.source_branch_id)
1518 if mp.source_git_repositoryID is not None:1560 if mp.source_git_repository_id is not None:
1519 git_ref_keys.add(1561 git_ref_keys.add(
1520 (mp.source_git_repositoryID, mp.source_git_path)1562 (mp.source_git_repository_id, mp.source_git_path)
1521 )1563 )
1522 git_ref_keys.add(1564 git_ref_keys.add(
1523 (mp.target_git_repositoryID, mp.target_git_path)1565 (mp.target_git_repository_id, mp.target_git_path)
1524 )1566 )
1525 if mp.prerequisite_git_repositoryID is not None:1567 if mp.prerequisite_git_repository_id is not None:
1526 git_ref_keys.add(1568 git_ref_keys.add(
1527 (1569 (
1528 mp.prerequisite_git_repositoryID,1570 mp.prerequisite_git_repository_id,
1529 mp.prerequisite_git_path,1571 mp.prerequisite_git_path,
1530 )1572 )
1531 )1573 )
1532 person_ids.add(mp.registrantID)1574 person_ids.add(mp.registrant_id)
1533 person_ids.add(mp.merge_reporterID)1575 person_ids.add(mp.merge_reporter_id)
1534 git_repository_ids = {1576 git_repository_ids = {
1535 repository_id for repository_id, _ in git_ref_keys1577 repository_id for repository_id, _ in git_ref_keys
1536 }1578 }
@@ -1538,15 +1580,15 @@ class BranchMergeProposal(SQLBase, BugLinkTargetMixin):
1538 branches = load_related(1580 branches = load_related(
1539 Branch,1581 Branch,
1540 branch_merge_proposals,1582 branch_merge_proposals,
1541 ("target_branchID", "prerequisite_branchID", "source_branchID"),1583 ("target_branch_id", "prerequisite_branch_id", "source_branch_id"),
1542 )1584 )
1543 repositories = load_related(1585 repositories = load_related(
1544 GitRepository,1586 GitRepository,
1545 branch_merge_proposals,1587 branch_merge_proposals,
1546 (1588 (
1547 "target_git_repositoryID",1589 "target_git_repository_id",
1548 "prerequisite_git_repositoryID",1590 "prerequisite_git_repository_id",
1549 "source_git_repositoryID",1591 "source_git_repository_id",
1550 ),1592 ),
1551 )1593 )
1552 load(GitRef, git_ref_keys)1594 load(GitRef, git_ref_keys)
@@ -1579,9 +1621,9 @@ class BranchMergeProposal(SQLBase, BugLinkTargetMixin):
1579 # Preload other merge proposals that supersede these.1621 # Preload other merge proposals that supersede these.
1580 supersedes_map = {}1622 supersedes_map = {}
1581 for other_mp in load_referencing(1623 for other_mp in load_referencing(
1582 BranchMergeProposal, branch_merge_proposals, ["superseded_byID"]1624 BranchMergeProposal, branch_merge_proposals, ["superseded_by_id"]
1583 ):1625 ):
1584 supersedes_map[other_mp.superseded_byID] = other_mp1626 supersedes_map[other_mp.superseded_by_id] = other_mp
1585 for mp in branch_merge_proposals:1627 for mp in branch_merge_proposals:
1586 get_property_cache(mp).supersedes = supersedes_map.get(mp.id)1628 get_property_cache(mp).supersedes = supersedes_map.get(mp.id)
15871629
@@ -1643,7 +1685,10 @@ class BranchMergeProposalGetter:
1643 @staticmethod1685 @staticmethod
1644 def get(id):1686 def get(id):
1645 """See `IBranchMergeProposalGetter`."""1687 """See `IBranchMergeProposalGetter`."""
1646 return BranchMergeProposal.get(id)1688 mp = IStore(BranchMergeProposal).get(BranchMergeProposal, id)
1689 if mp is None:
1690 raise NotFoundError(id)
1691 return mp
16471692
1648 @staticmethod1693 @staticmethod
1649 def getProposalsForContext(context, status=None, visible_by_user=None):1694 def getProposalsForContext(context, status=None, visible_by_user=None):
@@ -1666,7 +1711,7 @@ class BranchMergeProposalGetter:
1666 """See `IBranchMergeProposalGetter`."""1711 """See `IBranchMergeProposalGetter`."""
1667 registrant_select = Select(1712 registrant_select = Select(
1668 BranchMergeProposal.id,1713 BranchMergeProposal.id,
1669 BranchMergeProposal.registrantID == participant.id,1714 BranchMergeProposal.registrant_id == participant.id,
1670 )1715 )
16711716
1672 review_select = Select(1717 review_select = Select(
diff --git a/lib/lp/code/model/gitcollection.py b/lib/lp/code/model/gitcollection.py
index 1885d75..2481410 100644
--- a/lib/lp/code/model/gitcollection.py
+++ b/lib/lp/code/model/gitcollection.py
@@ -367,7 +367,7 @@ class GenericGitCollection:
367 BranchMergeProposal,367 BranchMergeProposal,
368 And(368 And(
369 GitRepository.id369 GitRepository.id
370 == BranchMergeProposal.source_git_repositoryID,370 == BranchMergeProposal.source_git_repository_id,
371 *(371 *(
372 self._filter_expressions372 self._filter_expressions
373 + self._asymmetric_filter_expressions373 + self._asymmetric_filter_expressions
@@ -376,7 +376,7 @@ class GenericGitCollection:
376 ),376 ),
377 Join(377 Join(
378 Target,378 Target,
379 Target.id == BranchMergeProposal.target_git_repositoryID,379 Target.id == BranchMergeProposal.target_git_repository_id,
380 ),380 ),
381 ]381 ]
382 )382 )
@@ -451,7 +451,8 @@ class GenericGitCollection:
451 # Need to filter on GitRepository beyond the with constraints.451 # Need to filter on GitRepository beyond the with constraints.
452 expressions += self._asymmetric_filter_expressions452 expressions += self._asymmetric_filter_expressions
453 expressions.append(453 expressions.append(
454 BranchMergeProposal.source_git_repositoryID == GitRepository.id454 BranchMergeProposal.source_git_repository_id
455 == GitRepository.id
455 )456 )
456 tables.append(GitRepository)457 tables.append(GitRepository)
457 tables.extend(self._asymmetric_tables.values())458 tables.extend(self._asymmetric_tables.values())
@@ -507,14 +508,14 @@ class GenericGitCollection:
507508
508 expressions = [509 expressions = [
509 CodeReviewVoteReference.reviewer == reviewer,510 CodeReviewVoteReference.reviewer == reviewer,
510 BranchMergeProposal.source_git_repositoryID.is_in(511 BranchMergeProposal.source_git_repository_id.is_in(
511 self._getRepositorySelect()512 self._getRepositorySelect()
512 ),513 ),
513 ]514 ]
514 visibility = self._getRepositoryVisibilityExpression()515 visibility = self._getRepositoryVisibilityExpression()
515 if visibility:516 if visibility:
516 expressions.append(517 expressions.append(
517 BranchMergeProposal.target_git_repositoryID.is_in(518 BranchMergeProposal.target_git_repository_id.is_in(
518 Select(GitRepository.id, visibility)519 Select(GitRepository.id, visibility)
519 )520 )
520 )521 )
diff --git a/lib/lp/code/model/gitrepository.py b/lib/lp/code/model/gitrepository.py
index 37c5c08..8b3c3ea 100644
--- a/lib/lp/code/model/gitrepository.py
+++ b/lib/lp/code/model/gitrepository.py
@@ -1417,7 +1417,7 @@ class GitRepository(
1417 }1417 }
1418 updated = set()1418 updated = set()
1419 for kind in ("source", "target", "prerequisite"):1419 for kind in ("source", "target", "prerequisite"):
1420 repository_name = "%s_git_repositoryID" % kind1420 repository_name = "%s_git_repository_id" % kind
1421 path_name = "%s_git_path" % kind1421 path_name = "%s_git_path" % kind
1422 commit_sha1_name = "%s_git_commit_sha1" % kind1422 commit_sha1_name = "%s_git_commit_sha1" % kind
1423 old_column = partial(getattr, BranchMergeProposal)1423 old_column = partial(getattr, BranchMergeProposal)
@@ -1958,8 +1958,8 @@ class GitRepository(
1958 seen_merge_proposal_ids.add(merge_proposal.id)1958 seen_merge_proposal_ids.add(merge_proposal.id)
1959 # Cannot use self.landing_candidates, because it ignores merged1959 # Cannot use self.landing_candidates, because it ignores merged
1960 # merge proposals.1960 # merge proposals.
1961 for merge_proposal in BranchMergeProposal.selectBy(1961 for merge_proposal in Store.of(self).find(
1962 target_git_repository=self1962 BranchMergeProposal, target_git_repository=self
1963 ):1963 ):
1964 if merge_proposal.id not in seen_merge_proposal_ids:1964 if merge_proposal.id not in seen_merge_proposal_ids:
1965 deletion_operations.append(1965 deletion_operations.append(
@@ -1973,8 +1973,8 @@ class GitRepository(
1973 )1973 )
1974 )1974 )
1975 seen_merge_proposal_ids.add(merge_proposal.id)1975 seen_merge_proposal_ids.add(merge_proposal.id)
1976 for merge_proposal in BranchMergeProposal.selectBy(1976 for merge_proposal in Store.of(self).find(
1977 prerequisite_git_repository=self1977 BranchMergeProposal, prerequisite_git_repository=self
1978 ):1978 ):
1979 if merge_proposal.id not in seen_merge_proposal_ids:1979 if merge_proposal.id not in seen_merge_proposal_ids:
1980 alteration_operations.append(1980 alteration_operations.append(
diff --git a/lib/lp/code/model/tests/test_branch.py b/lib/lp/code/model/tests/test_branch.py
index d31581b..6ea7f28 100644
--- a/lib/lp/code/model/tests/test_branch.py
+++ b/lib/lp/code/model/tests/test_branch.py
@@ -60,6 +60,7 @@ from lp.code.interfaces.branchlookup import IBranchLookup
60from lp.code.interfaces.branchmergeproposal import (60from lp.code.interfaces.branchmergeproposal import (
61 BRANCH_MERGE_PROPOSAL_FINAL_STATES as FINAL_STATES,61 BRANCH_MERGE_PROPOSAL_FINAL_STATES as FINAL_STATES,
62)62)
63from lp.code.interfaces.branchmergeproposal import IBranchMergeProposalGetter
63from lp.code.interfaces.branchnamespace import (64from lp.code.interfaces.branchnamespace import (
64 IBranchNamespacePolicy,65 IBranchNamespacePolicy,
65 IBranchNamespaceSet,66 IBranchNamespaceSet,
@@ -87,7 +88,6 @@ from lp.code.model.branchjob import (
87 BranchScanJob,88 BranchScanJob,
88 ReclaimBranchSpaceJob,89 ReclaimBranchSpaceJob,
89)90)
90from lp.code.model.branchmergeproposal import BranchMergeProposal
91from lp.code.model.branchrevision import BranchRevision91from lp.code.model.branchrevision import BranchRevision
92from lp.code.model.codereviewcomment import CodeReviewComment92from lp.code.model.codereviewcomment import CodeReviewComment
93from lp.code.model.revision import Revision93from lp.code.model.revision import Revision
@@ -110,7 +110,6 @@ from lp.registry.tests.test_accesspolicy import get_policies_for_artifact
110from lp.services.config import config110from lp.services.config import config
111from lp.services.database.constants import UTC_NOW111from lp.services.database.constants import UTC_NOW
112from lp.services.database.interfaces import IStore112from lp.services.database.interfaces import IStore
113from lp.services.database.sqlobject import SQLObjectNotFound
114from lp.services.features.testing import FeatureFixture113from lp.services.features.testing import FeatureFixture
115from lp.services.job.interfaces.job import JobStatus114from lp.services.job.interfaces.job import JobStatus
116from lp.services.job.runner import JobRunner115from lp.services.job.runner import JobRunner
@@ -1701,20 +1700,24 @@ class TestBranchDeletionConsequences(TestCase):
1701 """Merge proposal source branches can be deleted with break_links."""1700 """Merge proposal source branches can be deleted with break_links."""
1702 merge_proposal1, merge_proposal2 = self.makeMergeProposals()1701 merge_proposal1, merge_proposal2 = self.makeMergeProposals()
1703 merge_proposal1_id = merge_proposal1.id1702 merge_proposal1_id = merge_proposal1.id
1704 BranchMergeProposal.get(merge_proposal1_id)1703 getUtility(IBranchMergeProposalGetter).get(merge_proposal1_id)
1705 self.branch.destroySelf(break_references=True)1704 self.branch.destroySelf(break_references=True)
1706 self.assertRaises(1705 self.assertRaises(
1707 SQLObjectNotFound, BranchMergeProposal.get, merge_proposal1_id1706 NotFoundError,
1707 getUtility(IBranchMergeProposalGetter).get,
1708 merge_proposal1_id,
1708 )1709 )
17091710
1710 def test_deleteMergeProposalTarget(self):1711 def test_deleteMergeProposalTarget(self):
1711 """Merge proposal target branches can be deleted with break_links."""1712 """Merge proposal target branches can be deleted with break_links."""
1712 merge_proposal1, merge_proposal2 = self.makeMergeProposals()1713 merge_proposal1, merge_proposal2 = self.makeMergeProposals()
1713 merge_proposal1_id = merge_proposal1.id1714 merge_proposal1_id = merge_proposal1.id
1714 BranchMergeProposal.get(merge_proposal1_id)1715 getUtility(IBranchMergeProposalGetter).get(merge_proposal1_id)
1715 merge_proposal1.target_branch.destroySelf(break_references=True)1716 merge_proposal1.target_branch.destroySelf(break_references=True)
1716 self.assertRaises(1717 self.assertRaises(
1717 SQLObjectNotFound, BranchMergeProposal.get, merge_proposal1_id1718 NotFoundError,
1719 getUtility(IBranchMergeProposalGetter).get,
1720 merge_proposal1_id,
1718 )1721 )
17191722
1720 def test_deleteMergeProposalDependent(self):1723 def test_deleteMergeProposalDependent(self):
diff --git a/lib/lp/code/model/tests/test_gitrepository.py b/lib/lp/code/model/tests/test_gitrepository.py
index f74776f..057c80a 100644
--- a/lib/lp/code/model/tests/test_gitrepository.py
+++ b/lib/lp/code/model/tests/test_gitrepository.py
@@ -76,6 +76,7 @@ from lp.code.event.git import GitRefsUpdatedEvent
76from lp.code.interfaces.branchmergeproposal import (76from lp.code.interfaces.branchmergeproposal import (
77 BRANCH_MERGE_PROPOSAL_FINAL_STATES as FINAL_STATES,77 BRANCH_MERGE_PROPOSAL_FINAL_STATES as FINAL_STATES,
78)78)
79from lp.code.interfaces.branchmergeproposal import IBranchMergeProposalGetter
79from lp.code.interfaces.cibuild import (80from lp.code.interfaces.cibuild import (
80 CI_WEBHOOKS_FEATURE_FLAG,81 CI_WEBHOOKS_FEATURE_FLAG,
81 ICIBuild,82 ICIBuild,
@@ -103,7 +104,6 @@ from lp.code.interfaces.revisionstatus import (
103 IRevisionStatusArtifactSet,104 IRevisionStatusArtifactSet,
104 IRevisionStatusReportSet,105 IRevisionStatusReportSet,
105)106)
106from lp.code.model.branchmergeproposal import BranchMergeProposal
107from lp.code.model.branchmergeproposaljob import (107from lp.code.model.branchmergeproposaljob import (
108 BranchMergeProposalJob,108 BranchMergeProposalJob,
109 BranchMergeProposalJobType,109 BranchMergeProposalJobType,
@@ -156,7 +156,6 @@ from lp.services.config import config
156from lp.services.database.constants import UTC_NOW156from lp.services.database.constants import UTC_NOW
157from lp.services.database.interfaces import IStore157from lp.services.database.interfaces import IStore
158from lp.services.database.sqlbase import get_transaction_timestamp158from lp.services.database.sqlbase import get_transaction_timestamp
159from lp.services.database.sqlobject import SQLObjectNotFound
160from lp.services.features.testing import FeatureFixture159from lp.services.features.testing import FeatureFixture
161from lp.services.identity.interfaces.account import AccountStatus160from lp.services.identity.interfaces.account import AccountStatus
162from lp.services.job.interfaces.job import JobStatus161from lp.services.job.interfaces.job import JobStatus
@@ -1553,10 +1552,12 @@ class TestGitRepositoryDeletionConsequences(TestCaseWithFactory):
1553 # break_references.1552 # break_references.
1554 merge_proposal1, merge_proposal2 = self.makeMergeProposals()1553 merge_proposal1, merge_proposal2 = self.makeMergeProposals()
1555 merge_proposal1_id = merge_proposal1.id1554 merge_proposal1_id = merge_proposal1.id
1556 BranchMergeProposal.get(merge_proposal1_id)1555 getUtility(IBranchMergeProposalGetter).get(merge_proposal1_id)
1557 self.repository.destroySelf(break_references=True)1556 self.repository.destroySelf(break_references=True)
1558 self.assertRaises(1557 self.assertRaises(
1559 SQLObjectNotFound, BranchMergeProposal.get, merge_proposal1_id1558 NotFoundError,
1559 getUtility(IBranchMergeProposalGetter).get,
1560 merge_proposal1_id,
1560 )1561 )
15611562
1562 def test_delete_merge_proposal_target(self):1563 def test_delete_merge_proposal_target(self):
@@ -1564,12 +1565,14 @@ class TestGitRepositoryDeletionConsequences(TestCaseWithFactory):
1564 # break_references.1565 # break_references.
1565 merge_proposal1, merge_proposal2 = self.makeMergeProposals()1566 merge_proposal1, merge_proposal2 = self.makeMergeProposals()
1566 merge_proposal1_id = merge_proposal1.id1567 merge_proposal1_id = merge_proposal1.id
1567 BranchMergeProposal.get(merge_proposal1_id)1568 getUtility(IBranchMergeProposalGetter).get(merge_proposal1_id)
1568 merge_proposal1.target_git_repository.destroySelf(1569 merge_proposal1.target_git_repository.destroySelf(
1569 break_references=True1570 break_references=True
1570 )1571 )
1571 self.assertRaises(1572 self.assertRaises(
1572 SQLObjectNotFound, BranchMergeProposal.get, merge_proposal1_id1573 NotFoundError,
1574 getUtility(IBranchMergeProposalGetter).get,
1575 merge_proposal1_id,
1573 )1576 )
15741577
1575 def test_delete_merge_proposal_prerequisite(self):1578 def test_delete_merge_proposal_prerequisite(self):
@@ -1728,7 +1731,9 @@ class TestGitRepositoryDeletionConsequences(TestCaseWithFactory):
1728 merge_proposal, "blah", merge_proposal.deleteProposal1731 merge_proposal, "blah", merge_proposal.deleteProposal
1729 )()1732 )()
1730 self.assertRaises(1733 self.assertRaises(
1731 SQLObjectNotFound, BranchMergeProposal.get, merge_proposal_id1734 NotFoundError,
1735 getUtility(IBranchMergeProposalGetter).get,
1736 merge_proposal_id,
1732 )1737 )
17331738
1734 def test_DeleteCodeImport(self):1739 def test_DeleteCodeImport(self):

Subscribers

People subscribed via source and target branches

to status/vote changes: