PQM

Merge lp:~oddbloke/pqm/merge-directives into lp:pqm

Proposed by Dan Watkins
Status: Work in progress
Proposed branch: lp:~oddbloke/pqm/merge-directives
Merge into: lp:pqm
Prerequisite: lp:~oddbloke/pqm/fix-tests
Diff against target: 793 lines (+488/-20) (has conflicts)
7 files modified
.bzrignore (+1/-0)
pqm/__init__.py (+79/-0)
pqm/script.py (+164/-8)
pqm/tests/test_pqm.py (+201/-4)
tests/Makefile.am (+2/-1)
tests/bzr-merge-2.sh (+20/-0)
tests/test-framework (+21/-7)
Text conflict in pqm/__init__.py
Text conflict in pqm/script.py
Text conflict in pqm/tests/test_pqm.py
To merge this branch: bzr merge lp:~oddbloke/pqm/merge-directives
Reviewer Review Type Date Requested Status
Robert Collins Needs Resubmitting
Review via email: mp+833@code.launchpad.net

This proposal supersedes a proposal from 2008-07-09.

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote : Posted in a previous version of this proposal

overall good.

A few issues:

 - uses more shell tests rather than python unit tests
 - the new Command class won't render correctly in the web GUI
 - I don't like the merge_callback lambda usage, its unobvious and doesn't seem necessary.

overall - resubmit

review: Disapprove
Revision history for this message
Dan Watkins (oddbloke) wrote :

To address Robert's issues:

> - uses more shell tests rather than python unit tests
I'm not sure what the Python tests are missing. If you could give me some suggestions, I'd be happy to put them into practice.

> - the new Command class won't render correctly in the web GUI
Fixed.

> - I don't like the merge_callback lambda usage, its unobvious and doesn't seem necessary.
I agree. Fixed. In the process, replay merge became its own Command (rather than being a part of CommandRunner) to stop my head exploding because of the broken merge abstraction we had.

Revision history for this message
Robert Collins (lifeless) wrote :

On Sun, 2008-08-24 at 03:29 +0000, Daniel Watkins wrote:
> To address Robert's issues:
>
> > - uses more shell tests rather than python unit tests
> I'm not sure what the Python tests are missing. If you could give me some suggestions, I'd be happy to put them into practice.

Well, there are new shell tests; either they are redundant (in which
case, remove em :)) or they test something not tested in the python
tests (in which case move them into python tests).

> > - the new Command class won't render correctly in the web GUI
> Fixed.
>
> > - I don't like the merge_callback lambda usage, its unobvious and doesn't seem necessary.
> I agree. Fixed. In the process, replay merge became its own Command (rather than being a part of CommandRunner) to stop my head exploding because of the broken merge abstraction we had.

Cool - thanks.

-Rob

--
GPG key available at: <http://www.robertcollins.net/keys.txt>.

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

Were you going to remove the shell tests?

Revision history for this message
Dan Watkins (oddbloke) wrote :

On Wed, 2008-11-26 at 06:40 +0000, Tim Penhey wrote:
> Were you going to remove the shell tests?
I believe the intent is to replace them with Python unit tests, in time.

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

On Wed, 26 Nov 2008 22:51:31 Daniel Watkins wrote:
> On Wed, 2008-11-26 at 06:40 +0000, Tim Penhey wrote:
> > Were you going to remove the shell tests?
>
> I believe the intent is to replace them with Python unit tests, in
> time.

OK, I'll look to include this in my integration branch shortly (not
tonight).

Revision history for this message
Robert Collins (lifeless) wrote :

Needs conflicts fixing at minimum.

review: Needs Resubmitting

Unmerged revisions

181. By Dan Watkins

Readded replay merge as ReplayMergeCommand.

180. By Dan Watkins

Removed use of merge_callback.

179. By Dan Watkins

Refactored merge code from Command to MergeCommand.

178. By Dan Watkins

Removed replay legacy command.

177. By Dan Watkins

ExtendedMergeCommands now work with the UI correctly.

176. By Dan Watkins

Merged pqm.dev r183.

175. By Dan Watkins

Fixed failing tests.

174. By Dan Watkins

Merged pqm.dev r182, without fixing tests.

173. By Dan Watkins

Fixed issues with PGP headers and footers in merge directive mail.

172. By Dan Watkins

Modified test to step around issues with detecting which VCS a branch uses.

Updating diff...

An updated diff will be available in a few minutes. Reload to see the changes.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2009-08-30 02:09:42 +0000
3+++ .bzrignore 2010-05-04 16:39:23 +0000
4@@ -8,6 +8,7 @@
5 configure
6 autotools/*
7 tests/.gnupg/*
8+./bzr
9 twistd.log*
10 tests/workdir
11 bzr
12
13=== modified file 'pqm/__init__.py'
14--- pqm/__init__.py 2010-04-20 12:11:40 +0000
15+++ pqm/__init__.py 2010-05-04 16:39:23 +0000
16@@ -25,9 +25,21 @@
17 import re
18 import stat
19 import string
20+from StringIO import StringIO
21 import sys
22
23+<<<<<<< TREE
24 from pqm.core import do_mkdir
25+=======
26+from bzrlib import (
27+ errors,
28+ merge_directive,
29+ testament,
30+ )
31+
32+from PQMConfigParser import ConfigParser
33+
34+>>>>>>> MERGE-SOURCE
35 from pqm.errors import PQMException, PQMTlaFailure
36 from pqm.script import Script
37
38@@ -420,20 +432,85 @@
39 return output
40
41 def do_star_merge(self, sender, from_branch, local_dir):
42+<<<<<<< TREE
43 import bzrlib.errors
44+=======
45+ return self._do_bzr_merge(sender, None, None, local_dir, from_branch,
46+ None)
47+
48+ def do_bzr_merge(self, sender, revision_id, testament_sha1,
49+ local_dir, from_branch=None, bundle=None):
50+ if None in (revision_id, testament_sha1):
51+ raise PQMTlaFailure(sender, ['required argument missing'])
52+ return self._do_bzr_merge(sender, revision_id, testament_sha1,
53+ local_dir, from_branch, bundle)
54+
55+ def _do_bzr_merge(self, sender, revision_id, testament_sha1, local_dir,
56+ from_branch, bundle):
57+ from bzrlib.branch import Branch
58+ from bzrlib.bundle.apply_bundle import install_bundle
59+ from bzrlib.bundle import serializer as bundle_serializer
60+ from bzrlib.merge import Merger, Merge3Merger
61+>>>>>>> MERGE-SOURCE
62 from bzrlib.workingtree import WorkingTree
63 tree = WorkingTree.open(local_dir)
64 tree.lock_write()
65 try:
66+<<<<<<< TREE
67 try:
68 return self._do_star_merge(sender, from_branch, local_dir, tree)
69 except bzrlib.errors.UnrelatedBranches:
70 raise PQMTlaFailure(sender,
71 ['Branches have no common ancestor, and no merge base'
72 ' revision was specified.'])
73+=======
74+ merger = Merger(tree.branch, this_tree=tree)
75+ merger.check_basis(True)
76+ if from_branch is None and bundle is None:
77+ raise PQMTlaFailure(sender,
78+ ['Either a branch or a bundle must be supplied'])
79+
80+ if bundle is not None:
81+ other_branch = tree.branch
82+ reader = bundle_serializer.read_bundle(StringIO(bundle))
83+ install_bundle(other_branch.repository, reader)
84+ else:
85+ other_branch = Branch.open(from_branch)
86+ if testament_sha1 is not None:
87+ my_testament = testament.StrictTestament3.from_revision(
88+ other_branch.repository, revision_id)
89+ if my_testament.as_sha1() != testament_sha1:
90+ raise PQMTlaFailure(sender,
91+ ['Revision testament mismatch: "%s" is not %s.' %
92+ (my_testament.as_sha1(), testament_sha1)])
93+ if revision_id is None:
94+ revision_id = other_branch.last_revision()
95+ merger.set_other_revision(revision_id, other_branch)
96+ merger.find_base()
97+ if merger.base_rev_id == merger.other_rev_id:
98+ raise PQMTlaFailure(sender, ['Nothing to merge.'])
99+ merger.backup_files = False
100+ merger.merge_type = Merge3Merger
101+ merger.set_interesting_files(None)
102+ merger.show_base = False
103+ merger.reprocess = False
104+ conflicts = merger.do_merge()
105+ merger.set_pending()
106+ if conflicts:
107+ error_lines = ['Conflicts during merge: %s' % conflicts]
108+ tree.lock_read()
109+ try:
110+ for conflict in tree.conflicts():
111+ error_lines.append(str(conflict))
112+ finally:
113+ tree.unlock()
114+ raise PQMTlaFailure(sender, error_lines)
115+ return ["merge successful"]
116+>>>>>>> MERGE-SOURCE
117 finally:
118 tree.unlock()
119
120+<<<<<<< TREE
121 def _do_star_merge(self, sender, from_branch, local_dir, tree):
122 from bzrlib.merge import Merger, Merge3Merger
123 from bzrlib.tag import _merge_tags_if_possible
124@@ -462,6 +539,8 @@
125 _merge_tags_if_possible(merger.other_branch, tree.branch)
126 return ["merge successful"]
127
128+=======
129+>>>>>>> MERGE-SOURCE
130 def make_local_dir(self, sender, branch_spec, output_dir):
131 from bzrlib.branch import Branch, BranchReferenceFormat
132 import bzrlib.bzrdir as bzrdir
133
134=== modified file 'pqm/script.py'
135--- pqm/script.py 2010-04-21 22:38:26 +0000
136+++ pqm/script.py 2010-05-04 16:39:23 +0000
137@@ -36,6 +36,8 @@
138 import config_manager
139 import subunit.test_results
140
141+from bzrlib import merge_directive
142+import bzrlib.errors
143 from pqm.errors import PQMCmdFailure, PQMException, PQMTlaFailure
144
145
146@@ -192,6 +194,7 @@
147 pgp_re = re.compile('^-----BEGIN PGP.*MESSAGE')
148 pgp_end_re = re.compile('^-----BEGIN PGP SIG')
149 # parser for merge recognition
150+ replay_re = re.compile('^replay (\S+/\S+)\s+(\S+/\S+)\s*$')
151 star_re = re.compile('^star-merge (\S+/\S+)\s+(\S+/\S+)\s*$')
152 # parse matcher for the debug command
153 debug_re = re.compile('^debug')
154@@ -293,18 +296,59 @@
155 result.append(line)
156 return result
157
158+ def getRawLines(self):
159+ if not self.readComplete:
160+ self._read()
161+ return self.msg.get_payload().splitlines(True)
162+
163 def getCommands(self):
164 """Get the actual command lines from the script."""
165 self.logger.info("parsing commands")
166 result = []
167 legacy_lines = []
168+ try:
169+ md_lines = []
170+ to_skip = 0
171+ for line in self.getRawLines():
172+ if to_skip:
173+ to_skip -= 1
174+ continue
175+ if self.pgp_re.match(line):
176+ to_skip = 2
177+ continue
178+ if self.pgp_end_re.match(line):
179+ break
180+ md_lines.append(line)
181+ directive = merge_directive.MergeDirective.from_lines(md_lines)
182+ except bzrlib.errors.NotAMergeDirective:
183+ pass
184+ else:
185+ result.append(ExtendedMergeCommand(self,
186+ self._branch_spec_handler,
187+ self._configp,
188+ directive.revision_id,
189+ directive.testament_sha1,
190+ directive.message,
191+ directive.target_branch,
192+ directive.source_branch,
193+ directive.get_raw_bundle(),
194+ ))
195+ return result
196+
197 for line in self.getLines():
198 if not self.isCommand(line):
199 continue
200 # identify and construct commands
201+<<<<<<< TREE
202 star_match = EmailScript.star_re.match(line)
203 debug_match = EmailScript.debug_re.match(line)
204 any_match = star_match or debug_match
205+=======
206+ debug_match = Script.debug_re.match(line)
207+ replay_match = Script.replay_re.match(line)
208+ star_match = Script.star_re.match(line)
209+ any_match = debug_match or replay_match or star_match
210+>>>>>>> MERGE-SOURCE
211 if any_match and legacy_lines:
212 result.append(CommandRunner(self,
213 self._branch_spec_handler,
214@@ -323,8 +367,18 @@
215 elif debug_match:
216 result.append(DebugCommand(self,
217 self._branch_spec_handler,
218+<<<<<<< TREE
219 self._configp,
220 self.manager))
221+=======
222+ self._configp))
223+ elif replay_match:
224+ result.append(ReplayMergeCommand(self,
225+ self._branch_spec_handler,
226+ self._configp,
227+ replay_match.group(1),
228+ replay_match.group(2)))
229+>>>>>>> MERGE-SOURCE
230 else:
231 legacy_lines.append(line)
232 if legacy_lines:
233@@ -621,6 +675,7 @@
234 for top in os.listdir(possible_dir):
235 self.rm_rf(os.path.join(possible_dir, top))
236
237+<<<<<<< TREE
238 def do_merge(self, from_repo_revision, to_repo_revision, merge_name,
239 merge_method, line):
240 # Record the start time for elapsed time calculation.
241@@ -688,6 +743,8 @@
242 # Launchpad notices merges
243 self.reported = True
244
245+=======
246+>>>>>>> MERGE-SOURCE
247 def get_arch_impl(self):
248 # TODO: Tim Penhey, 2008-05-28
249 # Get rid of the imports from pqm module itself.
250@@ -946,6 +1003,7 @@
251 def run(self):
252 super(MergeCommand, self).run()
253 self.cleanup_wd()
254+<<<<<<< TREE
255 self.lp_mp = None
256 if self.launchpad is None:
257 self.from_branch_lp = None
258@@ -988,6 +1046,112 @@
259 self.manager.logger.error("Exception handling merge", exc_info=1)
260 self.fail_operation("Exception processing merge: %s" % e)
261 return CommandResult(self.successful, self.unrecognized, self.output, not self.reported)
262+=======
263+ self.do_merge(from_repo_revision=self.from_branch,
264+ to_repo_revision=self.to_branch,
265+ merge_name='star-merge',
266+ line='merge %s %s' % (self.from_branch, self.to_branch))
267+ return self.successful, self.unrecognized, self.output
268+>>>>>>> MERGE-SOURCE
269+
270+ def _do_merge(self, sender, dir):
271+ return self.get_vcs().do_star_merge(sender, self.from_branch, dir)
272+
273+ def do_merge(self, from_repo_revision, to_repo_revision, merge_name,
274+ line):
275+ sender = self.script.getSender()
276+ # Star-merge
277+ self.check_target(to_repo_revision, line)
278+ to_repo_revision, config = self.getBranchConfig(to_repo_revision)
279+ self.set_current_vcs(from_repo_revision, to_repo_revision)
280+ self.validate_revision(from_repo_revision)
281+ self.validate_revision(to_repo_revision)
282+ self.check_commit_regex(to_repo_revision, config)
283+ self.script.logger.info("current cwd is %s", os.getcwd())
284+ self.script.logger.info("getting working dir for %s", to_repo_revision)
285+ dir = self.get_wd(sender, to_repo_revision, config)
286+ origdir = os.getcwd()
287+ merge_line = 'Executing %s %s at %s' % (merge_name,
288+ from_repo_revision,
289+ time.strftime('%c'))
290+ self.log_with_status(self.script.logger, merge_line)
291+ self.output += [
292+ '\n',
293+ merge_line,
294+ '\n',
295+ ]
296+ self.wrap_command(self._do_merge, line, sender, dir)
297+ self.run_precommit(to_repo_revision, config, line, dir)
298+ os.chdir(origdir)
299+ self.log_with_status(self.script.logger, "success: %s", line)
300+ self.successful.append(line)
301+ self.output += ['\n', '%s succeeded at %s' % (merge_name, time.strftime('%c')), '\n']
302+ self.get_vcs().commit(sender, dir, self.commitmsg, to_repo_revision, config)
303+
304+
305+class ExtendedMergeCommand(MergeCommand):
306+
307+ def __init__(self, script, branch_spec_handler, configp, revision_id,
308+ testament_sha1, message, to_branch, from_branch=None,
309+ bundle=None):
310+
311+ MergeCommand.__init__(self, script, branch_spec_handler, configp,
312+ from_branch, to_branch)
313+ self.revision_id = revision_id
314+ self.testament_sha1 = testament_sha1
315+ self.message = message
316+ self.from_branch = from_branch
317+ self.bundle = bundle
318+
319+ def asHTML(self):
320+ print self.from_branch
321+ if self.from_branch is not None:
322+ s = " (%s)" % (str(self.from_branch),)
323+ else:
324+ s = ""
325+ return cgi.escape("Merge from bundle%s" % (s,))
326+
327+ def run(self):
328+ super(MergeCommand, self).run()
329+ self.cleanup_wd()
330+ if self.message is not None:
331+ self.commitmsg = self.message
332+ line = 'merge %s %s' % (self.from_branch, self.to_branch)
333+ self.do_merge(self.from_branch, self.to_branch, 'bzr-merge', line)
334+ return self.successful, self.unrecognized, self.output
335+
336+ def _do_merge(self, sender, dir):
337+ return self.get_vcs().do_bzr_merge(sender, self.revision_id,
338+ self.testament_sha1, dir,
339+ self.from_branch, self.bundle)
340+
341+ def __eq__(self, other):
342+ return (super(ExtendedMergeCommand, self).__eq__(other) and
343+ isinstance(other, ExtendedMergeCommand) and
344+ self.revision_id == other.revision_id and
345+ self.testament_sha1 == other.testament_sha1 and
346+ self.message == other.message and
347+ self.bundle == other.bundle)
348+
349+
350+class ReplayMergeCommand(MergeCommand):
351+
352+ def asHTML(self):
353+ return cgi.escape("Replay %s %s" % (self.from_branch,
354+ self.to_branch))
355+
356+ def run(self):
357+ super(MergeCommand, self).run()
358+ self.cleanup_wd()
359+ self.do_merge(from_repo_revision=self.from_branch,
360+ to_repo_revision=self.to_branch,
361+ merge_name='replay',
362+ line='replay %s %s' % (self.from_branch,
363+ self.to_branch))
364+ return self.successful, self.unrecognized, self.output
365+
366+ def _do_merge(self, sender, dir):
367+ return self.get_vcs().do_replay(sender, self.from_branch, dir)
368
369
370 class PrecommitCommand(Command):
371@@ -1121,7 +1285,6 @@
372
373 class CommandRunner(Command):
374 """This runs commands as lines one at a time."""
375- replay_re = re.compile('^replay (\S+/\S+)\s+(\S+/\S+)\s*$')
376 repo_cache_re = re.compile('^repo-cache-revision (\S+/\S+)\s*$')
377 repo_uncache_re = re.compile('^repo-uncache-revision (\S+/\S+)\s*$')
378 tag_re = re.compile('^tag (\S+/\S+)\s+(\S+/\S+)\s*$')
379@@ -1204,7 +1367,6 @@
380 # its a command of some sort
381 start_time = datetime.now()
382 patch_match = self.patch_re.match(line)
383- replay_match = self.replay_re.match(line)
384 repo_cache_match=self.repo_cache_re.match(line)
385 repo_uncache_match=self.repo_uncache_re.match(line)
386 tag_match=self.tag_re.match(line)
387@@ -1221,12 +1383,6 @@
388 self.accumulating_patch = True
389 elif self.accumulating_patch:
390 self.patch_content.append(line)
391- elif replay_match:
392- self.do_merge(from_repo_revision=replay_match.group(1),
393- to_repo_revision=replay_match.group(2),
394- merge_name='replay',
395- merge_method="do_replay",
396- line=line)
397 elif repo_cache_match:
398 # Cache a revision
399 repo_revision = repo_cache_match.group(1)
400
401=== modified file 'pqm/tests/test_pqm.py'
402--- pqm/tests/test_pqm.py 2010-04-19 02:40:26 +0000
403+++ pqm/tests/test_pqm.py 2010-05-04 16:39:23 +0000
404@@ -12,9 +12,18 @@
405 from pqm.core import PatchQueueManager
406 from pqm.errors import PQMCmdFailure, PQMException
407 from pqm.PQMConfigParser import ConfigParser
408+<<<<<<< TREE
409 from pqm.script import (
410 Command, CommandRunner, DebugCommand, EmailScript, MergeCommand)
411
412+=======
413+from pqm.script import (Command,
414+ CommandRunner,
415+ DebugCommand,
416+ ExtendedMergeCommand,
417+ MergeCommand,
418+ )
419+>>>>>>> MERGE-SOURCE
420
421 sample_message = dedent("""\
422 From: John.Citizen@example.com
423@@ -117,6 +126,51 @@
424 workdir=test-workdir
425 """)
426
427+sample_merge_directive = """\
428+From John.Citizen@example.com Sun Mar 11 20:19:38 2007
429+Return-Path: <John.Citizen@example.com>
430+X-Original-To: abentley
431+Delivered-To: abentley@localhost.localdomain
432+Received: from localhost.localdomain (localhost.localdomain [127.0.0.1])
433+ by localhost.localdomain (Postfix) with ESMTP id 6E01032E9F5
434+ for <abentley>; Sun, 11 Mar 2007 20:19:38 -0400 (EDT)
435+To: abentley@localhost.localdomain
436+From: John Citizen <John.Citizen@example.com>
437+Subject: This is my second commit message
438+Message-Id: <20070312001938.6E01032E9F5@localhost.localdomain>
439+Date: Sun, 11 Mar 2007 20:19:38 -0400 (EDT)
440+
441+# Bazaar merge directive format 1
442+# revision_id: john.citizen@example.com-20070312001559-\\
443+# 9jdb99jgb8dn1k5b
444+# message: Please merge this commit
445+# target_branch: http://example.com/target
446+# source_branch: http://example.com/source
447+# testament_sha1: 5cd628553ec98c056bd7eff4b8b72fce9961c53b
448+# timestamp: 2007-03-11 20:19:37 -0400
449+#
450+# Bazaar revision bundle v0.9
451+#
452+# message:
453+# This is my second commit message
454+# committer: John Citizen <John.Citizen@example.com>
455+# date: Sun 2007-03-11 20:15:59.841000080 -0400
456+
457+=== modified directory // last-changed:john.citizen@example.com-20070312001559
458+... -9jdb99jgb8dn1k5b
459+# revision id: john.citizen@example.com-20070312001559-9jdb99jgb8dn1k5b
460+# sha1: 5cd628553ec98c056bd7eff4b8b72fce9961c53b
461+# inventory sha1: 191c819cc7943e5e4140744cc04a7fe088897f35
462+# parent ids:
463+# john.citizen@example.com-20070312001321-qbz0l8mrp0csql1e
464+# base id: john.citizen@example.com-20070312001321-qbz0l8mrp0csql1e
465+# properties:
466+# branch-nick: example
467+
468+
469+"""
470+sample_bundle = ''.join(sample_merge_directive.splitlines(True)[22:])
471+
472
473 class QueueSetup(object):
474 """Setup a queue with mock messages in it."""
475@@ -198,6 +252,14 @@
476 return EmailScript(self.scriptname, logging, False, 54, handler,
477 configp, self.queue.manager)
478
479+
480+class TestQueueDirectory(TestWithQueueDirectory):
481+
482+ def testName(self):
483+ patch = pqm.Script('foo.script', logging, False, 0, None, None)
484+ self.assertEqual(patch.filename, 'foo.script')
485+ self.scriptname = 'fpp'
486+
487 def testFields(self):
488 script = self.getScript(sample_message)
489 self.assertEqual(script.getSender(), "John.Citizen@example.com")
490@@ -216,6 +278,26 @@
491 self.queue.manager)],
492 script.getCommands())
493
494+ def testMergeDirectiveFields(self):
495+ script = self.getScript(sample_merge_directive)
496+ self.assertEqual(script.getSender(),
497+ "John Citizen <John.Citizen@example.com>")
498+ self.assertEqual(script.getSubject(),
499+ "This is my second commit message")
500+ commands = script.getCommands()
501+ self.assertEqual([ExtendedMergeCommand(
502+ None,
503+ None,
504+ None,
505+ 'john.citizen@example.com-20070312001559-9jdb99jgb8dn1k5b',
506+ '5cd628553ec98c056bd7eff4b8b72fce9961c53b',
507+ 'Please merge this commit',
508+ 'http://example.com/target',
509+ 'http://example.com/source',
510+ sample_bundle,
511+ )],
512+ script.getCommands())
513+
514 def testGPGFields(self):
515 script = self.getScript(sample_signed_message)
516 self.assertEqual(script.getSender(), "whee@bar.com (Matthew Thomas)")
517@@ -273,7 +355,6 @@
518 self.assertEqual('bar\nfoo\n', content)
519
520
521-
522 # NOTDONEYET: move command recognition from CommandRunner to Script
523 # and commands should follow the command pattern rather than being strings.
524 #
525@@ -427,9 +508,10 @@
526 self.assertTrue(script.debug)
527
528
529-class FunctionalTestCommandRunner(unittest.TestCase):
530+class FunctionalTestCommandRunner(TestCaseWithTransport):
531
532 def setUp(self):
533+ super(FunctionalTestCommandRunner, self).setUp()
534 from bzrlib.bzrdir import BzrDir
535 from bzrlib.plugin import load_plugins
536 load_plugins()
537@@ -491,14 +573,18 @@
538 load_plugins()
539 tree = self.make_branch_and_tree("bzrbranch")
540 tree.smart_add(["bzrbranch"])
541- tree.commit("start branch.", verbose=False)
542+ tree.commit("start branch.", verbose=False, rev_id='revision-0')
543 tree.branch.bzrdir.sprout("bzrbranch-parent")
544 tree.branch.bzrdir.sprout("bzrbranch-public")
545 tree.branch.bzrdir.sprout("branch-contributor")
546 contrib_tree = BzrDir.open("branch-contributor").open_workingtree()
547+ self.build_tree_contents([("branch-contributor/NEWS",
548+ "This is brand-new\n")])
549+ contrib_tree.add(["NEWS"])
550+ contrib_tree.commit("add NEWS", rev_id='revision-1')
551 self.build_tree_contents([("branch-contributor/README", "Boo!\n")])
552 contrib_tree.add(["README"])
553- contrib_tree.commit("add README")
554+ contrib_tree.commit("add README", rev_id='revision-2')
555
556 def tearDown(self):
557 shutil.rmtree("bzrbranch")
558@@ -507,6 +593,9 @@
559 shutil.rmtree("bzrbranch-public")
560 super(BzrHandlerTestCase, self).tearDown()
561
562+
563+class TestBzrHandler(BzrHandlerTestCase):
564+
565 def test_commit(self):
566 from bzrlib.branch import Branch
567 branch = Branch.open("bzrbranch")
568@@ -569,6 +658,66 @@
569 contrib_branch.last_revision()).message,
570 'add README')
571 self.failUnless(os.path.exists("bzrbranch/README"))
572+
573+ def test_merge_revision(self):
574+ from bzrlib.branch import Branch
575+ from bzrlib.testament import StrictTestament3
576+ branch = Branch.open("bzrbranch")
577+ self.assertEqual(
578+ branch.repository.get_revision(branch.last_revision()).message,
579+ 'start branch.')
580+ contrib_branch = Branch.open("branch-contributor")
581+ self.assertEqual(contrib_branch.repository.get_revision(
582+ contrib_branch.last_revision()).message,
583+ 'add README')
584+ self.failIf(os.path.exists("bzrbranch/README"))
585+ self.failIf(os.path.exists("bzrbranch/NEWS"))
586+ handler = pqm.Bazaar2Handler()
587+ t = StrictTestament3.from_revision(contrib_branch.repository,
588+ 'revision-2')
589+ self.assertRaises(pqm.PQMTlaFailure, handler.do_bzr_merge, "me",
590+ 'revision-1', t.as_sha1(), "bzrbranch",
591+ "branch-contributor",)
592+ t = StrictTestament3.from_revision(contrib_branch.repository,
593+ 'revision-1')
594+ self.assertRaises(pqm.PQMTlaFailure, handler.do_bzr_merge, "me",
595+ 'revision-1', t.as_sha1(), "bzrbranch")
596+ result = handler.do_bzr_merge("me", 'revision-1', t.as_sha1(),
597+ "bzrbranch", 'branch-contributor')
598+ self.assertEqual(result, ["merge successful"])
599+ branch = Branch.open("bzrbranch")
600+ self.assertEqual(
601+ branch.repository.get_revision(branch.last_revision()).message,
602+ 'start branch.')
603+ contrib_branch = Branch.open("branch-contributor")
604+ self.assertEqual(contrib_branch.repository.get_revision(
605+ contrib_branch.last_revision()).message,
606+ 'add README')
607+ self.failIf(os.path.exists("bzrbranch/README"))
608+ self.failUnless(os.path.exists("bzrbranch/NEWS"))
609+
610+ def test_merge_bundle(self):
611+ from bzrlib.branch import Branch
612+ from bzrlib.bundle.serializer import write_bundle
613+ from bzrlib.testament import StrictTestament3
614+ branch = Branch.open("bzrbranch")
615+ self.assertEqual(
616+ branch.repository.get_revision(branch.last_revision()).message,
617+ 'start branch.')
618+ contrib_branch = Branch.open("branch-contributor")
619+ self.assertEqual(contrib_branch.repository.get_revision(
620+ contrib_branch.last_revision()).message,
621+ 'add README')
622+ self.failIf(os.path.exists("bzrbranch/README"))
623+ self.failIf(os.path.exists("bzrbranch/NEWS"))
624+ t = StrictTestament3.from_revision(contrib_branch.repository,
625+ 'revision-1')
626+ bundle = StringIO()
627+ write_bundle(contrib_branch.repository, 'revision-2', 'revision-0',
628+ bundle)
629+ handler = pqm.Bazaar2Handler()
630+ result = handler.do_bzr_merge("me", 'revision-1', t.as_sha1(),
631+ "bzrbranch", bundle=bundle.getvalue())
632
633 def test_merge_conflicts(self):
634 from bzrlib.workingtree import WorkingTree
635@@ -608,10 +757,17 @@
636 try:
637 handler.do_star_merge("me", "unrelated", "bzrbranch")
638 except pqm.PQMTlaFailure, e:
639+<<<<<<< TREE
640 self.assertEqual(
641 ["Branches have no common ancestor, and no merge base"
642 " revision was specified."],
643 e.output)
644+=======
645+ self.assertEqual(["Conflicts during merge: 1",
646+ "Text conflict in README",
647+ ],
648+ e.output)
649+>>>>>>> MERGE-SOURCE
650 return
651 self.fail("Merge base error not raised.")
652
653@@ -622,6 +778,47 @@
654 self.assertEqual('start branch.', message)
655
656
657+class TestBlackbox(BzrHandlerTestCase, TestWithQueueDirectory):
658+
659+ def setUp(self):
660+ BzrHandlerTestCase.setUp(self)
661+ TestWithQueueDirectory.setUp(self)
662+
663+ def test_blackbox(self):
664+ from bzrlib.branch import Branch
665+ from bzrlib.bundle.serializer import write_bundle
666+ from bzrlib.merge_directive import MergeDirective
667+ from bzrlib.testament import StrictTestament3
668+ branch = Branch.open("bzrbranch")
669+ self.assertEqual(
670+ branch.repository.get_revision(branch.last_revision()).message,
671+ 'start branch.')
672+ contrib_branch = Branch.open("branch-contributor")
673+ self.assertEqual(contrib_branch.repository.get_revision(
674+ contrib_branch.last_revision()).message,
675+ 'add README')
676+ repo = contrib_branch.repository
677+ repo.lock_write()
678+ try:
679+ directive = MergeDirective.from_objects(repo,
680+ contrib_branch.last_revision(), 0, 0,
681+ branch.bzrdir.root_transport.base)
682+ script = self.getScript(''.join(directive.to_lines()))
683+ self.failIf(os.path.exists("bzrbranch/README"))
684+ self.failIf(os.path.exists("bzrbranch/NEWS"))
685+ t = StrictTestament3.from_revision(contrib_branch.repository,
686+ 'revision-1')
687+ bundle = StringIO()
688+ write_bundle(contrib_branch.repository, 'revision-2',
689+ 'revision-0', bundle)
690+ handler = pqm.Bazaar2Handler()
691+ result = handler.do_bzr_merge("me", 'revision-1', t.as_sha1(),
692+ "bzrbranch",
693+ bundle=bundle.getvalue())
694+ finally:
695+ repo.unlock()
696+
697+
698 class TestConfig(unittest.TestCase):
699
700 def test_location_overrides(self):
701
702=== modified file 'tests/Makefile.am'
703--- tests/Makefile.am 2005-12-19 08:02:19 +0000
704+++ tests/Makefile.am 2010-05-04 16:39:23 +0000
705@@ -13,7 +13,8 @@
706 $(srcdir)/simple-merge-2.sh \
707 $(srcdir)/simple-merge-3.sh \
708 $(srcdir)/simple-merge-4.sh \
709- $(srcdir)/bzr-merge.sh
710+ $(srcdir)/bzr-merge.sh \
711+ $(srcdir)/bzr-merge-2.sh
712
713 EXTRA_DIST = test-framework pqm-tests.conf pqm-tests-2.conf \
714 pqm-tests-3.conf pqm-tests-4.conf \
715
716=== added file 'tests/bzr-merge-2.sh'
717--- tests/bzr-merge-2.sh 1970-01-01 00:00:00 +0000
718+++ tests/bzr-merge-2.sh 2010-05-04 16:39:23 +0000
719@@ -0,0 +1,20 @@
720+#!/bin/sh
721+# -*- mode: sh; coding: utf-8 -*-
722+# Copyright © 2005 Canonical Limited
723+# Authors: Robert Collins <robert@canonical.com>
724+#
725+# See the file "COPYING" for further information about
726+# the copyright and warranty status of this work.
727+
728+set -e
729+
730+srcdir=$(cd ${srcdir} && pwd)
731+
732+. ${srcdir}/test-framework
733+
734+PQM_CONFIG_FILE="${srcdir}/pqm-tests-2.conf"
735+initial_bzr_setup_with_plain_merge_directive
736+run_queue
737+bzr_archive_has_revision_with_summary "hello-world/mainline/1.0" 2 'minor rename'
738+
739+clean_workdir
740
741=== modified file 'tests/test-framework'
742--- tests/test-framework 2010-04-13 07:40:54 +0000
743+++ tests/test-framework 2010-05-04 16:39:23 +0000
744@@ -268,13 +268,13 @@
745 (echo "From: ${USERID}"; echo "Subject: ${subj}"; echo) | pqm --no-verify --read "$@"
746 else
747 if test ${type} = "verify"; then
748- tmpf="${WORKDIR}/sig.$$"
749- HOME=${srcdir} gpg --batch --clearsign --passphrase-fd 2 2</dev/null > "${tmpf}"
750- (echo "From: ${USERID}"; echo "Subject: ${subj}"; echo; cat < "${tmpf}") | pqm --read "$@"
751- rm -f "${tmpf}"
752+ tmpf="${WORKDIR}/sig.$$"
753+ HOME=${srcdir} gpg --batch --clearsign --passphrase-fd 2 2</dev/null > "${tmpf}"
754+ (echo "From: ${USERID}"; echo "Subject: ${subj}"; echo; cat < "${tmpf}") | pqm --read "$@"
755+ rm -f "${tmpf}"
756 else
757- echo "Unknown verification type ${type}!" 1>&2
758- exit 1
759+ echo "Unknown verification type ${type}!" 1>&2
760+ exit 1
761 fi
762 fi
763 endverbose
764@@ -486,6 +486,20 @@
765 endverbose
766 }
767
768+
769+initial_bzr_setup_with_plain_merge_directive ()
770+{
771+ initial_bzr_setup
772+ identity_user1
773+ verbose 'doing simple submission'
774+ cd ${WORKDIR}/hello-world
775+ pqm_bzr rename hello-world.c hello_world.c
776+ pqm_bzr commit -m 'rename hello-world => hello_world.c'
777+ pqm_bzr merge-directive --plain ${PQM_ARCHIVE_DIR}/hello-world/mainline/1.0 `pwd` | submit_merge 'minor rename' "verify"
778+ endverbose
779+}
780+
781+
782 import_bzr_hello_world () {
783 branch=$1
784 shift
785@@ -506,7 +520,7 @@
786 archive=$1
787 revision=$2
788 summary=$3
789- verbose "checking for revision \"$1\" in archive \"$2\""
790+ verbose "checking for revision \"$2\" in archive \"$1\""
791 output=$(pqm_bzr log --message "$summary" ${PQM_ARCHIVE_DIR}/${archive} | grep "revno")
792 test "$output" = "revno: $revision [merge]"
793 endverbose

Subscribers

People subscribed via source and target branches