Merge lp:~thumper/launchpad/only-show-latest-bmp-in-revision-mail into lp:launchpad

Proposed by Tim Penhey
Status: Merged
Merged at revision: 10325
Proposed branch: lp:~thumper/launchpad/only-show-latest-bmp-in-revision-mail
Merge into: lp:launchpad
Diff against target: 126 lines (+48/-16)
2 files modified
lib/lp/code/model/branchjob.py (+24/-12)
lib/lp/code/model/tests/test_branchjob.py (+24/-4)
To merge this branch: bzr merge lp:~thumper/launchpad/only-show-latest-bmp-in-revision-mail
Reviewer Review Type Date Requested Status
Michael Hudson-Doyle Approve
Review via email: mp+19377@code.launchpad.net

Commit message

Only show the most recent proposal for any given source branch in the revision mail.

To post a comment you must log in.
Revision history for this message
Tim Penhey (thumper) wrote :

The revision mail that goes out includes related merge proposals, which is great as long as one doesn't reuse branches. An example is the pending-db-changes that stub has. This branch only shows the latest merge proposal for any given source branch.

Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :
Download full text (5.8 KiB)

Hi Tim,

nice branch, just a couple of things to think about.

> === modified file 'lib/lp/code/model/branchjob.py'
> --- lib/lp/code/model/branchjob.py 2010-02-03 19:29:27 +0000
> +++ lib/lp/code/model/branchjob.py 2010-02-16 04:50:58 +0000
> @@ -13,6 +13,7 @@
> ]
>
> import contextlib
> +import operator
> import os
> import shutil
> from StringIO import StringIO
> @@ -600,28 +601,43 @@
> authors.update(revision.get_apparent_authors())
> return authors
>
> - def findRelatedBMP(self, revision_ids, include_superseded=True):
> + def findRelatedBMP(self, revision_ids):
> """Find merge proposals related to the revision-ids and branch.
>
> Only proposals whose source branch last-scanned-id is in the set of
> revision-ids and whose target_branch is the BranchJob branch are
> returned.
>
> + Only return the most recent proposal for any given source branch.
> +
> :param revision_ids: A list of revision-ids to look for.
> :param include_superseded: If true, include merge proposals that are
> superseded in the results.
> """
> store = Store.of(self.branch)
> conditions = [
> + ]

'conditions' is unused now.

> + result = store.find(
> + (BranchMergeProposal, Branch),
> BranchMergeProposal.target_branch == self.branch.id,
> BranchMergeProposal.source_branch == Branch.id,
> - Branch.last_scanned_id.is_in(revision_ids)]
> - if not include_superseded:
> - conditions.append(
> - BranchMergeProposal.queue_status !=
> - BranchMergeProposalStatus.SUPERSEDED)
> - result = store.find(BranchMergeProposal, *conditions)
> - return result
> + Branch.last_scanned_id.is_in(revision_ids),
> + (BranchMergeProposal.queue_status !=
> + BranchMergeProposalStatus.SUPERSEDED))
> +
> + proposals = {}
> + for proposal, source in result:
> + # Only show the must recent proposal for any given source.
> + date_created = proposal.date_created
> + source_id = source.id
> +
> + if (source_id not in proposals or
> + date_created > proposals[source_id][1]):
> + proposals[source_id] = (proposal, date_created)
> +
> + return sorted(
> + [proposal for proposal, date_created in proposals.itervalues()],
> + key=operator.attrgetter('date_created'), reverse=True)

This seems a little complicated, although I admit I can't think of any
obviously clearer ways. Did you think about any ways of doing the
filtering in the database? That seems likely to be complicated too
though...

> def getRevisionMessage(self, revision_id, revno):
> """Return the log message for a revision.
> @@ -654,9 +670,7 @@
> if len(pretty_authors) > 5:
> outf.write('...\n')
> outf.write('\n')
> - bmps = list(
> - self.findRelatedBMP(merged_revisions,
> - include_superseded=False))
> + bmps = self.f...

Read more...

review: Approve
Revision history for this message
Tim Penhey (thumper) wrote :

On Tue, 16 Feb 2010 19:27:34 Michael Hudson wrote:
> Review: Approve
> Hi Tim,
>
> nice branch, just a couple of things to think about.
>
> > === modified file 'lib/lp/code/model/branchjob.py'
> > --- lib/lp/code/model/branchjob.py 2010-02-03 19:29:27 +0000
> > +++ lib/lp/code/model/branchjob.py 2010-02-16 04:50:58 +0000
> > store = Store.of(self.branch)
> > conditions = [
> > + ]
>
> 'conditions' is unused now.

Removed now.

> > + return sorted(
> > + [proposal for proposal, date_created in
> > proposals.itervalues()], +
> > key=operator.attrgetter('date_created'), reverse=True)
>
> This seems a little complicated, although I admit I can't think of any
> obviously clearer ways. Did you think about any ways of doing the
> filtering in the database? That seems likely to be complicated too
> though...

It could possibly be done, but I don't know how to do it in storm.

We want to group by the source branch and choose the merge proposal with the
latest date_created. I just don't know how to do this.

> > def getRevisionMessage(self, revision_id, revno):
> > """Return the log message for a revision.
> > @@ -654,9 +670,7 @@
> > if len(pretty_authors) > 5:
> > outf.write('...\n')
> > outf.write('\n')
> > - bmps = list(
> > - self.findRelatedBMP(merged_revisions,
> > - include_superseded=False))
> > + bmps = self.findRelatedBMP(merged_revisions)
> > if len(bmps) > 0:
> > outf.write('Related merge proposals:\n')
> > for bmp in bmps:
> >
> > === modified file 'lib/lp/code/model/tests/test_branchjob.py'
> > --- lib/lp/code/model/tests/test_branchjob.py 2010-01-26 02:05:23 +0000
> > +++ lib/lp/code/model/tests/test_branchjob.py 2010-02-16 04:50:58 +0000
> > + def test_findRelatedBMP_one_per_source(self):
> > + """Assert that only the lastest for any particular source is
> > returned.
>
> I don't think it adds anything to start a test method
> comment/docstring with "Assert that". Something like "findRelatedBMP
> only returns the latest proposal for any source." would be better
> IMHO.

Fixed.

> And lastest isn't spelt like that :-)

I was tired. Also fixed.

> > self.assertEqual([desired_proposal],
> > list(job.findRelatedBMP(['rev2a-id'])))
>
> It would be nice to reformat this as
>
> self.assertEqual(
> [desired_proposal], job.findRelatedBMP(['rev2a-id']))
>
> as you did for the other test.

Done.

1=== modified file 'lib/lp/code/model/branchjob.py'
2--- lib/lp/code/model/branchjob.py 2010-02-15 23:50:19 +0000
3+++ lib/lp/code/model/branchjob.py 2010-02-17 00:39:08 +0000
4@@ -615,8 +615,6 @@
5 superseded in the results.
6 """
7 store = Store.of(self.branch)
8- conditions = [
9- ]
10 result = store.find(
11 (BranchMergeProposal, Branch),
12 BranchMergeProposal.target_branch == self.branch.id,
13
14=== modified file 'lib/lp/code/model/tests/test_branchjob.py'
15--- lib/lp/code/model/tests/test_branchjob.py 2010-02-15 23:50:19 +0000
16+++ lib/lp/code/model/tests/test_branchjob.py 2010-02-17 00:39:08 +0000
17@@ -551,7 +551,8 @@
18 [desired_proposal], job.findRelatedBMP(['rev2a-id']))
19
20 def test_findRelatedBMP_one_per_source(self):
21- """Assert that only the lastest for any particular source is returned.
22+ """findRelatedBMP only returns the most recent proposal for any
23+ particular source branch.
24 """
25 self.useBzrBranches()
26 target_branch, tree = self.create_branch_and_tree('tree')
27@@ -565,8 +566,8 @@
28 source_branch.owner, target_branch)
29 job = RevisionsAddedJob.create(
30 target_branch, 'rev2b-id', 'rev2b-id', '')
31- self.assertEqual([desired_proposal],
32- list(job.findRelatedBMP(['rev2a-id'])))
33+ self.assertEqual(
34+ [desired_proposal], job.findRelatedBMP(['rev2a-id']))
35
36 def test_getAuthors(self):
37 """Ensure getAuthors returns the authors for the revisions."""

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/code/model/branchjob.py'
2--- lib/lp/code/model/branchjob.py 2010-02-03 19:29:27 +0000
3+++ lib/lp/code/model/branchjob.py 2010-02-17 00:50:32 +0000
4@@ -13,6 +13,7 @@
5 ]
6
7 import contextlib
8+import operator
9 import os
10 import shutil
11 from StringIO import StringIO
12@@ -600,28 +601,41 @@
13 authors.update(revision.get_apparent_authors())
14 return authors
15
16- def findRelatedBMP(self, revision_ids, include_superseded=True):
17+ def findRelatedBMP(self, revision_ids):
18 """Find merge proposals related to the revision-ids and branch.
19
20 Only proposals whose source branch last-scanned-id is in the set of
21 revision-ids and whose target_branch is the BranchJob branch are
22 returned.
23
24+ Only return the most recent proposal for any given source branch.
25+
26 :param revision_ids: A list of revision-ids to look for.
27 :param include_superseded: If true, include merge proposals that are
28 superseded in the results.
29 """
30 store = Store.of(self.branch)
31- conditions = [
32+ result = store.find(
33+ (BranchMergeProposal, Branch),
34 BranchMergeProposal.target_branch == self.branch.id,
35 BranchMergeProposal.source_branch == Branch.id,
36- Branch.last_scanned_id.is_in(revision_ids)]
37- if not include_superseded:
38- conditions.append(
39- BranchMergeProposal.queue_status !=
40- BranchMergeProposalStatus.SUPERSEDED)
41- result = store.find(BranchMergeProposal, *conditions)
42- return result
43+ Branch.last_scanned_id.is_in(revision_ids),
44+ (BranchMergeProposal.queue_status !=
45+ BranchMergeProposalStatus.SUPERSEDED))
46+
47+ proposals = {}
48+ for proposal, source in result:
49+ # Only show the must recent proposal for any given source.
50+ date_created = proposal.date_created
51+ source_id = source.id
52+
53+ if (source_id not in proposals or
54+ date_created > proposals[source_id][1]):
55+ proposals[source_id] = (proposal, date_created)
56+
57+ return sorted(
58+ [proposal for proposal, date_created in proposals.itervalues()],
59+ key=operator.attrgetter('date_created'), reverse=True)
60
61 def getRevisionMessage(self, revision_id, revno):
62 """Return the log message for a revision.
63@@ -654,9 +668,7 @@
64 if len(pretty_authors) > 5:
65 outf.write('...\n')
66 outf.write('\n')
67- bmps = list(
68- self.findRelatedBMP(merged_revisions,
69- include_superseded=False))
70+ bmps = self.findRelatedBMP(merged_revisions)
71 if len(bmps) > 0:
72 outf.write('Related merge proposals:\n')
73 for bmp in bmps:
74
75=== modified file 'lib/lp/code/model/tests/test_branchjob.py'
76--- lib/lp/code/model/tests/test_branchjob.py 2010-01-26 02:05:23 +0000
77+++ lib/lp/code/model/tests/test_branchjob.py 2010-02-17 00:50:32 +0000
78@@ -7,6 +7,7 @@
79
80 import datetime
81 import os
82+import pytz
83 import shutil
84 from storm.locals import Store
85 import tempfile
86@@ -40,8 +41,8 @@
87 from lp.services.job.model.job import Job
88 from lp.code.bzr import BranchFormat, RepositoryFormat
89 from lp.code.enums import (
90- BranchSubscriptionDiffSize, BranchSubscriptionNotificationLevel,
91- CodeReviewNotificationLevel)
92+ BranchMergeProposalStatus, BranchSubscriptionDiffSize,
93+ BranchSubscriptionNotificationLevel, CodeReviewNotificationLevel)
94 from lp.code.interfaces.branchjob import (
95 IBranchDiffJob, IBranchJob, IBranchScanJob, IBranchUpgradeJob,
96 IReclaimBranchSpaceJob, IReclaimBranchSpaceJobSource, IRevisionMailJob,
97@@ -546,8 +547,27 @@
98 wrong_target_proposal.source_branch.last_scanned_id = 'rev2a-id'
99 job = RevisionsAddedJob.create(target_branch, 'rev2b-id', 'rev2b-id',
100 '')
101- self.assertEqual([desired_proposal],
102- list(job.findRelatedBMP(['rev2a-id'])))
103+ self.assertEqual(
104+ [desired_proposal], job.findRelatedBMP(['rev2a-id']))
105+
106+ def test_findRelatedBMP_one_per_source(self):
107+ """findRelatedBMP only returns the most recent proposal for any
108+ particular source branch.
109+ """
110+ self.useBzrBranches()
111+ target_branch, tree = self.create_branch_and_tree('tree')
112+ the_past = datetime.datetime(2009, 1, 1, tzinfo=pytz.UTC)
113+ old_proposal = self.factory.makeBranchMergeProposal(
114+ target_branch=target_branch, date_created=the_past,
115+ set_state=BranchMergeProposalStatus.MERGED)
116+ source_branch = old_proposal.source_branch
117+ source_branch.last_scanned_id = 'rev2a-id'
118+ desired_proposal = source_branch.addLandingTarget(
119+ source_branch.owner, target_branch)
120+ job = RevisionsAddedJob.create(
121+ target_branch, 'rev2b-id', 'rev2b-id', '')
122+ self.assertEqual(
123+ [desired_proposal], job.findRelatedBMP(['rev2a-id']))
124
125 def test_getAuthors(self):
126 """Ensure getAuthors returns the authors for the revisions."""