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 (
36
TestCaseWithTransport,
39
from bzrlib.tests.features import (
42
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
45
37
# TODO: Test commit with some added, and added-but-missing files
103
92
eq(rev.message, 'add hello')
105
94
tree1 = b.repository.revision_tree(rh[0])
107
95
text = tree1.get_file_text(file_id)
109
self.assertEqual('hello world', text)
96
eq(text, 'hello world')
111
98
tree2 = b.repository.revision_tree(rh[1])
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"""
99
eq(tree2.get_file_text(file_id), 'version 2')
101
def test_delete_commit(self):
102
"""Test a commit with a deleted file"""
157
103
wt = self.make_branch_and_tree('.')
159
105
file('hello', 'w').write('hello world')
166
112
tree = b.repository.revision_tree('rev2')
167
113
self.assertFalse(tree.has_id('hello-id'))
169
def test_partial_commit_move(self):
170
"""Test a partial commit where a file was renamed but not committed.
172
https://bugs.launchpad.net/bzr/+bug/83039
174
If not handled properly, commit will try to snapshot
175
dialog.py with olive/ as a parent, while
176
olive/ has not been snapshotted yet.
178
wt = self.make_branch_and_tree('.')
180
self.build_tree(['annotate/', 'annotate/foo.py',
181
'olive/', 'olive/dialog.py'
183
wt.add(['annotate', 'olive', 'annotate/foo.py', 'olive/dialog.py'])
184
wt.commit(message='add files')
185
wt.rename_one("olive/dialog.py", "aaa")
186
self.build_tree_contents([('annotate/foo.py', 'modified\n')])
187
wt.commit('renamed hello', specific_files=["annotate"])
189
115
def test_pointless_commit(self):
190
116
"""Commit refuses unless there are changes or it's forced."""
191
117
wt = self.make_branch_and_tree('.')
265
187
eq = self.assertEquals
266
188
tree1 = b.repository.revision_tree('test@rev-1')
268
self.addCleanup(tree1.unlock)
269
189
eq(tree1.id2path('hello-id'), 'hello')
270
190
eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
271
191
self.assertFalse(tree1.has_filename('fruity'))
272
self.check_tree_shape(tree1, ['hello'])
273
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')
275
196
tree2 = b.repository.revision_tree('test@rev-2')
277
self.addCleanup(tree2.unlock)
278
197
eq(tree2.id2path('hello-id'), 'fruity')
279
198
eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
280
self.check_tree_shape(tree2, ['fruity'])
281
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')
283
203
def test_reused_rev_id(self):
284
204
"""Test that a revision id cannot be reused in a branch"""
326
247
wt.commit('four', rev_id=r4, allow_pointless=False)
329
self.check_tree_shape(wt, ['a/', 'a/b/hello', 'a/b/'])
250
self.check_inventory_shape(wt.read_working_inventory(),
251
['a', 'a/b/hello', 'a/b'])
333
inv = b.repository.get_inventory(r4)
255
inv = b.repository.get_revision_inventory(r4)
334
256
eq(inv['hello-id'].revision, r4)
335
257
eq(inv['a-id'].revision, r1)
336
258
eq(inv['b-id'].revision, r3)
589
517
this_tree.merge_from_branch(other_tree.branch)
590
518
reporter = CapturingReporter()
591
519
this_tree.commit('do the commit', reporter=reporter)
521
('change', 'unchanged', ''),
522
('change', 'unchanged', 'dirtoleave'),
523
('change', 'unchanged', 'filetoleave'),
593
524
('change', 'modified', 'filetomodify'),
594
525
('change', 'added', 'newdir'),
595
526
('change', 'added', 'newfile'),
596
527
('renamed', 'renamed', 'dirtorename', 'renameddir'),
597
('renamed', 'renamed', 'filetorename', 'renamedfile'),
598
528
('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
599
529
('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
530
('renamed', 'renamed', 'filetorename', 'renamedfile'),
600
531
('deleted', 'dirtoremove'),
601
532
('deleted', 'filetoremove'),
603
result = set(reporter.calls)
604
missing = expected - result
605
new = result - expected
606
self.assertEqual((set(), set()), (missing, new))
608
536
def test_commit_removals_respects_filespec(self):
609
537
"""Commit respects the specified_files for removals."""
747
676
cb = self.Callback(u'commit 2', self)
748
677
repository = tree.branch.repository
749
678
# simulate network failure
750
def raise_(self, arg, arg2, arg3=None, arg4=None):
679
def raise_(self, arg, arg2):
751
680
raise errors.NoSuchFile('foo')
752
681
repository.add_inventory = raise_
753
repository.add_inventory_by_delta = raise_
754
682
self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
755
683
self.assertFalse(cb.called)
767
695
self.assertEqual(['bar', 'baz'], err.files)
768
696
self.assertEqual('Selected-file commit of merges is not supported'
769
697
' yet: files bar, baz', str(err))
771
def test_commit_ordering(self):
772
"""Test of corner-case commit ordering error"""
773
tree = self.make_branch_and_tree('.')
774
self.build_tree(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
775
tree.add(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
777
self.build_tree(['a/c/d/'])
779
tree.rename_one('a/z/x', 'a/c/d/x')
780
tree.commit('test', specific_files=['a/z/y'])
782
def test_commit_no_author(self):
783
"""The default kwarg author in MutableTree.commit should not add
784
the 'author' revision property.
786
tree = self.make_branch_and_tree('foo')
787
rev_id = tree.commit('commit 1')
788
rev = tree.branch.repository.get_revision(rev_id)
789
self.assertFalse('author' in rev.properties)
790
self.assertFalse('authors' in rev.properties)
792
def test_commit_author(self):
793
"""Passing a non-empty author kwarg to MutableTree.commit should add
794
the 'author' revision property.
796
tree = self.make_branch_and_tree('foo')
797
rev_id = self.callDeprecated(['The parameter author was '
798
'deprecated in version 1.13. Use authors instead'],
799
tree.commit, 'commit 1', author='John Doe <jdoe@example.com>')
800
rev = tree.branch.repository.get_revision(rev_id)
801
self.assertEqual('John Doe <jdoe@example.com>',
802
rev.properties['authors'])
803
self.assertFalse('author' in rev.properties)
805
def test_commit_empty_authors_list(self):
806
"""Passing an empty list to authors shouldn't add the property."""
807
tree = self.make_branch_and_tree('foo')
808
rev_id = tree.commit('commit 1', authors=[])
809
rev = tree.branch.repository.get_revision(rev_id)
810
self.assertFalse('author' in rev.properties)
811
self.assertFalse('authors' in rev.properties)
813
def test_multiple_authors(self):
814
tree = self.make_branch_and_tree('foo')
815
rev_id = tree.commit('commit 1',
816
authors=['John Doe <jdoe@example.com>',
817
'Jane Rey <jrey@example.com>'])
818
rev = tree.branch.repository.get_revision(rev_id)
819
self.assertEqual('John Doe <jdoe@example.com>\n'
820
'Jane Rey <jrey@example.com>', rev.properties['authors'])
821
self.assertFalse('author' in rev.properties)
823
def test_author_and_authors_incompatible(self):
824
tree = self.make_branch_and_tree('foo')
825
self.assertRaises(AssertionError, tree.commit, 'commit 1',
826
authors=['John Doe <jdoe@example.com>',
827
'Jane Rey <jrey@example.com>'],
828
author="Jack Me <jme@example.com>")
830
def test_author_with_newline_rejected(self):
831
tree = self.make_branch_and_tree('foo')
832
self.assertRaises(AssertionError, tree.commit, 'commit 1',
833
authors=['John\nDoe <jdoe@example.com>'])
835
def test_commit_with_checkout_and_branch_sharing_repo(self):
836
repo = self.make_repository('repo', shared=True)
837
# make_branch_and_tree ignores shared repos
838
branch = bzrdir.BzrDir.create_branch_convenience('repo/branch')
839
tree2 = branch.create_checkout('repo/tree2')
840
tree2.commit('message', rev_id='rev1')
841
self.assertTrue(tree2.branch.repository.has_revision('rev1'))