86
103
eq(rev.message, 'add hello')
88
105
tree1 = b.repository.revision_tree(rh[0])
89
107
text = tree1.get_file_text(file_id)
90
eq(text, 'hello world')
109
self.assertEqual('hello world', text)
92
111
tree2 = b.repository.revision_tree(rh[1])
93
eq(tree2.get_file_text(file_id), 'version 2')
95
def test_delete_commit(self):
96
"""Test a commit with a deleted file"""
113
text = tree2.get_file_text(file_id)
115
self.assertEqual('version 2', text)
117
def test_commit_lossy_native(self):
118
"""Attempt a lossy commit to a native branch."""
119
wt = self.make_branch_and_tree('.')
121
file('hello', 'w').write('hello world')
123
revid = wt.commit(message='add hello', rev_id='revid', lossy=True)
124
self.assertEquals('revid', revid)
126
def test_commit_lossy_foreign(self):
127
"""Attempt a lossy commit to a foreign branch."""
128
test_foreign.register_dummy_foreign_for_test(self)
129
wt = self.make_branch_and_tree('.',
130
format=test_foreign.DummyForeignVcsDirFormat())
132
file('hello', 'w').write('hello world')
134
revid = wt.commit(message='add hello', lossy=True,
135
timestamp=1302659388, timezone=0)
136
self.assertEquals('dummy-v1:1302659388.0-0-UNKNOWN', revid)
138
def test_commit_bound_lossy_foreign(self):
139
"""Attempt a lossy commit to a bzr branch bound to a foreign branch."""
140
test_foreign.register_dummy_foreign_for_test(self)
141
foreign_branch = self.make_branch('foreign',
142
format=test_foreign.DummyForeignVcsDirFormat())
143
wt = foreign_branch.create_checkout("local")
145
file('local/hello', 'w').write('hello world')
147
revid = wt.commit(message='add hello', lossy=True,
148
timestamp=1302659388, timezone=0)
149
self.assertEquals('dummy-v1:1302659388.0-0-0', revid)
150
self.assertEquals('dummy-v1:1302659388.0-0-0',
151
foreign_branch.last_revision())
152
self.assertEquals('dummy-v1:1302659388.0-0-0',
153
wt.branch.last_revision())
155
def test_missing_commit(self):
156
"""Test a commit with a missing file"""
97
157
wt = self.make_branch_and_tree('.')
99
159
file('hello', 'w').write('hello world')
217
307
wt.move(['hello'], 'a')
218
308
r2 = 'test@rev-2'
219
309
wt.commit('two', rev_id=r2, allow_pointless=False)
220
self.check_inventory_shape(wt.read_working_inventory(),
221
['a', 'a/hello', 'b'])
312
self.check_tree_shape(wt, ['a/', 'a/hello', 'b/'])
223
316
wt.move(['b'], 'a')
224
317
r3 = 'test@rev-3'
225
318
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'])
321
self.check_tree_shape(wt,
322
['a/', 'a/hello', 'a/b/'])
323
self.check_tree_shape(b.repository.revision_tree(r3),
324
['a/', 'a/hello', 'a/b/'])
231
328
wt.move(['a/hello'], 'a/b')
232
329
r4 = 'test@rev-4'
233
330
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'])
333
self.check_tree_shape(wt, ['a/', 'a/b/hello', 'a/b/'])
237
inv = b.repository.get_revision_inventory(r4)
337
inv = b.repository.get_inventory(r4)
238
338
eq(inv['hello-id'].revision, r4)
239
339
eq(inv['a-id'].revision, r1)
240
340
eq(inv['b-id'].revision, r3)
242
342
def test_removed_commit(self):
243
343
"""Commit with a removed file"""
244
344
wt = self.make_branch_and_tree('.')
490
590
other_tree.commit('modify all sample files and dirs.')
492
592
other_tree.unlock()
493
self.merge(other_tree.branch, this_tree)
593
this_tree.merge_from_branch(other_tree.branch)
494
594
reporter = CapturingReporter()
495
595
this_tree.commit('do the commit', reporter=reporter)
497
('change', 'unchanged', 'dirtoleave'),
498
('change', 'unchanged', 'filetoleave'),
499
597
('change', 'modified', 'filetomodify'),
500
598
('change', 'added', 'newdir'),
501
599
('change', 'added', 'newfile'),
502
600
('renamed', 'renamed', 'dirtorename', 'renameddir'),
601
('renamed', 'renamed', 'filetorename', 'renamedfile'),
503
602
('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
504
603
('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
505
('renamed', 'renamed', 'filetorename', 'renamedfile'),
506
604
('deleted', 'dirtoremove'),
507
605
('deleted', 'filetoremove'),
607
result = set(reporter.calls)
608
missing = expected - result
609
new = result - expected
610
self.assertEqual((set(), set()), (missing, new))
511
612
def test_commit_removals_respects_filespec(self):
512
613
"""Commit respects the specified_files for removals."""
543
647
timestamp = rev.timestamp
544
648
timestamp_1ms = round(timestamp, 3)
545
649
self.assertEqual(timestamp_1ms, timestamp)
651
def assertBasisTreeKind(self, kind, tree, file_id):
652
basis = tree.basis_tree()
655
self.assertEqual(kind, basis.kind(file_id))
659
def test_commit_kind_changes(self):
660
self.requireFeature(SymlinkFeature)
661
tree = self.make_branch_and_tree('.')
662
os.symlink('target', 'name')
663
tree.add('name', 'a-file-id')
664
tree.commit('Added a symlink')
665
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
668
self.build_tree(['name'])
669
tree.commit('Changed symlink to file')
670
self.assertBasisTreeKind('file', tree, 'a-file-id')
673
os.symlink('target', 'name')
674
tree.commit('file to symlink')
675
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
679
tree.commit('symlink to directory')
680
self.assertBasisTreeKind('directory', tree, 'a-file-id')
683
os.symlink('target', 'name')
684
tree.commit('directory to symlink')
685
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
687
# prepare for directory <-> file tests
690
tree.commit('symlink to directory')
691
self.assertBasisTreeKind('directory', tree, 'a-file-id')
694
self.build_tree(['name'])
695
tree.commit('Changed directory to file')
696
self.assertBasisTreeKind('file', tree, 'a-file-id')
700
tree.commit('file to directory')
701
self.assertBasisTreeKind('directory', tree, 'a-file-id')
703
def test_commit_unversioned_specified(self):
704
"""Commit should raise if specified files isn't in basis or worktree"""
705
tree = self.make_branch_and_tree('.')
706
self.assertRaises(errors.PathsNotVersionedError, tree.commit,
707
'message', specific_files=['bogus'])
709
class Callback(object):
711
def __init__(self, message, testcase):
713
self.message = message
714
self.testcase = testcase
716
def __call__(self, commit_obj):
718
self.testcase.assertTrue(isinstance(commit_obj, Commit))
721
def test_commit_callback(self):
722
"""Commit should invoke a callback to get the message"""
724
tree = self.make_branch_and_tree('.')
728
self.assertTrue(isinstance(e, BzrError))
729
self.assertEqual('The message or message_callback keyword'
730
' parameter is required for commit().', str(e))
732
self.fail('exception not raised')
733
cb = self.Callback(u'commit 1', self)
734
tree.commit(message_callback=cb)
735
self.assertTrue(cb.called)
736
repository = tree.branch.repository
737
message = repository.get_revision(tree.last_revision()).message
738
self.assertEqual('commit 1', message)
740
def test_no_callback_pointless(self):
741
"""Callback should not be invoked for pointless commit"""
742
tree = self.make_branch_and_tree('.')
743
cb = self.Callback(u'commit 2', self)
744
self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
745
allow_pointless=False)
746
self.assertFalse(cb.called)
748
def test_no_callback_netfailure(self):
749
"""Callback should not be invoked if connectivity fails"""
750
tree = self.make_branch_and_tree('.')
751
cb = self.Callback(u'commit 2', self)
752
repository = tree.branch.repository
753
# simulate network failure
754
def raise_(self, arg, arg2, arg3=None, arg4=None):
755
raise errors.NoSuchFile('foo')
756
repository.add_inventory = raise_
757
repository.add_inventory_by_delta = raise_
758
self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
759
self.assertFalse(cb.called)
761
def test_selected_file_merge_commit(self):
762
"""Ensure the correct error is raised"""
763
tree = self.make_branch_and_tree('foo')
764
# pending merge would turn into a left parent
765
tree.commit('commit 1')
766
tree.add_parent_tree_id('example')
767
self.build_tree(['foo/bar', 'foo/baz'])
768
tree.add(['bar', 'baz'])
769
err = self.assertRaises(errors.CannotCommitSelectedFileMerge,
770
tree.commit, 'commit 2', specific_files=['bar', 'baz'])
771
self.assertEqual(['bar', 'baz'], err.files)
772
self.assertEqual('Selected-file commit of merges is not supported'
773
' yet: files bar, baz', str(err))
775
def test_commit_ordering(self):
776
"""Test of corner-case commit ordering error"""
777
tree = self.make_branch_and_tree('.')
778
self.build_tree(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
779
tree.add(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
781
self.build_tree(['a/c/d/'])
783
tree.rename_one('a/z/x', 'a/c/d/x')
784
tree.commit('test', specific_files=['a/z/y'])
786
def test_commit_no_author(self):
787
"""The default kwarg author in MutableTree.commit should not add
788
the 'author' revision property.
790
tree = self.make_branch_and_tree('foo')
791
rev_id = tree.commit('commit 1')
792
rev = tree.branch.repository.get_revision(rev_id)
793
self.assertFalse('author' in rev.properties)
794
self.assertFalse('authors' in rev.properties)
796
def test_commit_author(self):
797
"""Passing a non-empty author kwarg to MutableTree.commit should add
798
the 'author' revision property.
800
tree = self.make_branch_and_tree('foo')
801
rev_id = self.callDeprecated(['The parameter author was '
802
'deprecated in version 1.13. Use authors instead'],
803
tree.commit, 'commit 1', author='John Doe <jdoe@example.com>')
804
rev = tree.branch.repository.get_revision(rev_id)
805
self.assertEqual('John Doe <jdoe@example.com>',
806
rev.properties['authors'])
807
self.assertFalse('author' in rev.properties)
809
def test_commit_empty_authors_list(self):
810
"""Passing an empty list to authors shouldn't add the property."""
811
tree = self.make_branch_and_tree('foo')
812
rev_id = tree.commit('commit 1', authors=[])
813
rev = tree.branch.repository.get_revision(rev_id)
814
self.assertFalse('author' in rev.properties)
815
self.assertFalse('authors' in rev.properties)
817
def test_multiple_authors(self):
818
tree = self.make_branch_and_tree('foo')
819
rev_id = tree.commit('commit 1',
820
authors=['John Doe <jdoe@example.com>',
821
'Jane Rey <jrey@example.com>'])
822
rev = tree.branch.repository.get_revision(rev_id)
823
self.assertEqual('John Doe <jdoe@example.com>\n'
824
'Jane Rey <jrey@example.com>', rev.properties['authors'])
825
self.assertFalse('author' in rev.properties)
827
def test_author_and_authors_incompatible(self):
828
tree = self.make_branch_and_tree('foo')
829
self.assertRaises(AssertionError, tree.commit, 'commit 1',
830
authors=['John Doe <jdoe@example.com>',
831
'Jane Rey <jrey@example.com>'],
832
author="Jack Me <jme@example.com>")
834
def test_author_with_newline_rejected(self):
835
tree = self.make_branch_and_tree('foo')
836
self.assertRaises(AssertionError, tree.commit, 'commit 1',
837
authors=['John\nDoe <jdoe@example.com>'])
839
def test_commit_with_checkout_and_branch_sharing_repo(self):
840
repo = self.make_repository('repo', shared=True)
841
# make_branch_and_tree ignores shared repos
842
branch = bzrdir.BzrDir.create_branch_convenience('repo/branch')
843
tree2 = branch.create_checkout('repo/tree2')
844
tree2.commit('message', rev_id='rev1')
845
self.assertTrue(tree2.branch.repository.has_revision('rev1'))