217
256
wt.move(['hello'], 'a')
218
257
r2 = 'test@rev-2'
219
258
wt.commit('two', rev_id=r2, allow_pointless=False)
220
self.check_inventory_shape(wt.read_working_inventory(),
221
['a', 'a/hello', 'b'])
261
self.check_inventory_shape(wt.read_working_inventory(),
262
['a/', 'a/hello', 'b/'])
223
266
wt.move(['b'], 'a')
224
267
r3 = 'test@rev-3'
225
268
wt.commit('three', rev_id=r3, allow_pointless=False)
226
self.check_inventory_shape(wt.read_working_inventory(),
227
['a', 'a/hello', 'a/b'])
228
self.check_inventory_shape(b.repository.get_revision_inventory(r3),
229
['a', 'a/hello', 'a/b'])
271
self.check_inventory_shape(wt.read_working_inventory(),
272
['a/', 'a/hello', 'a/b/'])
273
self.check_inventory_shape(b.repository.get_inventory(r3),
274
['a/', 'a/hello', 'a/b/'])
231
278
wt.move(['a/hello'], 'a/b')
232
279
r4 = 'test@rev-4'
233
280
wt.commit('four', rev_id=r4, allow_pointless=False)
234
self.check_inventory_shape(wt.read_working_inventory(),
235
['a', 'a/b/hello', 'a/b'])
283
self.check_inventory_shape(wt.read_working_inventory(),
284
['a/', 'a/b/hello', 'a/b/'])
237
inv = b.repository.get_revision_inventory(r4)
288
inv = b.repository.get_inventory(r4)
238
289
eq(inv['hello-id'].revision, r4)
239
290
eq(inv['a-id'].revision, r1)
240
291
eq(inv['b-id'].revision, r3)
242
293
def test_removed_commit(self):
243
294
"""Commit with a removed file"""
244
295
wt = self.make_branch_and_tree('.')
490
543
other_tree.commit('modify all sample files and dirs.')
492
545
other_tree.unlock()
493
self.merge(other_tree.branch, this_tree)
546
this_tree.merge_from_branch(other_tree.branch)
494
547
reporter = CapturingReporter()
495
548
this_tree.commit('do the commit', reporter=reporter)
497
('change', 'unchanged', ''),
498
('change', 'unchanged', 'dirtoleave'),
499
('change', 'unchanged', 'filetoleave'),
500
550
('change', 'modified', 'filetomodify'),
501
551
('change', 'added', 'newdir'),
502
552
('change', 'added', 'newfile'),
503
553
('renamed', 'renamed', 'dirtorename', 'renameddir'),
554
('renamed', 'renamed', 'filetorename', 'renamedfile'),
504
555
('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
505
556
('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
506
('renamed', 'renamed', 'filetorename', 'renamedfile'),
507
557
('deleted', 'dirtoremove'),
508
558
('deleted', 'filetoremove'),
560
result = set(reporter.calls)
561
missing = expected - result
562
new = result - expected
563
self.assertEqual((set(), set()), (missing, new))
512
565
def test_commit_removals_respects_filespec(self):
513
566
"""Commit respects the specified_files for removals."""
543
600
timestamp = rev.timestamp
544
601
timestamp_1ms = round(timestamp, 3)
545
602
self.assertEqual(timestamp_1ms, timestamp)
604
def assertBasisTreeKind(self, kind, tree, file_id):
605
basis = tree.basis_tree()
608
self.assertEqual(kind, basis.kind(file_id))
612
def test_commit_kind_changes(self):
613
self.requireFeature(SymlinkFeature)
614
tree = self.make_branch_and_tree('.')
615
os.symlink('target', 'name')
616
tree.add('name', 'a-file-id')
617
tree.commit('Added a symlink')
618
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
621
self.build_tree(['name'])
622
tree.commit('Changed symlink to file')
623
self.assertBasisTreeKind('file', tree, 'a-file-id')
626
os.symlink('target', 'name')
627
tree.commit('file to symlink')
628
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
632
tree.commit('symlink to directory')
633
self.assertBasisTreeKind('directory', tree, 'a-file-id')
636
os.symlink('target', 'name')
637
tree.commit('directory to symlink')
638
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
640
# prepare for directory <-> file tests
643
tree.commit('symlink to directory')
644
self.assertBasisTreeKind('directory', tree, 'a-file-id')
647
self.build_tree(['name'])
648
tree.commit('Changed directory to file')
649
self.assertBasisTreeKind('file', tree, 'a-file-id')
653
tree.commit('file to directory')
654
self.assertBasisTreeKind('directory', tree, 'a-file-id')
656
def test_commit_unversioned_specified(self):
657
"""Commit should raise if specified files isn't in basis or worktree"""
658
tree = self.make_branch_and_tree('.')
659
self.assertRaises(errors.PathsNotVersionedError, tree.commit,
660
'message', specific_files=['bogus'])
662
class Callback(object):
664
def __init__(self, message, testcase):
666
self.message = message
667
self.testcase = testcase
669
def __call__(self, commit_obj):
671
self.testcase.assertTrue(isinstance(commit_obj, Commit))
674
def test_commit_callback(self):
675
"""Commit should invoke a callback to get the message"""
677
tree = self.make_branch_and_tree('.')
681
self.assertTrue(isinstance(e, BzrError))
682
self.assertEqual('The message or message_callback keyword'
683
' parameter is required for commit().', str(e))
685
self.fail('exception not raised')
686
cb = self.Callback(u'commit 1', self)
687
tree.commit(message_callback=cb)
688
self.assertTrue(cb.called)
689
repository = tree.branch.repository
690
message = repository.get_revision(tree.last_revision()).message
691
self.assertEqual('commit 1', message)
693
def test_no_callback_pointless(self):
694
"""Callback should not be invoked for pointless commit"""
695
tree = self.make_branch_and_tree('.')
696
cb = self.Callback(u'commit 2', self)
697
self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
698
allow_pointless=False)
699
self.assertFalse(cb.called)
701
def test_no_callback_netfailure(self):
702
"""Callback should not be invoked if connectivity fails"""
703
tree = self.make_branch_and_tree('.')
704
cb = self.Callback(u'commit 2', self)
705
repository = tree.branch.repository
706
# simulate network failure
707
def raise_(self, arg, arg2, arg3=None, arg4=None):
708
raise errors.NoSuchFile('foo')
709
repository.add_inventory = raise_
710
repository.add_inventory_by_delta = raise_
711
self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
712
self.assertFalse(cb.called)
714
def test_selected_file_merge_commit(self):
715
"""Ensure the correct error is raised"""
716
tree = self.make_branch_and_tree('foo')
717
# pending merge would turn into a left parent
718
tree.commit('commit 1')
719
tree.add_parent_tree_id('example')
720
self.build_tree(['foo/bar', 'foo/baz'])
721
tree.add(['bar', 'baz'])
722
err = self.assertRaises(errors.CannotCommitSelectedFileMerge,
723
tree.commit, 'commit 2', specific_files=['bar', 'baz'])
724
self.assertEqual(['bar', 'baz'], err.files)
725
self.assertEqual('Selected-file commit of merges is not supported'
726
' yet: files bar, baz', str(err))
728
def test_commit_ordering(self):
729
"""Test of corner-case commit ordering error"""
730
tree = self.make_branch_and_tree('.')
731
self.build_tree(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
732
tree.add(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
734
self.build_tree(['a/c/d/'])
736
tree.rename_one('a/z/x', 'a/c/d/x')
737
tree.commit('test', specific_files=['a/z/y'])
739
def test_commit_no_author(self):
740
"""The default kwarg author in MutableTree.commit should not add
741
the 'author' revision property.
743
tree = self.make_branch_and_tree('foo')
744
rev_id = tree.commit('commit 1')
745
rev = tree.branch.repository.get_revision(rev_id)
746
self.assertFalse('author' in rev.properties)
747
self.assertFalse('authors' in rev.properties)
749
def test_commit_author(self):
750
"""Passing a non-empty author kwarg to MutableTree.commit should add
751
the 'author' revision property.
753
tree = self.make_branch_and_tree('foo')
754
rev_id = self.callDeprecated(['The parameter author was '
755
'deprecated in version 1.13. Use authors instead'],
756
tree.commit, 'commit 1', author='John Doe <jdoe@example.com>')
757
rev = tree.branch.repository.get_revision(rev_id)
758
self.assertEqual('John Doe <jdoe@example.com>',
759
rev.properties['authors'])
760
self.assertFalse('author' in rev.properties)
762
def test_commit_empty_authors_list(self):
763
"""Passing an empty list to authors shouldn't add the property."""
764
tree = self.make_branch_and_tree('foo')
765
rev_id = tree.commit('commit 1', authors=[])
766
rev = tree.branch.repository.get_revision(rev_id)
767
self.assertFalse('author' in rev.properties)
768
self.assertFalse('authors' in rev.properties)
770
def test_multiple_authors(self):
771
tree = self.make_branch_and_tree('foo')
772
rev_id = tree.commit('commit 1',
773
authors=['John Doe <jdoe@example.com>',
774
'Jane Rey <jrey@example.com>'])
775
rev = tree.branch.repository.get_revision(rev_id)
776
self.assertEqual('John Doe <jdoe@example.com>\n'
777
'Jane Rey <jrey@example.com>', rev.properties['authors'])
778
self.assertFalse('author' in rev.properties)
780
def test_author_and_authors_incompatible(self):
781
tree = self.make_branch_and_tree('foo')
782
self.assertRaises(AssertionError, tree.commit, 'commit 1',
783
authors=['John Doe <jdoe@example.com>',
784
'Jane Rey <jrey@example.com>'],
785
author="Jack Me <jme@example.com>")
787
def test_author_with_newline_rejected(self):
788
tree = self.make_branch_and_tree('foo')
789
self.assertRaises(AssertionError, tree.commit, 'commit 1',
790
authors=['John\nDoe <jdoe@example.com>'])
792
def test_commit_with_checkout_and_branch_sharing_repo(self):
793
repo = self.make_repository('repo', shared=True)
794
# make_branch_and_tree ignores shared repos
795
branch = bzrdir.BzrDir.create_branch_convenience('repo/branch')
796
tree2 = branch.create_checkout('repo/tree2')
797
tree2.commit('message', rev_id='rev1')
798
self.assertTrue(tree2.branch.repository.has_revision('rev1'))