13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
21
from bzrlib import (
25
27
from bzrlib.branch import Branch
26
from bzrlib.bzrdir import BzrDirMetaFormat1
28
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
27
29
from bzrlib.commit import Commit, NullCommitReporter
28
30
from bzrlib.config import BranchConfig
29
from bzrlib.errors import (
35
from bzrlib.tests import (
37
TestCaseWithTransport,
40
from bzrlib.tests.matchers import MatchesAncestry
31
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed,
33
from bzrlib.tests import TestCaseWithTransport
34
from bzrlib.workingtree import WorkingTree
43
37
# TODO: Test commit with some added, and added-but-missing files
101
92
eq(rev.message, 'add hello')
103
94
tree1 = b.repository.revision_tree(rh[0])
105
95
text = tree1.get_file_text(file_id)
107
self.assertEqual('hello world', text)
96
eq(text, 'hello world')
109
98
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"""
99
eq(tree2.get_file_text(file_id), 'version 2')
101
def test_delete_commit(self):
102
"""Test a commit with a deleted file"""
155
103
wt = self.make_branch_and_tree('.')
157
105
file('hello', 'w').write('hello world')
164
112
tree = b.repository.revision_tree('rev2')
165
113
self.assertFalse(tree.has_id('hello-id'))
167
def test_partial_commit_move(self):
168
"""Test a partial commit where a file was renamed but not committed.
170
https://bugs.launchpad.net/bzr/+bug/83039
172
If not handled properly, commit will try to snapshot
173
dialog.py with olive/ as a parent, while
174
olive/ has not been snapshotted yet.
176
wt = self.make_branch_and_tree('.')
178
self.build_tree(['annotate/', 'annotate/foo.py',
179
'olive/', 'olive/dialog.py'
181
wt.add(['annotate', 'olive', 'annotate/foo.py', 'olive/dialog.py'])
182
wt.commit(message='add files')
183
wt.rename_one("olive/dialog.py", "aaa")
184
self.build_tree_contents([('annotate/foo.py', 'modified\n')])
185
wt.commit('renamed hello', specific_files=["annotate"])
187
115
def test_pointless_commit(self):
188
116
"""Commit refuses unless there are changes or it's forced."""
189
117
wt = self.make_branch_and_tree('.')
263
187
eq = self.assertEquals
264
188
tree1 = b.repository.revision_tree('test@rev-1')
266
self.addCleanup(tree1.unlock)
267
189
eq(tree1.id2path('hello-id'), 'hello')
268
190
eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
269
191
self.assertFalse(tree1.has_filename('fruity'))
270
self.check_tree_shape(tree1, ['hello'])
271
eq(tree1.get_file_revision('hello-id'), 'test@rev-1')
192
self.check_inventory_shape(tree1.inventory, ['hello'])
193
ie = tree1.inventory['hello-id']
194
eq(ie.revision, 'test@rev-1')
273
196
tree2 = b.repository.revision_tree('test@rev-2')
275
self.addCleanup(tree2.unlock)
276
197
eq(tree2.id2path('hello-id'), 'fruity')
277
198
eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
278
self.check_tree_shape(tree2, ['fruity'])
279
eq(tree2.get_file_revision('hello-id'), 'test@rev-2')
199
self.check_inventory_shape(tree2.inventory, ['fruity'])
200
ie = tree2.inventory['hello-id']
201
eq(ie.revision, 'test@rev-2')
281
203
def test_reused_rev_id(self):
282
204
"""Test that a revision id cannot be reused in a branch"""
587
517
this_tree.merge_from_branch(other_tree.branch)
588
518
reporter = CapturingReporter()
589
519
this_tree.commit('do the commit', reporter=reporter)
521
('change', 'unchanged', ''),
522
('change', 'unchanged', 'dirtoleave'),
523
('change', 'unchanged', 'filetoleave'),
591
524
('change', 'modified', 'filetomodify'),
592
525
('change', 'added', 'newdir'),
593
526
('change', 'added', 'newfile'),
594
527
('renamed', 'renamed', 'dirtorename', 'renameddir'),
595
('renamed', 'renamed', 'filetorename', 'renamedfile'),
596
528
('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
597
529
('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
530
('renamed', 'renamed', 'filetorename', 'renamedfile'),
598
531
('deleted', 'dirtoremove'),
599
532
('deleted', 'filetoremove'),
601
result = set(reporter.calls)
602
missing = expected - result
603
new = result - expected
604
self.assertEqual((set(), set()), (missing, new))
606
536
def test_commit_removals_respects_filespec(self):
607
537
"""Commit respects the specified_files for removals."""
745
676
cb = self.Callback(u'commit 2', self)
746
677
repository = tree.branch.repository
747
678
# simulate network failure
748
def raise_(self, arg, arg2, arg3=None, arg4=None):
679
def raise_(self, arg, arg2):
749
680
raise errors.NoSuchFile('foo')
750
681
repository.add_inventory = raise_
751
repository.add_inventory_by_delta = raise_
752
682
self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
753
683
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'))