101
86
eq(rev.message, 'add hello')
103
88
tree1 = b.repository.revision_tree(rh[0])
105
89
text = tree1.get_file_text(file_id)
107
self.assertEqual('hello world', text)
90
eq(text, 'hello world')
109
92
tree2 = b.repository.revision_tree(rh[1])
111
text = tree2.get_file_text(file_id)
113
self.assertEqual('version 2', text)
115
def test_commit_lossy_native(self):
116
"""Attempt a lossy commit to a native branch."""
117
wt = self.make_branch_and_tree('.')
119
file('hello', 'w').write('hello world')
121
revid = wt.commit(message='add hello', rev_id='revid', lossy=True)
122
self.assertEquals('revid', revid)
124
def test_commit_lossy_foreign(self):
125
"""Attempt a lossy commit to a foreign branch."""
126
test_foreign.register_dummy_foreign_for_test(self)
127
wt = self.make_branch_and_tree('.',
128
format=test_foreign.DummyForeignVcsDirFormat())
130
file('hello', 'w').write('hello world')
132
revid = wt.commit(message='add hello', lossy=True,
133
timestamp=1302659388, timezone=0)
134
self.assertEquals('dummy-v1:1302659388.0-0-UNKNOWN', revid)
136
def test_commit_bound_lossy_foreign(self):
137
"""Attempt a lossy commit to a bzr branch bound to a foreign branch."""
138
test_foreign.register_dummy_foreign_for_test(self)
139
foreign_branch = self.make_branch('foreign',
140
format=test_foreign.DummyForeignVcsDirFormat())
141
wt = foreign_branch.create_checkout("local")
143
file('local/hello', 'w').write('hello world')
145
revid = wt.commit(message='add hello', lossy=True,
146
timestamp=1302659388, timezone=0)
147
self.assertEquals('dummy-v1:1302659388.0-0-0', revid)
148
self.assertEquals('dummy-v1:1302659388.0-0-0',
149
foreign_branch.last_revision())
150
self.assertEquals('dummy-v1:1302659388.0-0-0',
151
wt.branch.last_revision())
153
def test_missing_commit(self):
154
"""Test a commit with a missing file"""
93
eq(tree2.get_file_text(file_id), 'version 2')
95
def test_delete_commit(self):
96
"""Test a commit with a deleted file"""
155
97
wt = self.make_branch_and_tree('.')
157
99
file('hello', 'w').write('hello world')
301
217
wt.move(['hello'], 'a')
302
218
r2 = 'test@rev-2'
303
219
wt.commit('two', rev_id=r2, allow_pointless=False)
306
self.check_tree_shape(wt, ['a/', 'a/hello', 'b/'])
220
self.check_inventory_shape(wt.read_working_inventory(),
221
['a', 'a/hello', 'b'])
310
223
wt.move(['b'], 'a')
311
224
r3 = 'test@rev-3'
312
225
wt.commit('three', rev_id=r3, allow_pointless=False)
315
self.check_tree_shape(wt,
316
['a/', 'a/hello', 'a/b/'])
317
self.check_tree_shape(b.repository.revision_tree(r3),
318
['a/', 'a/hello', 'a/b/'])
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'])
322
231
wt.move(['a/hello'], 'a/b')
323
232
r4 = 'test@rev-4'
324
233
wt.commit('four', rev_id=r4, allow_pointless=False)
327
self.check_tree_shape(wt, ['a/', 'a/b/hello', 'a/b/'])
234
self.check_inventory_shape(wt.read_working_inventory(),
235
['a', 'a/b/hello', 'a/b'])
331
inv = b.repository.get_inventory(r4)
237
inv = b.repository.get_revision_inventory(r4)
332
238
eq(inv['hello-id'].revision, r4)
333
239
eq(inv['a-id'].revision, r1)
334
240
eq(inv['b-id'].revision, r3)
336
242
def test_removed_commit(self):
337
243
"""Commit with a removed file"""
338
244
wt = self.make_branch_and_tree('.')
587
493
this_tree.merge_from_branch(other_tree.branch)
588
494
reporter = CapturingReporter()
589
495
this_tree.commit('do the commit', reporter=reporter)
497
('change', 'unchanged', ''),
498
('change', 'unchanged', 'dirtoleave'),
499
('change', 'unchanged', 'filetoleave'),
591
500
('change', 'modified', 'filetomodify'),
592
501
('change', 'added', 'newdir'),
593
502
('change', 'added', 'newfile'),
594
503
('renamed', 'renamed', 'dirtorename', 'renameddir'),
595
('renamed', 'renamed', 'filetorename', 'renamedfile'),
596
504
('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
597
505
('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
506
('renamed', 'renamed', 'filetorename', 'renamedfile'),
598
507
('deleted', 'dirtoremove'),
599
508
('deleted', 'filetoremove'),
601
result = set(reporter.calls)
602
missing = expected - result
603
new = result - expected
604
self.assertEqual((set(), set()), (missing, new))
606
512
def test_commit_removals_respects_filespec(self):
607
513
"""Commit respects the specified_files for removals."""
641
543
timestamp = rev.timestamp
642
544
timestamp_1ms = round(timestamp, 3)
643
545
self.assertEqual(timestamp_1ms, timestamp)
645
def assertBasisTreeKind(self, kind, tree, file_id):
646
basis = tree.basis_tree()
649
self.assertEqual(kind, basis.kind(file_id))
653
def test_commit_kind_changes(self):
654
self.requireFeature(SymlinkFeature)
655
tree = self.make_branch_and_tree('.')
656
os.symlink('target', 'name')
657
tree.add('name', 'a-file-id')
658
tree.commit('Added a symlink')
659
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
662
self.build_tree(['name'])
663
tree.commit('Changed symlink to file')
664
self.assertBasisTreeKind('file', tree, 'a-file-id')
667
os.symlink('target', 'name')
668
tree.commit('file to symlink')
669
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
673
tree.commit('symlink to directory')
674
self.assertBasisTreeKind('directory', tree, 'a-file-id')
677
os.symlink('target', 'name')
678
tree.commit('directory to symlink')
679
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
681
# prepare for directory <-> file tests
684
tree.commit('symlink to directory')
685
self.assertBasisTreeKind('directory', tree, 'a-file-id')
688
self.build_tree(['name'])
689
tree.commit('Changed directory to file')
690
self.assertBasisTreeKind('file', tree, 'a-file-id')
694
tree.commit('file to directory')
695
self.assertBasisTreeKind('directory', tree, 'a-file-id')
697
def test_commit_unversioned_specified(self):
698
"""Commit should raise if specified files isn't in basis or worktree"""
699
tree = self.make_branch_and_tree('.')
700
self.assertRaises(errors.PathsNotVersionedError, tree.commit,
701
'message', specific_files=['bogus'])
703
class Callback(object):
705
def __init__(self, message, testcase):
707
self.message = message
708
self.testcase = testcase
710
def __call__(self, commit_obj):
712
self.testcase.assertTrue(isinstance(commit_obj, Commit))
715
def test_commit_callback(self):
716
"""Commit should invoke a callback to get the message"""
718
tree = self.make_branch_and_tree('.')
722
self.assertTrue(isinstance(e, BzrError))
723
self.assertEqual('The message or message_callback keyword'
724
' parameter is required for commit().', str(e))
726
self.fail('exception not raised')
727
cb = self.Callback(u'commit 1', self)
728
tree.commit(message_callback=cb)
729
self.assertTrue(cb.called)
730
repository = tree.branch.repository
731
message = repository.get_revision(tree.last_revision()).message
732
self.assertEqual('commit 1', message)
734
def test_no_callback_pointless(self):
735
"""Callback should not be invoked for pointless commit"""
736
tree = self.make_branch_and_tree('.')
737
cb = self.Callback(u'commit 2', self)
738
self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
739
allow_pointless=False)
740
self.assertFalse(cb.called)
742
def test_no_callback_netfailure(self):
743
"""Callback should not be invoked if connectivity fails"""
744
tree = self.make_branch_and_tree('.')
745
cb = self.Callback(u'commit 2', self)
746
repository = tree.branch.repository
747
# simulate network failure
748
def raise_(self, arg, arg2, arg3=None, arg4=None):
749
raise errors.NoSuchFile('foo')
750
repository.add_inventory = raise_
751
repository.add_inventory_by_delta = raise_
752
self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
753
self.assertFalse(cb.called)
755
def test_selected_file_merge_commit(self):
756
"""Ensure the correct error is raised"""
757
tree = self.make_branch_and_tree('foo')
758
# pending merge would turn into a left parent
759
tree.commit('commit 1')
760
tree.add_parent_tree_id('example')
761
self.build_tree(['foo/bar', 'foo/baz'])
762
tree.add(['bar', 'baz'])
763
err = self.assertRaises(errors.CannotCommitSelectedFileMerge,
764
tree.commit, 'commit 2', specific_files=['bar', 'baz'])
765
self.assertEqual(['bar', 'baz'], err.files)
766
self.assertEqual('Selected-file commit of merges is not supported'
767
' yet: files bar, baz', str(err))
769
def test_commit_ordering(self):
770
"""Test of corner-case commit ordering error"""
771
tree = self.make_branch_and_tree('.')
772
self.build_tree(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
773
tree.add(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
775
self.build_tree(['a/c/d/'])
777
tree.rename_one('a/z/x', 'a/c/d/x')
778
tree.commit('test', specific_files=['a/z/y'])
780
def test_commit_no_author(self):
781
"""The default kwarg author in MutableTree.commit should not add
782
the 'author' revision property.
784
tree = self.make_branch_and_tree('foo')
785
rev_id = tree.commit('commit 1')
786
rev = tree.branch.repository.get_revision(rev_id)
787
self.assertFalse('author' in rev.properties)
788
self.assertFalse('authors' in rev.properties)
790
def test_commit_author(self):
791
"""Passing a non-empty author kwarg to MutableTree.commit should add
792
the 'author' revision property.
794
tree = self.make_branch_and_tree('foo')
795
rev_id = self.callDeprecated(['The parameter author was '
796
'deprecated in version 1.13. Use authors instead'],
797
tree.commit, 'commit 1', author='John Doe <jdoe@example.com>')
798
rev = tree.branch.repository.get_revision(rev_id)
799
self.assertEqual('John Doe <jdoe@example.com>',
800
rev.properties['authors'])
801
self.assertFalse('author' in rev.properties)
803
def test_commit_empty_authors_list(self):
804
"""Passing an empty list to authors shouldn't add the property."""
805
tree = self.make_branch_and_tree('foo')
806
rev_id = tree.commit('commit 1', authors=[])
807
rev = tree.branch.repository.get_revision(rev_id)
808
self.assertFalse('author' in rev.properties)
809
self.assertFalse('authors' in rev.properties)
811
def test_multiple_authors(self):
812
tree = self.make_branch_and_tree('foo')
813
rev_id = tree.commit('commit 1',
814
authors=['John Doe <jdoe@example.com>',
815
'Jane Rey <jrey@example.com>'])
816
rev = tree.branch.repository.get_revision(rev_id)
817
self.assertEqual('John Doe <jdoe@example.com>\n'
818
'Jane Rey <jrey@example.com>', rev.properties['authors'])
819
self.assertFalse('author' in rev.properties)
821
def test_author_and_authors_incompatible(self):
822
tree = self.make_branch_and_tree('foo')
823
self.assertRaises(AssertionError, tree.commit, 'commit 1',
824
authors=['John Doe <jdoe@example.com>',
825
'Jane Rey <jrey@example.com>'],
826
author="Jack Me <jme@example.com>")
828
def test_author_with_newline_rejected(self):
829
tree = self.make_branch_and_tree('foo')
830
self.assertRaises(AssertionError, tree.commit, 'commit 1',
831
authors=['John\nDoe <jdoe@example.com>'])
833
def test_commit_with_checkout_and_branch_sharing_repo(self):
834
repo = self.make_repository('repo', shared=True)
835
# make_branch_and_tree ignores shared repos
836
branch = bzrdir.BzrDir.create_branch_convenience('repo/branch')
837
tree2 = branch.create_checkout('repo/tree2')
838
tree2.commit('message', rev_id='rev1')
839
self.assertTrue(tree2.branch.repository.has_revision('rev1'))