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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
21
from bzrlib import (
27
25
from bzrlib.branch import Branch
28
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
26
from bzrlib.bzrdir import BzrDirMetaFormat1
29
27
from bzrlib.commit import Commit, NullCommitReporter
30
28
from bzrlib.config import BranchConfig
31
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed,
29
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed,
33
from bzrlib.tests import TestCaseWithTransport
34
from bzrlib.workingtree import WorkingTree
31
from bzrlib.tests import (
33
TestCaseWithTransport,
37
38
# TODO: Test commit with some added, and added-but-missing files
92
96
eq(rev.message, 'add hello')
94
98
tree1 = b.repository.revision_tree(rh[0])
95
100
text = tree1.get_file_text(file_id)
96
eq(text, 'hello world')
102
self.assertEqual('hello world', text)
98
104
tree2 = b.repository.revision_tree(rh[1])
99
eq(tree2.get_file_text(file_id), 'version 2')
101
def test_delete_commit(self):
102
"""Test a commit with a deleted file"""
106
text = tree2.get_file_text(file_id)
108
self.assertEqual('version 2', text)
110
def test_commit_lossy_native(self):
111
"""Attempt a lossy commit to a native branch."""
112
wt = self.make_branch_and_tree('.')
114
file('hello', 'w').write('hello world')
116
revid = wt.commit(message='add hello', rev_id='revid', lossy=True)
117
self.assertEquals('revid', revid)
119
def test_commit_lossy_foreign(self):
120
"""Attempt a lossy commit to a foreign branch."""
121
test_foreign.register_dummy_foreign_for_test(self)
122
wt = self.make_branch_and_tree('.',
123
format=test_foreign.DummyForeignVcsDirFormat())
125
file('hello', 'w').write('hello world')
127
revid = wt.commit(message='add hello', lossy=True,
128
timestamp=1302659388, timezone=0)
129
self.assertEquals('dummy-v1:1302659388.0-0-UNKNOWN', revid)
131
def test_commit_bound_lossy_foreign(self):
132
"""Attempt a lossy commit to a bzr branch bound to a foreign branch."""
133
test_foreign.register_dummy_foreign_for_test(self)
134
foreign_branch = self.make_branch('foreign',
135
format=test_foreign.DummyForeignVcsDirFormat())
136
wt = foreign_branch.create_checkout("local")
138
file('local/hello', 'w').write('hello world')
140
revid = wt.commit(message='add hello', lossy=True,
141
timestamp=1302659388, timezone=0)
142
self.assertEquals('dummy-v1:1302659388.0-0-0', revid)
143
self.assertEquals('dummy-v1:1302659388.0-0-0',
144
foreign_branch.last_revision())
145
self.assertEquals('dummy-v1:1302659388.0-0-0',
146
wt.branch.last_revision())
148
def test_missing_commit(self):
149
"""Test a commit with a missing file"""
103
150
wt = self.make_branch_and_tree('.')
105
152
file('hello', 'w').write('hello world')
112
159
tree = b.repository.revision_tree('rev2')
113
160
self.assertFalse(tree.has_id('hello-id'))
162
def test_partial_commit_move(self):
163
"""Test a partial commit where a file was renamed but not committed.
165
https://bugs.launchpad.net/bzr/+bug/83039
167
If not handled properly, commit will try to snapshot
168
dialog.py with olive/ as a parent, while
169
olive/ has not been snapshotted yet.
171
wt = self.make_branch_and_tree('.')
173
self.build_tree(['annotate/', 'annotate/foo.py',
174
'olive/', 'olive/dialog.py'
176
wt.add(['annotate', 'olive', 'annotate/foo.py', 'olive/dialog.py'])
177
wt.commit(message='add files')
178
wt.rename_one("olive/dialog.py", "aaa")
179
self.build_tree_contents([('annotate/foo.py', 'modified\n')])
180
wt.commit('renamed hello', specific_files=["annotate"])
115
182
def test_pointless_commit(self):
116
183
"""Commit refuses unless there are changes or it's forced."""
117
184
wt = self.make_branch_and_tree('.')
187
258
eq = self.assertEquals
188
259
tree1 = b.repository.revision_tree('test@rev-1')
261
self.addCleanup(tree1.unlock)
189
262
eq(tree1.id2path('hello-id'), 'hello')
190
263
eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
191
264
self.assertFalse(tree1.has_filename('fruity'))
192
self.check_inventory_shape(tree1.inventory, ['hello'])
193
ie = tree1.inventory['hello-id']
194
eq(ie.revision, 'test@rev-1')
265
self.check_tree_shape(tree1, ['hello'])
266
eq(tree1.get_file_revision('hello-id'), 'test@rev-1')
196
268
tree2 = b.repository.revision_tree('test@rev-2')
270
self.addCleanup(tree2.unlock)
197
271
eq(tree2.id2path('hello-id'), 'fruity')
198
272
eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
199
self.check_inventory_shape(tree2.inventory, ['fruity'])
200
ie = tree2.inventory['hello-id']
201
eq(ie.revision, 'test@rev-2')
273
self.check_tree_shape(tree2, ['fruity'])
274
eq(tree2.get_file_revision('hello-id'), 'test@rev-2')
203
276
def test_reused_rev_id(self):
204
277
"""Test that a revision id cannot be reused in a branch"""
515
582
this_tree.merge_from_branch(other_tree.branch)
516
583
reporter = CapturingReporter()
517
584
this_tree.commit('do the commit', reporter=reporter)
519
('change', 'unchanged', ''),
520
('change', 'unchanged', 'dirtoleave'),
521
('change', 'unchanged', 'filetoleave'),
522
586
('change', 'modified', 'filetomodify'),
523
587
('change', 'added', 'newdir'),
524
588
('change', 'added', 'newfile'),
525
589
('renamed', 'renamed', 'dirtorename', 'renameddir'),
590
('renamed', 'renamed', 'filetorename', 'renamedfile'),
526
591
('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
527
592
('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
528
('renamed', 'renamed', 'filetorename', 'renamedfile'),
529
593
('deleted', 'dirtoremove'),
530
594
('deleted', 'filetoremove'),
596
result = set(reporter.calls)
597
missing = expected - result
598
new = result - expected
599
self.assertEqual((set(), set()), (missing, new))
534
601
def test_commit_removals_respects_filespec(self):
535
602
"""Commit respects the specified_files for removals."""
674
740
cb = self.Callback(u'commit 2', self)
675
741
repository = tree.branch.repository
676
742
# simulate network failure
677
def raise_(self, arg, arg2):
743
def raise_(self, arg, arg2, arg3=None, arg4=None):
678
744
raise errors.NoSuchFile('foo')
679
745
repository.add_inventory = raise_
746
repository.add_inventory_by_delta = raise_
680
747
self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
681
748
self.assertFalse(cb.called)
750
def test_selected_file_merge_commit(self):
751
"""Ensure the correct error is raised"""
752
tree = self.make_branch_and_tree('foo')
753
# pending merge would turn into a left parent
754
tree.commit('commit 1')
755
tree.add_parent_tree_id('example')
756
self.build_tree(['foo/bar', 'foo/baz'])
757
tree.add(['bar', 'baz'])
758
err = self.assertRaises(errors.CannotCommitSelectedFileMerge,
759
tree.commit, 'commit 2', specific_files=['bar', 'baz'])
760
self.assertEqual(['bar', 'baz'], err.files)
761
self.assertEqual('Selected-file commit of merges is not supported'
762
' yet: files bar, baz', str(err))
764
def test_commit_ordering(self):
765
"""Test of corner-case commit ordering error"""
766
tree = self.make_branch_and_tree('.')
767
self.build_tree(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
768
tree.add(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
770
self.build_tree(['a/c/d/'])
772
tree.rename_one('a/z/x', 'a/c/d/x')
773
tree.commit('test', specific_files=['a/z/y'])
775
def test_commit_no_author(self):
776
"""The default kwarg author in MutableTree.commit should not add
777
the 'author' revision property.
779
tree = self.make_branch_and_tree('foo')
780
rev_id = tree.commit('commit 1')
781
rev = tree.branch.repository.get_revision(rev_id)
782
self.assertFalse('author' in rev.properties)
783
self.assertFalse('authors' in rev.properties)
785
def test_commit_author(self):
786
"""Passing a non-empty author kwarg to MutableTree.commit should add
787
the 'author' revision property.
789
tree = self.make_branch_and_tree('foo')
790
rev_id = self.callDeprecated(['The parameter author was '
791
'deprecated in version 1.13. Use authors instead'],
792
tree.commit, 'commit 1', author='John Doe <jdoe@example.com>')
793
rev = tree.branch.repository.get_revision(rev_id)
794
self.assertEqual('John Doe <jdoe@example.com>',
795
rev.properties['authors'])
796
self.assertFalse('author' in rev.properties)
798
def test_commit_empty_authors_list(self):
799
"""Passing an empty list to authors shouldn't add the property."""
800
tree = self.make_branch_and_tree('foo')
801
rev_id = tree.commit('commit 1', authors=[])
802
rev = tree.branch.repository.get_revision(rev_id)
803
self.assertFalse('author' in rev.properties)
804
self.assertFalse('authors' in rev.properties)
806
def test_multiple_authors(self):
807
tree = self.make_branch_and_tree('foo')
808
rev_id = tree.commit('commit 1',
809
authors=['John Doe <jdoe@example.com>',
810
'Jane Rey <jrey@example.com>'])
811
rev = tree.branch.repository.get_revision(rev_id)
812
self.assertEqual('John Doe <jdoe@example.com>\n'
813
'Jane Rey <jrey@example.com>', rev.properties['authors'])
814
self.assertFalse('author' in rev.properties)
816
def test_author_and_authors_incompatible(self):
817
tree = self.make_branch_and_tree('foo')
818
self.assertRaises(AssertionError, tree.commit, 'commit 1',
819
authors=['John Doe <jdoe@example.com>',
820
'Jane Rey <jrey@example.com>'],
821
author="Jack Me <jme@example.com>")
823
def test_author_with_newline_rejected(self):
824
tree = self.make_branch_and_tree('foo')
825
self.assertRaises(AssertionError, tree.commit, 'commit 1',
826
authors=['John\nDoe <jdoe@example.com>'])
828
def test_commit_with_checkout_and_branch_sharing_repo(self):
829
repo = self.make_repository('repo', shared=True)
830
# make_branch_and_tree ignores shared repos
831
branch = bzrdir.BzrDir.create_branch_convenience('repo/branch')
832
tree2 = branch.create_checkout('repo/tree2')
833
tree2.commit('message', rev_id='rev1')
834
self.assertTrue(tree2.branch.repository.has_revision('rev1'))