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 (
28
25
from bzrlib.branch import Branch
29
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
26
from bzrlib.bzrdir import BzrDirMetaFormat1
30
27
from bzrlib.commit import Commit, NullCommitReporter
31
28
from bzrlib.config import BranchConfig
32
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed,
34
from bzrlib.tests import SymlinkFeature, TestCaseWithTransport
35
from bzrlib.workingtree import WorkingTree
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
38
45
# TODO: Test commit with some added, and added-but-missing files
108
115
self.assertEqual('version 2', text)
110
def test_delete_commit(self):
111
"""Test a commit with a deleted file"""
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"""
112
157
wt = self.make_branch_and_tree('.')
114
159
file('hello', 'w').write('hello world')
116
161
wt.commit(message='add hello')
118
163
os.remove('hello')
119
wt.commit('removed hello', rev_id='rev2')
164
reporter = CapturingReporter()
165
wt.commit('removed hello', rev_id='rev2', reporter=reporter)
167
[('missing', u'hello'), ('deleted', u'hello')],
121
170
tree = b.repository.revision_tree('rev2')
122
171
self.assertFalse(tree.has_id('hello-id'))
125
174
"""Test a partial commit where a file was renamed but not committed.
127
176
https://bugs.launchpad.net/bzr/+bug/83039
129
178
If not handled properly, commit will try to snapshot
130
dialog.py with olive/ as a parent, while
179
dialog.py with olive/ as a parent, while
131
180
olive/ has not been snapshotted yet.
133
182
wt = self.make_branch_and_tree('.')
224
273
eq(tree1.id2path('hello-id'), 'hello')
225
274
eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
226
275
self.assertFalse(tree1.has_filename('fruity'))
227
self.check_inventory_shape(tree1.inventory, ['hello'])
228
ie = tree1.inventory['hello-id']
229
eq(ie.revision, 'test@rev-1')
276
self.check_tree_shape(tree1, ['hello'])
277
eq(tree1.get_file_revision('hello-id'), 'test@rev-1')
231
279
tree2 = b.repository.revision_tree('test@rev-2')
232
280
tree2.lock_read()
233
281
self.addCleanup(tree2.unlock)
234
282
eq(tree2.id2path('hello-id'), 'fruity')
235
283
eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
236
self.check_inventory_shape(tree2.inventory, ['fruity'])
237
ie = tree2.inventory['hello-id']
238
eq(ie.revision, 'test@rev-2')
284
self.check_tree_shape(tree2, ['fruity'])
285
eq(tree2.get_file_revision('hello-id'), 'test@rev-2')
240
287
def test_reused_rev_id(self):
241
288
"""Test that a revision id cannot be reused in a branch"""
272
318
wt.commit('three', rev_id=r3, allow_pointless=False)
275
self.check_inventory_shape(wt.read_working_inventory(),
321
self.check_tree_shape(wt,
276
322
['a/', 'a/hello', 'a/b/'])
277
self.check_inventory_shape(b.repository.get_revision_inventory(r3),
323
self.check_tree_shape(b.repository.revision_tree(r3),
278
324
['a/', 'a/hello', 'a/b/'])
284
330
wt.commit('four', rev_id=r4, allow_pointless=False)
287
self.check_inventory_shape(wt.read_working_inventory(),
288
['a/', 'a/b/hello', 'a/b/'])
333
self.check_tree_shape(wt, ['a/', 'a/b/hello', 'a/b/'])
292
inv = b.repository.get_revision_inventory(r4)
337
inv = b.repository.get_inventory(r4)
293
338
eq(inv['hello-id'].revision, r4)
294
339
eq(inv['a-id'].revision, r1)
295
340
eq(inv['b-id'].revision, r3)
323
368
eq = self.assertEquals
324
369
eq(b.revision_history(), rev_ids)
325
370
for i in range(4):
326
anc = b.repository.get_ancestry(rev_ids[i])
327
eq(anc, [None] + rev_ids[:i+1])
371
self.assertThat(rev_ids[:i+1],
372
MatchesAncestry(b.repository, rev_ids[i]))
329
374
def test_commit_new_subdir_child_selective(self):
330
375
wt = self.make_branch_and_tree('.')
409
453
wt = self.make_branch_and_tree('.')
410
454
branch = wt.branch
411
455
wt.commit("base", allow_pointless=True, rev_id='A')
412
self.failIf(branch.repository.has_signature_for_revision_id('A'))
456
self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
414
from bzrlib.testament import Testament
415
458
# monkey patch gpg signing mechanism
416
459
bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
417
460
config = MustSignConfig(branch)
501
544
bound_tree.commit(message='commit of merge in bound tree')
503
546
def test_commit_reporting_after_merge(self):
504
# when doing a commit of a merge, the reporter needs to still
547
# when doing a commit of a merge, the reporter needs to still
505
548
# be called for each item that is added/removed/deleted.
506
549
this_tree = self.make_branch_and_tree('this')
507
550
# we need a bunch of files and dirs, to perform one action on each.
550
593
this_tree.merge_from_branch(other_tree.branch)
551
594
reporter = CapturingReporter()
552
595
this_tree.commit('do the commit', reporter=reporter)
554
('change', 'unchanged', ''),
555
('change', 'unchanged', 'dirtoleave'),
556
('change', 'unchanged', 'filetoleave'),
557
597
('change', 'modified', 'filetomodify'),
558
598
('change', 'added', 'newdir'),
559
599
('change', 'added', 'newfile'),
563
603
('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
564
604
('deleted', 'dirtoremove'),
565
605
('deleted', 'filetoremove'),
607
result = set(reporter.calls)
608
missing = expected - result
609
new = result - expected
610
self.assertEqual((set(), set()), (missing, new))
569
612
def test_commit_removals_respects_filespec(self):
570
613
"""Commit respects the specified_files for removals."""
660
703
def test_commit_unversioned_specified(self):
661
704
"""Commit should raise if specified files isn't in basis or worktree"""
662
705
tree = self.make_branch_and_tree('.')
663
self.assertRaises(errors.PathsNotVersionedError, tree.commit,
706
self.assertRaises(errors.PathsNotVersionedError, tree.commit,
664
707
'message', specific_files=['bogus'])
666
709
class Callback(object):
668
711
def __init__(self, message, testcase):
669
712
self.called = False
670
713
self.message = message
698
741
"""Callback should not be invoked for pointless commit"""
699
742
tree = self.make_branch_and_tree('.')
700
743
cb = self.Callback(u'commit 2', self)
701
self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
744
self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
702
745
allow_pointless=False)
703
746
self.assertFalse(cb.called)
708
751
cb = self.Callback(u'commit 2', self)
709
752
repository = tree.branch.repository
710
753
# simulate network failure
711
def raise_(self, arg, arg2):
754
def raise_(self, arg, arg2, arg3=None, arg4=None):
712
755
raise errors.NoSuchFile('foo')
713
756
repository.add_inventory = raise_
757
repository.add_inventory_by_delta = raise_
714
758
self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
715
759
self.assertFalse(cb.called)
747
791
rev_id = tree.commit('commit 1')
748
792
rev = tree.branch.repository.get_revision(rev_id)
749
793
self.assertFalse('author' in rev.properties)
794
self.assertFalse('authors' in rev.properties)
751
796
def test_commit_author(self):
752
797
"""Passing a non-empty author kwarg to MutableTree.commit should add
753
798
the 'author' revision property.
755
800
tree = self.make_branch_and_tree('foo')
756
rev_id = tree.commit('commit 1', author='John Doe <jdoe@example.com>')
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>')
757
804
rev = tree.branch.repository.get_revision(rev_id)
758
805
self.assertEqual('John Doe <jdoe@example.com>',
759
rev.properties['author'])
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>'])
761
839
def test_commit_with_checkout_and_branch_sharing_repo(self):
762
840
repo = self.make_repository('repo', shared=True)