Merge lp:~thumper/launchpad/bmp-notification-email-job into lp:launchpad

Proposed by Tim Penhey
Status: Merged
Approved by: Michael Hudson-Doyle
Approved revision: no longer in the source branch.
Merge reported by: Tim Penhey
Merged at revision: not available
Proposed branch: lp:~thumper/launchpad/bmp-notification-email-job
Merge into: lp:launchpad
Prerequisite: lp:~thumper/launchpad/new-reviewer-email-job
Diff against target: 423 lines (+187/-76)
5 files modified
lib/lp/code/configure.zcml (+10/-0)
lib/lp/code/interfaces/branchmergeproposal.py (+21/-0)
lib/lp/code/mail/branchmergeproposal.py (+22/-13)
lib/lp/code/mail/tests/test_branchmergeproposal.py (+60/-62)
lib/lp/code/model/branchmergeproposaljob.py (+74/-1)
To merge this branch: bzr merge lp:~thumper/launchpad/bmp-notification-email-job
Reviewer Review Type Date Requested Status
Michael Hudson-Doyle Approve
Review via email: mp+21703@code.launchpad.net

Description of the change

Pipe 3 of (approximately 7).

This branch changes the email being sent from update events to be sent using a job.

Not a lot to see here, just more of the same.

tests:
  mail/tests/test_branchmergeproposal

This branch is not going to be landed, but the branch at the end of the
pipeline that will be.

BTW the tests pass for this branch on ec2.

lib/lp/code/configure.zcml
 - just registering the job

lib/lp/code/interfaces/branchmergeproposal.py
 - the interface for the job and the job creation utility

lib/lp/code/mail/branchmergeproposal.py
 - Some of the delta checking logic has moved into the event subscriber
   function as we don't want to create a job for something that isn't
   even going to send out some mail.
 - If there are changes to see, then a job is created.
 - The job contains the text_delta that would be included in the email.

lib/lp/code/mail/tests/test_branchmergeproposal.py
 - tests for the job creation and the resulting email.

lib/lp/code/model/branchmergeproposaljob.py
 - the implementation of the job itself.
 - again this just defers most of the processing to the BMPMailer

To post a comment you must log in.
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

I'm not sure that all the docstrings in lib/lp/code/mail/tests/test_branchmergeproposal.py make sense any more -- can you have a whip through and make sure they're up to date?

Otherwise, it's all good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/code/configure.zcml'
--- lib/lp/code/configure.zcml 2010-03-29 01:14:29 +0000
+++ lib/lp/code/configure.zcml 2010-03-29 01:14:30 +0000
@@ -943,6 +943,16 @@
943 </class>943 </class>
944944
945 <securedutility945 <securedutility
946 component="lp.code.model.branchmergeproposaljob.MergeProposalUpdatedEmailJob"
947 provides="lp.code.interfaces.branchmergeproposal.IMergeProposalUpdatedEmailJobSource">
948 <allow interface="lp.code.interfaces.branchmergeproposal.IMergeProposalUpdatedEmailJobSource"/>
949 </securedutility>
950 <class class="lp.code.model.branchmergeproposaljob.MergeProposalUpdatedEmailJob">
951 <allow interface="lp.services.job.interfaces.job.IRunnableJob" />
952 <allow interface="lp.code.interfaces.branchmergeproposal.IBranchMergeProposalJob" />
953 </class>
954
955 <securedutility
946 component="lp.code.model.branchjob.BranchUpgradeJob"956 component="lp.code.model.branchjob.BranchUpgradeJob"
947 provides="lp.code.interfaces.branchjob.IBranchUpgradeJobSource">957 provides="lp.code.interfaces.branchjob.IBranchUpgradeJobSource">
948 <allow interface="lp.code.interfaces.branchjob.IBranchUpgradeJobSource"/>958 <allow interface="lp.code.interfaces.branchjob.IBranchUpgradeJobSource"/>
949959
=== modified file 'lib/lp/code/interfaces/branchmergeproposal.py'
--- lib/lp/code/interfaces/branchmergeproposal.py 2010-03-29 01:14:29 +0000
+++ lib/lp/code/interfaces/branchmergeproposal.py 2010-03-29 01:14:30 +0000
@@ -18,6 +18,8 @@
18 'ICreateMergeProposalJobSource',18 'ICreateMergeProposalJobSource',
19 'IMergeProposalCreatedJob',19 'IMergeProposalCreatedJob',
20 'IMergeProposalCreatedJobSource',20 'IMergeProposalCreatedJobSource',
21 'IMergeProposalUpdatedEmailJob',
22 'IMergeProposalUpdatedEmailJobSource',
21 'IReviewRequestedEmailJob',23 'IReviewRequestedEmailJob',
22 'IReviewRequestedEmailJobSource',24 'IReviewRequestedEmailJobSource',
23 'IUpdatePreviewDiffJobSource',25 'IUpdatePreviewDiffJobSource',
@@ -632,6 +634,25 @@
632 """634 """
633635
634636
637class IMergeProposalUpdatedEmailJob(IRunnableJob):
638 """Interface for the job to sends email about merge proposal updates."""
639
640 editor = Attribute('The person that did the editing.')
641 delta_text = Attribute('The textual representation of the changed fields.')
642
643
644class IMergeProposalUpdatedEmailJobSource(IJobSource):
645 """Create or retrieve jobs that email about merge proposal updates."""
646
647 def create(merge_proposal, delta_text, editor):
648 """Create a job to email merge proposal updates to subscribers.
649
650 :param merge_proposal: The merge proposal that has been edited.
651 :param delta_text: The text representation of the changed fields.
652 :param editor: The person who did the editing.
653 """
654
655
635# XXX: JonathanLange 2010-01-06: This is only used in the scanner, perhaps it656# XXX: JonathanLange 2010-01-06: This is only used in the scanner, perhaps it
636# should be moved there.657# should be moved there.
637def notify_modified(proposal, func, *args, **kwargs):658def notify_modified(proposal, func, *args, **kwargs):
638659
=== modified file 'lib/lp/code/mail/branchmergeproposal.py'
--- lib/lp/code/mail/branchmergeproposal.py 2010-03-29 01:14:29 +0000
+++ lib/lp/code/mail/branchmergeproposal.py 2010-03-29 01:14:30 +0000
@@ -15,10 +15,12 @@
15from lp.code.adapters.branch import BranchMergeProposalDelta15from lp.code.adapters.branch import BranchMergeProposalDelta
16from lp.code.enums import CodeReviewNotificationLevel16from lp.code.enums import CodeReviewNotificationLevel
17from lp.code.interfaces.branchmergeproposal import (17from lp.code.interfaces.branchmergeproposal import (
18 IMergeProposalCreatedJobSource, IReviewRequestedEmailJobSource)18 IMergeProposalCreatedJobSource, IMergeProposalUpdatedEmailJobSource,
19 IReviewRequestedEmailJobSource)
19from lp.code.mail.branch import BranchMailer20from lp.code.mail.branch import BranchMailer
20from lp.registry.interfaces.person import IPerson21from lp.registry.interfaces.person import IPerson
21from lp.services.mail.basemailer import BaseMailer22from lp.services.mail.basemailer import BaseMailer
23from lp.services.utils import text_delta
2224
2325
24def send_merge_proposal_created_notifications(merge_proposal, event):26def send_merge_proposal_created_notifications(merge_proposal, event):
@@ -32,16 +34,24 @@
3234
33def send_merge_proposal_modified_notifications(merge_proposal, event):35def send_merge_proposal_modified_notifications(merge_proposal, event):
34 """Notify branch subscribers when merge proposals are updated."""36 """Notify branch subscribers when merge proposals are updated."""
37 # Check the user.
35 if event.user is None:38 if event.user is None:
36 return39 return
37 if isinstance(event.user, UnauthenticatedPrincipal):40 if isinstance(event.user, UnauthenticatedPrincipal):
38 from_person = None41 from_person = None
39 else:42 else:
40 from_person = IPerson(event.user)43 from_person = IPerson(event.user)
41 mailer = BMPMailer.forModification(44 # Create a delta of the changes. If there are no changes to report, then
42 event.object_before_modification, merge_proposal, from_person)45 # we're done.
43 if mailer is not None:46 delta = BranchMergeProposalDelta.construct(
44 mailer.sendAll()47 event.object_before_modification, merge_proposal)
48 if delta is None:
49 return
50 changes = text_delta(
51 delta, delta.delta_values, delta.new_values, delta.interface)
52 # Now create the job to send the email.
53 getUtility(IMergeProposalUpdatedEmailJobSource).create(
54 merge_proposal, changes, from_person)
4555
4656
47def send_review_requested_notifications(vote_reference, event):57def send_review_requested_notifications(vote_reference, event):
@@ -57,13 +67,14 @@
57 requested_reviews=None, preview_diff=None,67 requested_reviews=None, preview_diff=None,
58 direct_email=False):68 direct_email=False):
59 BranchMailer.__init__(69 BranchMailer.__init__(
60 self, subject, template_name, recipients, from_address, delta,70 self, subject, template_name, recipients, from_address,
61 message_id=message_id, notification_type='code-review')71 message_id=message_id, notification_type='code-review')
62 self.merge_proposal = merge_proposal72 self.merge_proposal = merge_proposal
63 if requested_reviews is None:73 if requested_reviews is None:
64 requested_reviews = []74 requested_reviews = []
65 self.requested_reviews = requested_reviews75 self.requested_reviews = requested_reviews
66 self.preview_diff = preview_diff76 self.preview_diff = preview_diff
77 self.delta_text = delta
67 self.template_params = self._generateTemplateParams()78 self.template_params = self._generateTemplateParams()
68 self.direct_email = direct_email79 self.direct_email = direct_email
6980
@@ -95,8 +106,7 @@
95 preview_diff=merge_proposal.preview_diff)106 preview_diff=merge_proposal.preview_diff)
96107
97 @classmethod108 @classmethod
98 def forModification(cls, old_merge_proposal, merge_proposal,109 def forModification(cls, merge_proposal, delta_text, from_user):
99 from_user=None):
100 """Return a mailer for BranchMergeProposal creation.110 """Return a mailer for BranchMergeProposal creation.
101111
102 :param merge_proposal: The BranchMergeProposal that was created.112 :param merge_proposal: The BranchMergeProposal that was created.
@@ -111,14 +121,11 @@
111 from_address = cls._format_user_address(from_user)121 from_address = cls._format_user_address(from_user)
112 else:122 else:
113 from_address = config.canonical.noreply_from_address123 from_address = config.canonical.noreply_from_address
114 delta = BranchMergeProposalDelta.construct(
115 old_merge_proposal, merge_proposal)
116 if delta is None:
117 return None
118 return cls(124 return cls(
119 '%(proposal_title)s',125 '%(proposal_title)s',
120 'branch-merge-proposal-updated.txt', recipients,126 'branch-merge-proposal-updated.txt', recipients,
121 merge_proposal, from_address, delta, get_msgid())127 merge_proposal, from_address, delta=delta_text,
128 message_id=get_msgid())
122129
123 @classmethod130 @classmethod
124 def forReviewRequest(cls, reason, merge_proposal, from_user):131 def forReviewRequest(cls, reason, merge_proposal, from_user):
@@ -189,6 +196,8 @@
189 'whiteboard': '', # No more whiteboard.196 'whiteboard': '', # No more whiteboard.
190 'diff_cutoff_warning': '',197 'diff_cutoff_warning': '',
191 }198 }
199 if self.delta_text is not None:
200 params['delta'] = self.delta_text
192201
193 if proposal.prerequisite_branch is not None:202 if proposal.prerequisite_branch is not None:
194 prereq_url = proposal.prerequisite_branch.bzr_identity203 prereq_url = proposal.prerequisite_branch.bzr_identity
195204
=== modified file 'lib/lp/code/mail/tests/test_branchmergeproposal.py'
--- lib/lp/code/mail/tests/test_branchmergeproposal.py 2010-03-29 01:14:29 +0000
+++ lib/lp/code/mail/tests/test_branchmergeproposal.py 2010-03-29 01:14:30 +0000
@@ -25,7 +25,7 @@
25from lp.code.model.branch import update_trigger_modified_fields25from lp.code.model.branch import update_trigger_modified_fields
26from lp.code.model.branchmergeproposaljob import (26from lp.code.model.branchmergeproposaljob import (
27 BranchMergeProposalJob, BranchMergeProposalJobType,27 BranchMergeProposalJob, BranchMergeProposalJobType,
28 ReviewRequestedEmailJob)28 MergeProposalUpdatedEmailJob, ReviewRequestedEmailJob)
29from lp.code.model.codereviewvote import CodeReviewVoteReference29from lp.code.model.codereviewvote import CodeReviewVoteReference
30from canonical.launchpad.webapp import canonical_url30from canonical.launchpad.webapp import canonical_url
31from lp.testing import login_person, TestCaseWithFactory31from lp.testing import login_person, TestCaseWithFactory
@@ -280,95 +280,93 @@
280 warning_text = "The attached diff has been truncated due to its size."280 warning_text = "The attached diff has been truncated due to its size."
281 self.assertTrue(warning_text in ctrl.body)281 self.assertTrue(warning_text in ctrl.body)
282282
283 def test_forModificationNoModification(self):283 def getProposalUpdatedEmailJob(self, merge_proposal):
284 """Return the merge proposal updated email job."""
285 jobs = list(
286 IStore(BranchMergeProposalJob).find(
287 BranchMergeProposalJob,
288 BranchMergeProposalJob.branch_merge_proposal ==
289 merge_proposal,
290 BranchMergeProposalJob.job_type ==
291 BranchMergeProposalJobType.MERGE_PROPOSAL_UPDATED))
292 if len(jobs) == 0:
293 return None
294 elif len(jobs) == 1:
295 return MergeProposalUpdatedEmailJob(jobs[0])
296 else:
297 self.fail('There are more than one jobs.')
298
299 def test_no_job_created_if_no_delta(self):
284 """Ensure None is returned if no change has been made."""300 """Ensure None is returned if no change has been made."""
285 merge_proposal, person = self.makeProposalWithSubscriber()301 merge_proposal, person = self.makeProposalWithSubscriber()
286 old_merge_proposal = BranchMergeProposalDelta.snapshot(merge_proposal)302 old_merge_proposal = BranchMergeProposalDelta.snapshot(merge_proposal)
287 self.assertEqual(None, BMPMailer.forModification(303 event = ObjectModifiedEvent(
288 old_merge_proposal, merge_proposal, merge_proposal.registrant))304 merge_proposal, old_merge_proposal, [], merge_proposal.registrant)
305 send_merge_proposal_modified_notifications(merge_proposal, event)
306 self.assertIs(None, self.getProposalUpdatedEmailJob(merge_proposal))
289307
290 def makeMergeProposalMailerModification(self):308 def makeProposalUpdatedEmailJob(self):
291 """Fixture method providing a mailer for a modified merge proposal"""309 """Fixture method providing a mailer for a modified merge proposal"""
292 merge_proposal, subscriber = self.makeProposalWithSubscriber()310 merge_proposal, subscriber = self.makeProposalWithSubscriber()
293 old_merge_proposal = BranchMergeProposalDelta.snapshot(merge_proposal)311 old_merge_proposal = BranchMergeProposalDelta.snapshot(merge_proposal)
294 merge_proposal.requestReview()312 merge_proposal.requestReview()
295 merge_proposal.commit_message = 'new commit message'313 merge_proposal.commit_message = 'new commit message'
296 merge_proposal.description = 'change description'314 merge_proposal.description = 'change description'
315 event = ObjectModifiedEvent(
316 merge_proposal, old_merge_proposal, [], merge_proposal.registrant)
317 send_merge_proposal_modified_notifications(merge_proposal, event)
318 job = self.getProposalUpdatedEmailJob(merge_proposal)
319 self.assertIsNot(None, job, 'Job was not created.')
320 return job, subscriber
321
322 def test_forModificationHasMsgId(self):
323 """Ensure the right delta is filled out if there is a change."""
324 merge_proposal = self.factory.makeBranchMergeProposal()
297 mailer = BMPMailer.forModification(325 mailer = BMPMailer.forModification(
298 old_merge_proposal, merge_proposal, merge_proposal.registrant)326 merge_proposal, 'the diff', merge_proposal.registrant)
299 return mailer, subscriber327 self.assertIsNot(None, mailer.message_id, 'message_id not set')
300
301 def test_forModificationWithModificationDelta(self):
302 """Ensure the right delta is filled out if there is a change."""
303 mailer, subscriber = self.makeMergeProposalMailerModification()
304 self.assertEqual('new commit message',
305 mailer.delta.commit_message)
306
307 def test_forModificationHasMsgId(self):
308 """Ensure the right delta is filled out if there is a change."""
309 mailer, subscriber = self.makeMergeProposalMailerModification()
310 assert mailer.message_id is not None, 'message_id not set'
311328
312 def test_forModificationWithModificationTextDelta(self):329 def test_forModificationWithModificationTextDelta(self):
313 """Ensure the right delta is filled out if there is a change."""330 """Ensure the right delta is filled out if there is a change."""
314 mailer, subscriber = self.makeMergeProposalMailerModification()331 job, subscriber = self.makeProposalUpdatedEmailJob()
315 self.assertEqual(332 self.assertEqual(
316 ' Status: Work in progress => Needs review\n\n'333 ' Status: Work in progress => Needs review\n\n'
317 'Commit Message changed to:\n\nnew commit message\n\n'334 'Commit Message changed to:\n\nnew commit message\n\n'
318 'Description changed to:\n\nchange description',335 'Description changed to:\n\nchange description',
319 mailer.textDelta())336 job.delta_text)
320
321 def test_generateEmail(self):
322 """Ensure that contents of modification mails are right."""
323 mailer, subscriber = self.makeMergeProposalMailerModification()
324 ctrl = mailer.generateEmail('baz.quxx@example.com', subscriber)
325 self.assertEqual('[Merge] '
326 'lp://dev/~bob/super-product/fix-foo-for-bar into '
327 'lp://dev/~mary/super-product/bar', ctrl.subject)
328 url = canonical_url(mailer.merge_proposal)
329 reason = mailer._recipients.getReason(
330 subscriber.preferredemail.email)[0].getReason()
331 self.assertEqual("""\
332The proposal to merge lp://dev/~bob/super-product/fix-foo-for-bar into lp://dev/~mary/super-product/bar has been updated.
333
334 Status: Work in progress => Needs review
335
336Commit Message changed to:
337
338new commit message
339
340Description changed to:
341
342change description
343--\x20
344%s
345%s
346""" % (url, reason), ctrl.body)
347337
348 def test_send_merge_proposal_modified_notifications(self):338 def test_send_merge_proposal_modified_notifications(self):
349 """Should send emails when invoked with correct parameters."""339 """Should send emails when invoked with correct parameters."""
350 merge_proposal, subscriber = self.makeProposalWithSubscriber()340 job, subscriber = self.makeProposalUpdatedEmailJob()
351 snapshot = BranchMergeProposalDelta.snapshot(merge_proposal)
352 merge_proposal.commit_message = 'new message'
353 event = ObjectModifiedEvent(merge_proposal, snapshot, None)
354 pop_notifications()341 pop_notifications()
355 send_merge_proposal_modified_notifications(merge_proposal, event)342 job.run()
356 emails = pop_notifications()343 emails = pop_notifications()
357 self.assertEqual(3, len(emails),344 self.assertEqual(3, len(emails),
358 'There should be three emails sent out. One to the '345 'There should be three emails sent out. One to the '
359 'explicit subscriber above, and one each to the '346 'explicit subscriber above, and one each to the '
360 'source branch owner and the target branch owner '347 'source branch owner and the target branch owner '
361 'who were implicitly subscribed to their branches.')348 'who were implicitly subscribed to their branches.')
362349 email = emails[0]
363 def test_send_merge_proposal_modified_notifications_no_delta(self):350 self.assertEqual('[Merge] '
364 """Should not send emails if no delta."""351 'lp://dev/~bob/super-product/fix-foo-for-bar into\n\t'
365 merge_proposal, subscriber = self.makeProposalWithSubscriber()352 'lp://dev/~mary/super-product/bar', email['subject'])
366 snapshot = BranchMergeProposalDelta.snapshot(merge_proposal)353 self.assertEqual(dedent("""\
367 event = ObjectModifiedEvent(merge_proposal, snapshot, None)354 The proposal to merge lp://dev/~bob/super-product/fix-foo-for-bar into lp://dev/~mary/super-product/bar has been updated.
368 pop_notifications()355
369 send_merge_proposal_modified_notifications(merge_proposal, event)356 Status: Work in progress => Needs review
370 emails = pop_notifications()357
371 self.assertEqual([], emails)358 Commit Message changed to:
359
360 new commit message
361
362 Description changed to:
363
364 change description
365 --\x20
366 %s
367 You are subscribed to branch lp://dev/~bob/super-product/fix-foo-for-bar.
368 """) % canonical_url(job.branch_merge_proposal),
369 email.get_payload(decode=True))
372370
373 def assertRecipientsMatches(self, recipients, mailer):371 def assertRecipientsMatches(self, recipients, mailer):
374 """Assert that `mailer` will send to the people in `recipients`."""372 """Assert that `mailer` will send to the people in `recipients`."""
375373
=== modified file 'lib/lp/code/model/branchmergeproposaljob.py'
--- lib/lp/code/model/branchmergeproposaljob.py 2010-03-29 01:14:29 +0000
+++ lib/lp/code/model/branchmergeproposaljob.py 2010-03-29 01:14:30 +0000
@@ -52,7 +52,8 @@
52 IBranchMergeProposalJob, ICodeReviewCommentEmailJob,52 IBranchMergeProposalJob, ICodeReviewCommentEmailJob,
53 ICodeReviewCommentEmailJobSource, ICreateMergeProposalJob,53 ICodeReviewCommentEmailJobSource, ICreateMergeProposalJob,
54 ICreateMergeProposalJobSource, IMergeProposalCreatedJob,54 ICreateMergeProposalJobSource, IMergeProposalCreatedJob,
55 IMergeProposalCreatedJobSource, IReviewRequestedEmailJob,55 IMergeProposalCreatedJobSource, IMergeProposalUpdatedEmailJob,
56 IMergeProposalUpdatedEmailJobSource, IReviewRequestedEmailJob,
56 IReviewRequestedEmailJobSource, IUpdatePreviewDiffJobSource,57 IReviewRequestedEmailJobSource, IUpdatePreviewDiffJobSource,
57 )58 )
58from lp.code.mail.branch import RecipientReason59from lp.code.mail.branch import RecipientReason
@@ -97,6 +98,13 @@
97 requested reviewer team asking them to review the proposal.98 requested reviewer team asking them to review the proposal.
98 """)99 """)
99100
101 MERGE_PROPOSAL_UPDATED = DBItem(4, """
102 Merge proposal updated
103
104 This job sends an email to the subscribers informing them of fields
105 that have been changed on the merge proposal itself.
106 """)
107
100108
101class BranchMergeProposalJob(Storm):109class BranchMergeProposalJob(Storm):
102 """Base class for jobs related to branch merge proposals."""110 """Base class for jobs related to branch merge proposals."""
@@ -491,3 +499,68 @@
491 if self.requester is not None:499 if self.requester is not None:
492 recipients.append(self.requester.preferredemail)500 recipients.append(self.requester.preferredemail)
493 return recipients501 return recipients
502
503
504class MergeProposalUpdatedEmailJob(BranchMergeProposalJobDerived):
505 """Send email to the subscribers informing them of updated fields.
506
507 When attributes of the merge proposal are edited, we inform the
508 subscribers.
509 """
510
511 implements(IMergeProposalUpdatedEmailJob)
512
513 classProvides(IMergeProposalUpdatedEmailJobSource)
514
515 class_job_type = BranchMergeProposalJobType.MERGE_PROPOSAL_UPDATED
516
517 def run(self):
518 """See `IRunnableJob`."""
519 mailer = BMPMailer.forModification(
520 self.branch_merge_proposal, self.delta_text, self.editor)
521 mailer.sendAll()
522
523 @classmethod
524 def create(cls, merge_proposal, delta_text, editor):
525 """See `IReviewRequestedEmailJobSource`."""
526 metadata = cls.getMetadata(delta_text, editor)
527 job = BranchMergeProposalJob(
528 merge_proposal, cls.class_job_type, metadata)
529 return cls(job)
530
531 @staticmethod
532 def getMetadata(delta_text, editor):
533 metadata = {'delta_text': delta_text}
534 if editor is not None:
535 metadata['editor'] = editor.name;
536 return metadata
537
538 @property
539 def editor(self):
540 """The person who updated the merge proposal."""
541 editor_name = self.metadata.get('editor')
542 if editor_name is None:
543 return None
544 else:
545 return getUtility(IPersonSet).getByName(editor_name)
546
547 @property
548 def delta_text(self):
549 """The changes that were made to the merge proposal."""
550 return self.metadata['delta_text']
551
552 def getOopsVars(self):
553 """See `IRunnableJob`."""
554 vars = BranchMergeProposalJobDerived.getOopsVars(self)
555 vars.extend([
556 ('editor', self.metadata.get('editor', '(not set)')),
557 ('delta_text', self.metadata['delta_text']),
558 ])
559 return vars
560
561 def getErrorRecipients(self):
562 """Return a list of email-ids to notify about user errors."""
563 recipients = []
564 if self.editor is not None:
565 recipients.append(self.editor.preferredemail)
566 return recipients