Merge lp:~abentley/launchpad/incremental-diffs into lp:launchpad/db-devel

Proposed by Aaron Bentley
Status: Merged
Approved by: Leonard Richardson
Approved revision: no longer in the source branch.
Merged at revision: 9950
Proposed branch: lp:~abentley/launchpad/incremental-diffs
Merge into: lp:launchpad/db-devel
Diff against target: 462 lines (+271/-5)
8 files modified
lib/lp/code/configure.zcml (+7/-1)
lib/lp/code/interfaces/diff.py (+19/-0)
lib/lp/code/model/branchmergeproposal.py (+41/-1)
lib/lp/code/model/diff.py (+66/-3)
lib/lp/code/model/tests/test_branchmergeproposal.py (+41/-0)
lib/lp/code/model/tests/test_diff.py (+84/-0)
lib/lp/testing/factory.py (+12/-0)
utilities/sourcedeps.conf (+1/-0)
To merge this branch: bzr merge lp:~abentley/launchpad/incremental-diffs
Reviewer Review Type Date Requested Status
Leonard Richardson (community) Approve
Review via email: mp+36875@code.launchpad.net

Commit message

Implement incremental diff generation.

Description of the change

= Summary =
Implement incremental diff generation

== Proposed fix ==
See above

== Pre-implementation notes ==
Mid-implementation with thumper

== Implementation details ==
The generation of incremental diffs is handled by the Difftacular bzr plugin,
and the full testing of its behaviour is provided by its test suite.

I implemented the diff_changes test method to get a clearer idea what was added
and removed by a given diff.

== Tests ==
bin/test -t TestIncrementalDiff -t TestBranchMergeProposalGetIncrementalDiffs

== Demo and Q/A ==
None

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/code/configure.zcml
  lib/lp/code/model/branchmergeproposal.py
  lib/lp/code/model/tests/test_branchmergeproposal.py
  lib/lp/code/model/diff.py
  lib/lp/testing/factory.py
  lib/lp/code/model/tests/test_diff.py
  utilities/sourcedeps.conf
  lib/lp/code/interfaces/diff.py

./lib/lp/code/model/tests/test_branchmergeproposal.py
     192: E231 missing whitespace after ','
     194: E231 missing whitespace after ','
./lib/lp/code/model/diff.py
     166: E301 expected 1 blank line, found 0

To post a comment you must log in.
Revision history for this message
Leonard Richardson (leonardr) wrote :

This branch looks good with some trivial cleanup suggested in IRC, one minor change also suggested in IRC, and one major caveat:

The minor change: test_generateIncrementalDiff is pretty confusing, with lots of branches and lots of nearly-identical commits. It needs at least a comment up-front describing what's in the two revisions being diffed, and how the precursor and prerequisite branches affect this.

It might also be easier to understand if you defined a helper method to create a new branch *and its first commit*. This would make it clear which commits are setup, reflecting the "initial" states of the branches, and which commits are the ones leading up to the endpoint of the incremental diff. But an explanatory comment is good enough to get my approval.

The caveat: this branch introduces a new source dependency, difftacular, which was written by Aaron in July. Since it was written in-house, I think difftacular needs to go through the code review process, just like the lazr packages that are used in Launchpad. Fortunately, the entire difftacular project isn't much longer than 800 lines, so it shouldn't be too difficult for me to do the review.

review: Approve
Revision history for this message
Leonard Richardson (leonardr) wrote :

Oh, another change I suggested which Aaron carried through was removing the exported() calls from IIncrementalDiff. Those are for publishing fields through the web service, and IIncrementalDiff isn't being published yet.

Revision history for this message
Leonard Richardson (leonardr) wrote :

OK, I've done a review of the difftastic codebase and I see no reason why it can't be used in Launchpad. I do have one possible performance improvement, and a number of changes to make the tests more clear.

1. "foo" and "bar" are fine for filenames within the test branches,
but they really hurt comprehension when used as variable names
for the branches themselves. In the helper methods, can you call
the branches 'initial' and 'merged_in' or something that reflects
their history?

Outside the helper methods, you can call them whatever's
helpful. For instance, in test_mainline_diff, I believe
'foo' (aka 'initial') could be called 'mainline' and 'bar' (aka
'merged_in') could be called 'ignored'.

2. typo: "emtpy commit"

3. test_diff_ignore_branches calls
create_unignored_merge_scenario() to do its setup. This sounds
like a contradiction, but we're actually checking that only
*specified* branches are ignored. A docstring would make it clear
that we're checking that the diff ignores the merge of the "bar"
branch, but not the merge of the "unignored" branch. Similarly
for ignore_old_revisions--what's being ignored and what's being
included? It's hard to figure out.

Making the commits that are being ignored really obviously
destructive would also help.

3. In generate_diff.py#apply_merges(), do you need to call
merger.make_preview_transform and transform.get_preview_tree
within the for loop? Unless those methods modify 'merger'
in-place, I think they can be moved outside and run only once.

Revision history for this message
Aaron Bentley (abentley) wrote :

1. "foo" is actually the tree whose branch will be diffed. I don't think "initial" describes that any better than "foo". "merged_in" is fine, but I think "merge_input" is better.

2. Sure

3. Yes, I need it. The output of get_preview_tree is fed back into the subsequent merge. Without that, you would generate a bogus merge and likely violate the TreeTransform API.

Revision history for this message
Brad Crittenden (bac) wrote :

Is this approved branch ready to land or are you blocked? If you have abandoned the work please change the MP status to "Rejected."

Revision history for this message
Aaron Bentley (abentley) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 11/04/2010 11:08 PM, Brad Crittenden wrote:
> Is this approved branch ready to land or are you blocked? If you have abandoned the work please change the MP status to "Rejected."

These changes will be landed as part of the follow-on branch
incremental-diff-jobs. Please see my comment at
https://code.launchpad.net/~abentley/launchpad/incremental-diff-job/+merge/36881
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkzUBVsACgkQ0F+nu1YWqI285wCfQd6GoKGnYBtp37QgqMIs2RvA
9n4AnRU1u4d8MDX+jvBBF5vWqoQsJeYE
=mGMI
-----END PGP SIGNATURE-----

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added symlink 'bzrplugins/difftacular'
=== target is u'../sourcecode/difftacular/'
=== modified file 'lib/lp/code/configure.zcml'
--- lib/lp/code/configure.zcml 2010-10-26 13:52:43 +0000
+++ lib/lp/code/configure.zcml 2010-10-29 15:33:57 +0000
@@ -233,6 +233,7 @@
233 review_diff233 review_diff
234 next_preview_diff_job234 next_preview_diff_job
235 preview_diff235 preview_diff
236 getIncrementalDiffs
236 votes237 votes
237 all_comments238 all_comments
238 related_bugs239 related_bugs
@@ -245,7 +246,8 @@
245 isValidTransition246 isValidTransition
246 getUnlandedSourceBranchRevisions247 getUnlandedSourceBranchRevisions
247 root_message_id248 root_message_id
248 getUsersVoteReference"/>249 getUsersVoteReference
250 generateIncrementalDiff"/>
249 <allow interface="lp.code.interfaces.branchtarget.IHasBranchTarget"/>251 <allow interface="lp.code.interfaces.branchtarget.IHasBranchTarget"/>
250 <require252 <require
251 permission="launchpad.Edit"253 permission="launchpad.Edit"
@@ -879,6 +881,10 @@
879 <class class="lp.code.model.diff.Diff">881 <class class="lp.code.model.diff.Diff">
880 <allow interface="lp.code.interfaces.diff.IDiff" />882 <allow interface="lp.code.interfaces.diff.IDiff" />
881 </class>883 </class>
884 <class class="lp.code.model.diff.IncrementalDiff">
885 <allow interface="lp.code.interfaces.diff.IDiff" />
886 <allow interface="lp.code.interfaces.diff.IIncrementalDiff" />
887 </class>
882 <class class="lp.code.model.diff.StaticDiff">888 <class class="lp.code.model.diff.StaticDiff">
883 <allow interface="lp.code.interfaces.diff.IStaticDiff" />889 <allow interface="lp.code.interfaces.diff.IStaticDiff" />
884 </class>890 </class>
885891
=== modified file 'lib/lp/code/interfaces/diff.py'
--- lib/lp/code/interfaces/diff.py 2010-08-20 20:31:18 +0000
+++ lib/lp/code/interfaces/diff.py 2010-10-29 15:33:57 +0000
@@ -9,6 +9,7 @@
99
10__all__ = [10__all__ = [
11 'IDiff',11 'IDiff',
12 'IIncrementalDiff',
12 'IPreviewDiff',13 'IPreviewDiff',
13 'IStaticDiff',14 'IStaticDiff',
14 'IStaticDiffSource',15 'IStaticDiffSource',
@@ -29,6 +30,7 @@
29 )30 )
3031
31from canonical.launchpad import _32from canonical.launchpad import _
33from lp.code.interfaces.revision import IRevision
3234
3335
34class IDiff(Interface):36class IDiff(Interface):
@@ -62,6 +64,23 @@
62 readonly=True))64 readonly=True))
6365
6466
67class IIncrementalDiff(Interface):
68 """An incremental diff for a merge proposal."""
69
70 diff = Reference(IDiff, title=_('The Diff object.'), readonly=True)
71
72 # The schema for the Reference gets patched in _schema_circular_imports.
73 branch_merge_proposal = Reference(
74 Interface, readonly=True,
75 title=_('The branch merge proposal that diff relates to.'))
76
77 old_revision = Reference(
78 IRevision, readonly=True, title=_('The old revision of the diff.'))
79
80 new_revision = Reference(
81 IRevision, readonly=True, title=_('The new revision of the diff.'))
82
83
65class IStaticDiff(Interface):84class IStaticDiff(Interface):
66 """A diff with a fixed value, i.e. between two revisions."""85 """A diff with a fixed value, i.e. between two revisions."""
6786
6887
=== modified file 'lib/lp/code/model/branchmergeproposal.py'
--- lib/lp/code/model/branchmergeproposal.py 2010-10-19 00:44:24 +0000
+++ lib/lp/code/model/branchmergeproposal.py 2010-10-29 15:33:57 +0000
@@ -50,6 +50,7 @@
50 SQLBase,50 SQLBase,
51 sqlvalues,51 sqlvalues,
52 )52 )
53from canonical.launchpad.interfaces.lpstorm import IMasterStore
53from lp.code.enums import (54from lp.code.enums import (
54 BranchMergeProposalStatus,55 BranchMergeProposalStatus,
55 CodeReviewVote,56 CodeReviewVote,
@@ -78,7 +79,7 @@
78from lp.code.model.branchrevision import BranchRevision79from lp.code.model.branchrevision import BranchRevision
79from lp.code.model.codereviewcomment import CodeReviewComment80from lp.code.model.codereviewcomment import CodeReviewComment
80from lp.code.model.codereviewvote import CodeReviewVoteReference81from lp.code.model.codereviewvote import CodeReviewVoteReference
81from lp.code.model.diff import PreviewDiff82from lp.code.model.diff import Diff, IncrementalDiff, PreviewDiff
82from lp.registry.interfaces.person import (83from lp.registry.interfaces.person import (
83 IPerson,84 IPerson,
84 validate_public_person,85 validate_public_person,
@@ -783,6 +784,45 @@
783 Store.of(self).flush()784 Store.of(self).flush()
784 return self.preview_diff785 return self.preview_diff
785786
787 def generateIncrementalDiff(self, old_revision, new_revision, diff=None):
788 """Generate an incremental diff for the merge proposal.
789
790 :param old_revision: The `Revision` to generate the diff from.
791 :param new_revision: The `Revision` to generate the diff to.
792 :param diff: If supplied, a pregenerated `Diff`.
793 """
794 if diff is None:
795 source_branch = self.source_branch.getBzrBranch()
796 ignore_branches = [self.target_branch.getBzrBranch()]
797 if self.prerequisite_branch is not None:
798 ignore_branches.append(
799 self.prerequisite_branch.getBzrBranch())
800 diff = Diff.generateIncrementalDiff(
801 old_revision, new_revision, source_branch, ignore_branches)
802 incremental_diff = IncrementalDiff()
803 incremental_diff.diff = diff
804 incremental_diff.branch_merge_proposal = self
805 incremental_diff.old_revision = old_revision
806 incremental_diff.new_revision = new_revision
807 IMasterStore(IncrementalDiff).add(incremental_diff)
808 return incremental_diff
809
810 def getIncrementalDiffs(self, revision_list):
811 """Return a list of diffs for the specified revisions.
812
813 :param revision_list: A list of tuples of (`Revision`, `Revision`).
814 The first revision in the tuple is the old revision. The second
815 is the new revision.
816 :return: A list of IncrementalDiffs in the same order as the supplied
817 Revisions.
818 """
819 diffs = Store.of(self).find(IncrementalDiff,
820 IncrementalDiff.branch_merge_proposal_id == self.id)
821 diff_dict = dict(
822 ((diff.old_revision, diff.new_revision), diff)
823 for diff in diffs)
824 return [diff_dict.get(revisions) for revisions in revision_list]
825
786 @property826 @property
787 def revision_end_date(self):827 def revision_end_date(self):
788 """The cutoff date for showing revisions.828 """The cutoff date for showing revisions.
789829
=== modified file 'lib/lp/code/model/diff.py'
--- lib/lp/code/model/diff.py 2010-10-03 15:30:06 +0000
+++ lib/lp/code/model/diff.py 2010-10-29 15:33:57 +0000
@@ -4,10 +4,11 @@
4"""Implementation classes for IDiff, etc."""4"""Implementation classes for IDiff, etc."""
55
6__metaclass__ = type6__metaclass__ = type
7__all__ = ['Diff', 'PreviewDiff', 'StaticDiff']7__all__ = ['Diff', 'IncrementalDiff', 'PreviewDiff', 'StaticDiff']
88
9from contextlib import nested
10from cStringIO import StringIO
9import sys11import sys
10from cStringIO import StringIO
1112
12from uuid import uuid113from uuid import uuid1
1314
@@ -18,6 +19,7 @@
18 parse_patches,19 parse_patches,
19 Patch,20 Patch,
20 )21 )
22from bzrlib.plugins.difftacular.generate_diff import diff_ignore_branches
21from lazr.delegates import delegates23from lazr.delegates import delegates
22import simplejson24import simplejson
23from sqlobject import (25from sqlobject import (
@@ -44,10 +46,12 @@
44from lp.app.errors import NotFoundError46from lp.app.errors import NotFoundError
45from lp.code.interfaces.diff import (47from lp.code.interfaces.diff import (
46 IDiff,48 IDiff,
49 IIncrementalDiff,
47 IPreviewDiff,50 IPreviewDiff,
48 IStaticDiff,51 IStaticDiff,
49 IStaticDiffSource,52 IStaticDiffSource,
50 )53 )
54from lp.codehosting.bzrutils import read_locked
5155
5256
53class Diff(SQLBase):57class Diff(SQLBase):
@@ -194,9 +198,14 @@
194 diff_content = StringIO()198 diff_content = StringIO()
195 show_diff_trees(from_tree, to_tree, diff_content, old_label='',199 show_diff_trees(from_tree, to_tree, diff_content, old_label='',
196 new_label='')200 new_label='')
201 return klass.fromFileAtEnd(diff_content, filename)
202
203 @classmethod
204 def fromFileAtEnd(cls, diff_content, filename=None):
205 """Make a Diff from a file object that is currently at its end."""
197 size = diff_content.tell()206 size = diff_content.tell()
198 diff_content.seek(0)207 diff_content.seek(0)
199 return klass.fromFile(diff_content, size, filename)208 return cls.fromFile(diff_content, size, filename)
200209
201 @classmethod210 @classmethod
202 def fromFile(cls, diff_content, size, filename=None):211 def fromFile(cls, diff_content, size, filename=None):
@@ -257,6 +266,30 @@
257 file_stats[path] = tuple(patch.stats_values()[:2])266 file_stats[path] = tuple(patch.stats_values()[:2])
258 return file_stats267 return file_stats
259268
269 @classmethod
270 def generateIncrementalDiff(cls, old_revision, new_revision,
271 source_branch, ignore_branches):
272 """Return a Diff whose contents are an incremental diff.
273
274 The Diff's contents will show the changes made between old_revision
275 and new_revision, except those changes introduced by the
276 ignore_branches.
277
278 :param old_revision: The `Revision` to show changes from.
279 :param new_revision: The `Revision` to show changes to.
280 :param source_branch: The bzr branch containing these revisions.
281 :param ignore_brances: A collection of branches to ignore merges from.
282 :return: a `Diff`.
283 """
284 diff_content = StringIO()
285 read_locks = [read_locked(branch) for branch in [source_branch] +
286 ignore_branches]
287 with nested(*read_locks):
288 diff_ignore_branches(
289 source_branch, ignore_branches, old_revision.revision_id,
290 new_revision.revision_id, diff_content)
291 return cls.fromFileAtEnd(diff_content)
292
260293
261class StaticDiff(SQLBase):294class StaticDiff(SQLBase):
262 """A diff from one revision to another."""295 """A diff from one revision to another."""
@@ -305,6 +338,36 @@
305 diff.destroySelf()338 diff.destroySelf()
306339
307340
341class IncrementalDiff(Storm):
342 """See `IIncrementalDiff."""
343
344 implements(IIncrementalDiff)
345
346 delegates(IDiff, context='diff')
347
348 __storm_table__ = 'IncrementalDiff'
349
350 id = Int(primary=True, allow_none=False)
351
352 diff_id = Int(name='diff', allow_none=False)
353
354 diff = Reference(diff_id, 'Diff.id')
355
356 branch_merge_proposal_id = Int(
357 name='branch_merge_proposal', allow_none=False)
358
359 branch_merge_proposal = Reference(
360 branch_merge_proposal_id, "BranchMergeProposal.id")
361
362 old_revision_id = Int(name='old_revision', allow_none=False)
363
364 old_revision = Reference(old_revision_id, 'Revision.id')
365
366 new_revision_id = Int(name='new_revision', allow_none=False)
367
368 new_revision = Reference(new_revision_id, 'Revision.id')
369
370
308class PreviewDiff(Storm):371class PreviewDiff(Storm):
309 """See `IPreviewDiff`."""372 """See `IPreviewDiff`."""
310 implements(IPreviewDiff)373 implements(IPreviewDiff)
311374
=== modified file 'lib/lp/code/model/tests/test_branchmergeproposal.py'
--- lib/lp/code/model/tests/test_branchmergeproposal.py 2010-10-27 14:20:21 +0000
+++ lib/lp/code/model/tests/test_branchmergeproposal.py 2010-10-29 15:33:57 +0000
@@ -1829,5 +1829,46 @@
1829 self.assertRevisionGroups(bmp, expected_groups)1829 self.assertRevisionGroups(bmp, expected_groups)
18301830
18311831
1832class TestBranchMergeProposalGetIncrementalDiffs(TestCaseWithFactory):
1833
1834 layer = LaunchpadFunctionalLayer
1835
1836 def test_getIncrementalDiffs(self):
1837 """getIncrementalDiffs returns the requested values or None.
1838
1839 None is returned if there is no IncrementalDiff for the requested
1840 revision pair and branch_merge_proposal.
1841 """
1842 bmp = self.factory.makeBranchMergeProposal()
1843 diff1 = self.factory.makeIncrementalDiff(merge_proposal=bmp)
1844 diff2 = self.factory.makeIncrementalDiff(merge_proposal=bmp)
1845 diff3 = self.factory.makeIncrementalDiff()
1846 result = bmp.getIncrementalDiffs([
1847 (diff1.old_revision, diff1.new_revision),
1848 (diff2.old_revision, diff2.new_revision),
1849 # Wrong merge proposal
1850 (diff3.old_revision, diff3.new_revision),
1851 # Mismatched revisions
1852 (diff1.old_revision, diff2.new_revision),
1853 ])
1854 self.assertEqual([diff1, diff2, None, None], result)
1855
1856 def test_getIncrementalDiffs_respects_input_order(self):
1857 """The order of the output follows the input order."""
1858 bmp = self.factory.makeBranchMergeProposal()
1859 diff1 = self.factory.makeIncrementalDiff(merge_proposal=bmp)
1860 diff2 = self.factory.makeIncrementalDiff(merge_proposal=bmp)
1861 result = bmp.getIncrementalDiffs([
1862 (diff1.old_revision, diff1.new_revision),
1863 (diff2.old_revision, diff2.new_revision),
1864 ])
1865 self.assertEqual([diff1, diff2], result)
1866 result = bmp.getIncrementalDiffs([
1867 (diff2.old_revision, diff2.new_revision),
1868 (diff1.old_revision, diff1.new_revision),
1869 ])
1870 self.assertEqual([diff2, diff1], result)
1871
1872
1832def test_suite():1873def test_suite():
1833 return TestLoader().loadTestsFromName(__name__)1874 return TestLoader().loadTestsFromName(__name__)
18341875
=== modified file 'lib/lp/code/model/tests/test_diff.py'
--- lib/lp/code/model/tests/test_diff.py 2010-10-26 15:47:24 +0000
+++ lib/lp/code/model/tests/test_diff.py 2010-10-29 15:33:57 +0000
@@ -12,6 +12,7 @@
12from unittest import TestLoader12from unittest import TestLoader
1313
14from bzrlib import trace14from bzrlib import trace
15from bzrlib.patches import InsertLine, parse_patches, RemoveLine
15import transaction16import transaction
16from zope.security.proxy import removeSecurityProxy17from zope.security.proxy import removeSecurityProxy
1718
@@ -24,6 +25,7 @@
24from lp.app.errors import NotFoundError25from lp.app.errors import NotFoundError
25from lp.code.interfaces.diff import (26from lp.code.interfaces.diff import (
26 IDiff,27 IDiff,
28 IIncrementalDiff,
27 IPreviewDiff,29 IPreviewDiff,
28 IStaticDiff,30 IStaticDiff,
29 IStaticDiffSource,31 IStaticDiffSource,
@@ -521,5 +523,87 @@
521 NotFoundError, diff.getFileByName, 'preview.diff')523 NotFoundError, diff.getFileByName, 'preview.diff')
522524
523525
526class TestIncrementalDiff(DiffTestCase):
527 """Test that IncrementalDiff objects work."""
528
529 layer = LaunchpadFunctionalLayer
530
531 def test_providesInterface(self):
532 incremental_diff = self.factory.makeIncrementalDiff()
533 verifyObject(IIncrementalDiff, incremental_diff)
534
535 @staticmethod
536 def diff_changes(diff_bytes):
537 inserted = []
538 removed = []
539 for patch in parse_patches(diff_bytes.splitlines(True)):
540 for hunk in patch.hunks:
541 for line in hunk.lines:
542 if isinstance(line, InsertLine):
543 inserted.append(line.contents)
544 if isinstance(line, RemoveLine):
545 removed.append(line.contents)
546 return inserted, removed
547
548 def test_generateIncrementalDiff(self):
549 """generateIncrementalDiff works.
550
551 Changes merged from the prerequisite and target are ignored in the
552 diff.
553
554 We generate an incremental diff from old_revision_id to
555 new_revision_id.
556
557 old_revision_id has:
558 a
559 b
560 e
561
562 new_revision_id has:
563 d
564 a
565 c
566 e
567 f
568
569 Because the prerequisite branch adds "d", this change is ignored.
570 Because the target branch adds "f", this change is ignored.
571 So the incremental diff shows that "c" was added and "b" was removed.
572 """
573 self.useBzrBranches(direct_database=True)
574 prerequisite_branch = self.factory.makeAnyBranch()
575 bmp = self.factory.makeBranchMergeProposal(
576 prerequisite_branch=prerequisite_branch)
577 target_branch = self.createBzrBranch(bmp.target_branch)
578 old_revision_id = self.commitFile(
579 bmp.target_branch, 'foo', 'a\nb\ne\n')
580 old_revision = self.factory.makeRevision(rev_id=old_revision_id)
581 source_branch = self.createBzrBranch(
582 bmp.source_branch, target_branch)
583 self.commitFile(bmp.source_branch, 'foo', 'a\nc\ne\n')
584 prerequisite = self.createBzrBranch(
585 bmp.prerequisite_branch, target_branch)
586 prerequisite_revision = self.commitFile(bmp.prerequisite_branch,
587 'foo', 'd\na\nb\ne\n')
588 merge_parent = self.commitFile(bmp.target_branch, 'foo',
589 'a\nb\ne\nf\n')
590 source_branch.repository.fetch(target_branch.repository,
591 revision_id=merge_parent)
592 self.commitFile(
593 bmp.source_branch, 'foo', 'a\nc\ne\nf\n', [merge_parent])
594 source_branch.repository.fetch(prerequisite.repository,
595 revision_id=prerequisite_revision)
596 new_revision_id = self.commitFile(
597 bmp.source_branch, 'foo', 'd\na\nc\ne\nf\n',
598 [prerequisite_revision])
599 new_revision = self.factory.makeRevision(rev_id=new_revision_id)
600 incremental_diff = bmp.generateIncrementalDiff(
601 old_revision, new_revision)
602 transaction.commit()
603 inserted, removed = self.diff_changes(incremental_diff.text)
604 self.assertEqual(['c\n'], inserted)
605 self.assertEqual(['b\n'], removed)
606
607
524def test_suite():608def test_suite():
525 return TestLoader().loadTestsFromName(__name__)609 return TestLoader().loadTestsFromName(__name__)
526610
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2010-10-28 09:11:36 +0000
+++ lib/lp/testing/factory.py 2010-10-29 15:33:57 +0000
@@ -1266,6 +1266,18 @@
1266 preview_diff.target_revision_id = self.getUniqueUnicode()1266 preview_diff.target_revision_id = self.getUniqueUnicode()
1267 return preview_diff1267 return preview_diff
12681268
1269 def makeIncrementalDiff(self, merge_proposal=None, old_revision=None,
1270 new_revision=None):
1271 diff = self.makeDiff()
1272 if merge_proposal is None:
1273 merge_proposal = self.makeBranchMergeProposal()
1274 if old_revision is None:
1275 old_revision = self.makeRevision()
1276 if new_revision is None:
1277 new_revision = self.makeRevision()
1278 return merge_proposal.generateIncrementalDiff(
1279 old_revision, new_revision, diff)
1280
1269 def makeStaticDiff(self):1281 def makeStaticDiff(self):
1270 return StaticDiff.acquireFromText(1282 return StaticDiff.acquireFromText(
1271 self.getUniqueUnicode(), self.getUniqueUnicode(),1283 self.getUniqueUnicode(), self.getUniqueUnicode(),
12721284
=== modified file 'utilities/sourcedeps.conf'
--- utilities/sourcedeps.conf 2010-10-25 15:23:38 +0000
+++ utilities/sourcedeps.conf 2010-10-29 15:33:57 +0000
@@ -5,6 +5,7 @@
5bzr-svn lp:~launchpad-pqm/bzr-svn/devel;revno=27105bzr-svn lp:~launchpad-pqm/bzr-svn/devel;revno=2710
6cscvs lp:~launchpad-pqm/launchpad-cscvs/devel;revno=4326cscvs lp:~launchpad-pqm/launchpad-cscvs/devel;revno=432
7dulwich lp:~launchpad-pqm/dulwich/devel;revno=4247dulwich lp:~launchpad-pqm/dulwich/devel;revno=424
8difftacular lp:difftacular;revno=6
8loggerhead lp:~launchpad-pqm/loggerhead/devel;revno=1769loggerhead lp:~launchpad-pqm/loggerhead/devel;revno=176
9lpreview lp:~launchpad-pqm/bzr-lpreview/devel;revno=2310lpreview lp:~launchpad-pqm/bzr-lpreview/devel;revno=23
10mailman lp:~launchpad-pqm/mailman/2.1;revno=97611mailman lp:~launchpad-pqm/mailman/2.1;revno=976

Subscribers

People subscribed via source and target branches

to status/vote changes: