52
43
return "bzrlib.ahook bzrlib.ahook"
55
class CapturingReporter(NullCommitReporter):
56
"""This reporter captures the calls made to it for evaluation later."""
59
# a list of the calls this received
62
def snapshot_change(self, change, path):
63
self.calls.append(('change', change, path))
65
def deleted(self, file_id):
66
self.calls.append(('deleted', file_id))
68
def missing(self, path):
69
self.calls.append(('missing', path))
71
def renamed(self, change, old_path, new_path):
72
self.calls.append(('renamed', change, old_path, new_path))
78
class TestCommit(TestCaseWithTransport):
46
class TestCommit(TestCaseInTempDir):
80
48
def test_simple_commit(self):
81
49
"""Commit and check two versions of a single file."""
82
wt = self.make_branch_and_tree('.')
50
b = Branch.initialize('.')
84
51
file('hello', 'w').write('hello world')
86
wt.commit(message='add hello')
87
file_id = wt.path2id('hello')
53
b.working_tree().commit(message='add hello')
54
file_id = b.working_tree().path2id('hello')
89
56
file('hello', 'w').write('version 2')
90
wt.commit(message='commit 2')
57
b.working_tree().commit(message='commit 2')
92
59
eq = self.assertEquals
94
61
rh = b.revision_history()
95
rev = b.repository.get_revision(rh[0])
62
rev = b.get_revision(rh[0])
96
63
eq(rev.message, 'add hello')
98
tree1 = b.repository.revision_tree(rh[0])
65
tree1 = b.revision_tree(rh[0])
100
66
text = tree1.get_file_text(file_id)
102
self.assertEqual('hello world', text)
67
eq(text, 'hello world')
104
tree2 = b.repository.revision_tree(rh[1])
106
text = tree2.get_file_text(file_id)
108
self.assertEqual('version 2', text)
69
tree2 = b.revision_tree(rh[1])
70
eq(tree2.get_file_text(file_id), 'version 2')
110
72
def test_delete_commit(self):
111
73
"""Test a commit with a deleted file"""
112
wt = self.make_branch_and_tree('.')
74
b = Branch.initialize('.')
114
75
file('hello', 'w').write('hello world')
115
wt.add(['hello'], ['hello-id'])
116
wt.commit(message='add hello')
76
b.add(['hello'], ['hello-id'])
77
b.working_tree().commit(message='add hello')
118
79
os.remove('hello')
119
wt.commit('removed hello', rev_id='rev2')
80
b.working_tree().commit('removed hello', rev_id='rev2')
121
tree = b.repository.revision_tree('rev2')
82
tree = b.revision_tree('rev2')
122
83
self.assertFalse(tree.has_id('hello-id'))
124
def test_partial_commit_move(self):
125
"""Test a partial commit where a file was renamed but not committed.
127
https://bugs.launchpad.net/bzr/+bug/83039
129
If not handled properly, commit will try to snapshot
130
dialog.py with olive/ as a parent, while
131
olive/ has not been snapshotted yet.
133
wt = self.make_branch_and_tree('.')
135
self.build_tree(['annotate/', 'annotate/foo.py',
136
'olive/', 'olive/dialog.py'
138
wt.add(['annotate', 'olive', 'annotate/foo.py', 'olive/dialog.py'])
139
wt.commit(message='add files')
140
wt.rename_one("olive/dialog.py", "aaa")
141
self.build_tree_contents([('annotate/foo.py', 'modified\n')])
142
wt.commit('renamed hello', specific_files=["annotate"])
144
85
def test_pointless_commit(self):
145
86
"""Commit refuses unless there are changes or it's forced."""
146
wt = self.make_branch_and_tree('.')
87
b = Branch.initialize('.')
148
88
file('hello', 'w').write('hello')
150
wt.commit(message='add hello')
90
b.working_tree().commit(message='add hello')
151
91
self.assertEquals(b.revno(), 1)
152
92
self.assertRaises(PointlessCommit,
93
b.working_tree().commit,
155
95
allow_pointless=False)
156
96
self.assertEquals(b.revno(), 1)
158
98
def test_commit_empty(self):
159
99
"""Commiting an empty tree works."""
160
wt = self.make_branch_and_tree('.')
162
wt.commit(message='empty tree', allow_pointless=True)
100
b = Branch.initialize('.')
101
b.working_tree().commit(message='empty tree', allow_pointless=True)
163
102
self.assertRaises(PointlessCommit,
103
b.working_tree().commit,
165
104
message='empty tree',
166
105
allow_pointless=False)
167
wt.commit(message='empty tree', allow_pointless=True)
106
b.working_tree().commit(message='empty tree', allow_pointless=True)
168
107
self.assertEquals(b.revno(), 2)
170
110
def test_selective_delete(self):
171
111
"""Selective commit in tree with deletions"""
172
wt = self.make_branch_and_tree('.')
112
b = Branch.initialize('.')
174
113
file('hello', 'w').write('hello')
175
114
file('buongia', 'w').write('buongia')
176
wt.add(['hello', 'buongia'],
115
b.add(['hello', 'buongia'],
177
116
['hello-id', 'buongia-id'])
178
wt.commit(message='add files',
117
b.working_tree().commit(message='add files',
179
118
rev_id='test@rev-1')
181
120
os.remove('hello')
182
121
file('buongia', 'w').write('new text')
183
wt.commit(message='update text',
122
b.working_tree().commit(message='update text',
184
123
specific_files=['buongia'],
185
124
allow_pointless=False,
186
125
rev_id='test@rev-2')
188
wt.commit(message='remove hello',
127
b.working_tree().commit(message='remove hello',
189
128
specific_files=['hello'],
190
129
allow_pointless=False,
191
130
rev_id='test@rev-3')
228
161
ie = tree1.inventory['hello-id']
229
162
eq(ie.revision, 'test@rev-1')
231
tree2 = b.repository.revision_tree('test@rev-2')
233
self.addCleanup(tree2.unlock)
164
tree2 = b.revision_tree('test@rev-2')
234
165
eq(tree2.id2path('hello-id'), 'fruity')
235
166
eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
236
167
self.check_inventory_shape(tree2.inventory, ['fruity'])
237
168
ie = tree2.inventory['hello-id']
238
169
eq(ie.revision, 'test@rev-2')
240
172
def test_reused_rev_id(self):
241
173
"""Test that a revision id cannot be reused in a branch"""
242
wt = self.make_branch_and_tree('.')
244
wt.commit('initial', rev_id='test@rev-1', allow_pointless=True)
174
b = Branch.initialize('.')
175
b.working_tree().commit('initial', rev_id='test@rev-1', allow_pointless=True)
245
176
self.assertRaises(Exception,
177
b.working_tree().commit,
247
178
message='reused id',
248
179
rev_id='test@rev-1',
249
180
allow_pointless=True)
251
184
def test_commit_move(self):
252
185
"""Test commit of revisions with moved files and directories"""
253
186
eq = self.assertEquals
254
wt = self.make_branch_and_tree('.')
187
b = Branch.initialize('.')
256
188
r1 = 'test@rev-1'
257
189
self.build_tree(['hello', 'a/', 'b/'])
258
wt.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
259
wt.commit('initial', rev_id=r1, allow_pointless=False)
260
wt.move(['hello'], 'a')
190
b.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
191
b.working_tree().commit('initial', rev_id=r1, allow_pointless=False)
193
b.move(['hello'], 'a')
261
194
r2 = 'test@rev-2'
262
wt.commit('two', rev_id=r2, allow_pointless=False)
265
self.check_inventory_shape(wt.read_working_inventory(),
266
['a/', 'a/hello', 'b/'])
195
b.working_tree().commit('two', rev_id=r2, allow_pointless=False)
196
self.check_inventory_shape(b.working_tree().read_working_inventory(),
197
['a', 'a/hello', 'b'])
271
200
r3 = 'test@rev-3'
272
wt.commit('three', rev_id=r3, allow_pointless=False)
275
self.check_inventory_shape(wt.read_working_inventory(),
276
['a/', 'a/hello', 'a/b/'])
277
self.check_inventory_shape(b.repository.get_revision_inventory(r3),
278
['a/', 'a/hello', 'a/b/'])
201
b.working_tree().commit('three', rev_id=r3, allow_pointless=False)
202
self.check_inventory_shape(b.working_tree().read_working_inventory(),
203
['a', 'a/hello', 'a/b'])
204
self.check_inventory_shape(b.get_revision_inventory(r3),
205
['a', 'a/hello', 'a/b'])
282
wt.move(['a/hello'], 'a/b')
207
b.move([os.sep.join(['a', 'hello'])],
208
os.sep.join(['a', 'b']))
283
209
r4 = 'test@rev-4'
284
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/'])
210
b.working_tree().commit('four', rev_id=r4, allow_pointless=False)
211
self.check_inventory_shape(b.working_tree().read_working_inventory(),
212
['a', 'a/b/hello', 'a/b'])
292
inv = b.repository.get_revision_inventory(r4)
214
inv = b.get_revision_inventory(r4)
293
215
eq(inv['hello-id'].revision, r4)
294
216
eq(inv['a-id'].revision, r1)
295
217
eq(inv['b-id'].revision, r3)
297
220
def test_removed_commit(self):
298
221
"""Commit with a removed file"""
299
wt = self.make_branch_and_tree('.')
222
b = Branch.initialize('.')
223
wt = b.working_tree()
301
224
file('hello', 'w').write('hello world')
302
wt.add(['hello'], ['hello-id'])
303
wt.commit(message='add hello')
225
b.add(['hello'], ['hello-id'])
226
b.working_tree().commit(message='add hello')
228
wt = b.working_tree() # FIXME: kludge for aliasing of working inventory
304
229
wt.remove('hello')
305
wt.commit('removed hello', rev_id='rev2')
230
b.working_tree().commit('removed hello', rev_id='rev2')
307
tree = b.repository.revision_tree('rev2')
232
tree = b.revision_tree('rev2')
308
233
self.assertFalse(tree.has_id('hello-id'))
310
236
def test_committed_ancestry(self):
311
237
"""Test commit appends revisions to ancestry."""
312
wt = self.make_branch_and_tree('.')
238
b = Branch.initialize('.')
315
240
for i in range(4):
316
241
file('hello', 'w').write((str(i) * 4) + '\n')
318
wt.add(['hello'], ['hello-id'])
243
b.add(['hello'], ['hello-id'])
319
244
rev_id = 'test@rev-%d' % (i+1)
320
245
rev_ids.append(rev_id)
321
wt.commit(message='rev %d' % (i+1),
246
b.working_tree().commit(message='rev %d' % (i+1),
323
248
eq = self.assertEquals
324
249
eq(b.revision_history(), rev_ids)
325
250
for i in range(4):
326
anc = b.repository.get_ancestry(rev_ids[i])
251
anc = b.get_ancestry(rev_ids[i])
327
252
eq(anc, [None] + rev_ids[:i+1])
329
254
def test_commit_new_subdir_child_selective(self):
330
wt = self.make_branch_and_tree('.')
255
b = Branch.initialize('.')
332
256
self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
333
wt.add(['dir', 'dir/file1', 'dir/file2'],
257
b.add(['dir', 'dir/file1', 'dir/file2'],
334
258
['dirid', 'file1id', 'file2id'])
335
wt.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
336
inv = b.repository.get_inventory('1')
259
b.working_tree().commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
260
inv = b.get_inventory('1')
337
261
self.assertEqual('1', inv['dirid'].revision)
338
262
self.assertEqual('1', inv['file1id'].revision)
339
263
# FIXME: This should raise a KeyError I think, rbc20051006
342
266
def test_strict_commit(self):
343
267
"""Try and commit with unknown files and strict = True, should fail."""
344
268
from bzrlib.errors import StrictCommitFailed
345
wt = self.make_branch_and_tree('.')
269
b = Branch.initialize('.')
347
270
file('hello', 'w').write('hello world')
349
272
file('goodbye', 'w').write('goodbye cruel world!')
350
self.assertRaises(StrictCommitFailed, wt.commit,
273
self.assertRaises(StrictCommitFailed, b.working_tree().commit,
351
274
message='add hello but not goodbye', strict=True)
353
276
def test_strict_commit_without_unknowns(self):
354
277
"""Try and commit with no unknown files and strict = True,
356
279
from bzrlib.errors import StrictCommitFailed
357
wt = self.make_branch_and_tree('.')
280
b = Branch.initialize('.')
359
281
file('hello', 'w').write('hello world')
361
wt.commit(message='add hello', strict=True)
283
b.working_tree().commit(message='add hello', strict=True)
363
285
def test_nonstrict_commit(self):
364
286
"""Try and commit with unknown files and strict = False, should work."""
365
wt = self.make_branch_and_tree('.')
287
b = Branch.initialize('.')
367
288
file('hello', 'w').write('hello world')
369
290
file('goodbye', 'w').write('goodbye cruel world!')
370
wt.commit(message='add hello but not goodbye', strict=False)
291
b.working_tree().commit(message='add hello but not goodbye', strict=False)
372
293
def test_nonstrict_commit_without_unknowns(self):
373
294
"""Try and commit with no unknown files and strict = False,
375
wt = self.make_branch_and_tree('.')
296
b = Branch.initialize('.')
377
297
file('hello', 'w').write('hello world')
379
wt.commit(message='add hello', strict=False)
299
b.working_tree().commit(message='add hello', strict=False)
381
301
def test_signed_commit(self):
382
302
import bzrlib.gpg
383
303
import bzrlib.commit as commit
384
304
oldstrategy = bzrlib.gpg.GPGStrategy
385
wt = self.make_branch_and_tree('.')
387
wt.commit("base", allow_pointless=True, rev_id='A')
388
self.failIf(branch.repository.has_signature_for_revision_id('A'))
305
branch = Branch.initialize('.')
306
branch.working_tree().commit("base", allow_pointless=True, rev_id='A')
307
self.failIf(branch.revision_store.has_id('A', 'sig'))
390
309
from bzrlib.testament import Testament
391
310
# monkey patch gpg signing mechanism
392
311
bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
393
commit.Commit(config=MustSignConfig(branch)).commit(message="base",
312
commit.Commit(config=MustSignConfig(branch)).commit(branch, "base",
394
313
allow_pointless=True,
398
return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
399
self.assertEqual(sign(Testament.from_revision(branch.repository,
400
'B').as_short_text()),
401
branch.repository.get_signature_text('B'))
315
self.assertEqual(Testament.from_revision(branch,'B').as_short_text(),
316
branch.revision_store.get('B', 'sig').read())
403
318
bzrlib.gpg.GPGStrategy = oldstrategy
439
351
config = BranchWithHooks(branch)
440
352
commit.Commit(config=config).commit(
442
354
allow_pointless=True,
443
rev_id='A', working_tree = wt)
444
356
self.assertEqual(['called', 'called'], calls)
448
def test_commit_object_doesnt_set_nick(self):
449
# using the Commit object directly does not set the branch nick.
450
wt = self.make_branch_and_tree('.')
452
c.commit(working_tree=wt, message='empty tree', allow_pointless=True)
453
self.assertEquals(wt.branch.revno(), 1)
455
wt.branch.repository.get_revision(
456
wt.branch.last_revision()).properties)
458
def test_safe_master_lock(self):
460
master = BzrDirMetaFormat1().initialize('master')
461
master.create_repository()
462
master_branch = master.create_branch()
463
master.create_workingtree()
464
bound = master.sprout('bound')
465
wt = bound.open_workingtree()
466
wt.branch.set_bound_location(os.path.realpath('master'))
467
master_branch.lock_write()
469
self.assertRaises(LockContention, wt.commit, 'silly')
471
master_branch.unlock()
473
def test_commit_bound_merge(self):
474
# see bug #43959; commit of a merge in a bound branch fails to push
475
# the new commit into the master
476
master_branch = self.make_branch('master')
477
bound_tree = self.make_branch_and_tree('bound')
478
bound_tree.branch.bind(master_branch)
480
self.build_tree_contents([('bound/content_file', 'initial contents\n')])
481
bound_tree.add(['content_file'])
482
bound_tree.commit(message='woo!')
484
other_bzrdir = master_branch.bzrdir.sprout('other')
485
other_tree = other_bzrdir.open_workingtree()
487
# do a commit to the the other branch changing the content file so
488
# that our commit after merging will have a merged revision in the
489
# content file history.
490
self.build_tree_contents([('other/content_file', 'change in other\n')])
491
other_tree.commit('change in other')
493
# do a merge into the bound branch from other, and then change the
494
# content file locally to force a new revision (rather than using the
495
# revision from other). This forces extra processing in commit.
496
bound_tree.merge_from_branch(other_tree.branch)
497
self.build_tree_contents([('bound/content_file', 'change in bound\n')])
499
# before #34959 was fixed, this failed with 'revision not present in
500
# weave' when trying to implicitly push from the bound branch to the master
501
bound_tree.commit(message='commit of merge in bound tree')
503
def test_commit_reporting_after_merge(self):
504
# when doing a commit of a merge, the reporter needs to still
505
# be called for each item that is added/removed/deleted.
506
this_tree = self.make_branch_and_tree('this')
507
# we need a bunch of files and dirs, to perform one action on each.
510
'this/dirtoreparent/',
513
'this/filetoreparent',
530
this_tree.commit('create_files')
531
other_dir = this_tree.bzrdir.sprout('other')
532
other_tree = other_dir.open_workingtree()
533
other_tree.lock_write()
534
# perform the needed actions on the files and dirs.
536
other_tree.rename_one('dirtorename', 'renameddir')
537
other_tree.rename_one('dirtoreparent', 'renameddir/reparenteddir')
538
other_tree.rename_one('filetorename', 'renamedfile')
539
other_tree.rename_one('filetoreparent', 'renameddir/reparentedfile')
540
other_tree.remove(['dirtoremove', 'filetoremove'])
541
self.build_tree_contents([
543
('other/filetomodify', 'new content'),
544
('other/newfile', 'new file content')])
545
other_tree.add('newfile')
546
other_tree.add('newdir/')
547
other_tree.commit('modify all sample files and dirs.')
550
this_tree.merge_from_branch(other_tree.branch)
551
reporter = CapturingReporter()
552
this_tree.commit('do the commit', reporter=reporter)
554
('change', 'unchanged', ''),
555
('change', 'unchanged', 'dirtoleave'),
556
('change', 'unchanged', 'filetoleave'),
557
('change', 'modified', 'filetomodify'),
558
('change', 'added', 'newdir'),
559
('change', 'added', 'newfile'),
560
('renamed', 'renamed', 'dirtorename', 'renameddir'),
561
('renamed', 'renamed', 'filetorename', 'renamedfile'),
562
('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
563
('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
564
('deleted', 'dirtoremove'),
565
('deleted', 'filetoremove'),
569
def test_commit_removals_respects_filespec(self):
570
"""Commit respects the specified_files for removals."""
571
tree = self.make_branch_and_tree('.')
572
self.build_tree(['a', 'b'])
574
tree.commit('added a, b')
575
tree.remove(['a', 'b'])
576
tree.commit('removed a', specific_files='a')
577
basis = tree.basis_tree()
580
self.assertIs(None, basis.path2id('a'))
581
self.assertFalse(basis.path2id('b') is None)
585
def test_commit_saves_1ms_timestamp(self):
586
"""Passing in a timestamp is saved with 1ms resolution"""
587
tree = self.make_branch_and_tree('.')
588
self.build_tree(['a'])
590
tree.commit('added a', timestamp=1153248633.4186721, timezone=0,
593
rev = tree.branch.repository.get_revision('a1')
594
self.assertEqual(1153248633.419, rev.timestamp)
596
def test_commit_has_1ms_resolution(self):
597
"""Allowing commit to generate the timestamp also has 1ms resolution"""
598
tree = self.make_branch_and_tree('.')
599
self.build_tree(['a'])
601
tree.commit('added a', rev_id='a1')
603
rev = tree.branch.repository.get_revision('a1')
604
timestamp = rev.timestamp
605
timestamp_1ms = round(timestamp, 3)
606
self.assertEqual(timestamp_1ms, timestamp)
608
def assertBasisTreeKind(self, kind, tree, file_id):
609
basis = tree.basis_tree()
612
self.assertEqual(kind, basis.kind(file_id))
616
def test_commit_kind_changes(self):
617
self.requireFeature(SymlinkFeature)
618
tree = self.make_branch_and_tree('.')
619
os.symlink('target', 'name')
620
tree.add('name', 'a-file-id')
621
tree.commit('Added a symlink')
622
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
625
self.build_tree(['name'])
626
tree.commit('Changed symlink to file')
627
self.assertBasisTreeKind('file', tree, 'a-file-id')
630
os.symlink('target', 'name')
631
tree.commit('file to symlink')
632
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
636
tree.commit('symlink to directory')
637
self.assertBasisTreeKind('directory', tree, 'a-file-id')
640
os.symlink('target', 'name')
641
tree.commit('directory to symlink')
642
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
644
# prepare for directory <-> file tests
647
tree.commit('symlink to directory')
648
self.assertBasisTreeKind('directory', tree, 'a-file-id')
651
self.build_tree(['name'])
652
tree.commit('Changed directory to file')
653
self.assertBasisTreeKind('file', tree, 'a-file-id')
657
tree.commit('file to directory')
658
self.assertBasisTreeKind('directory', tree, 'a-file-id')
660
def test_commit_unversioned_specified(self):
661
"""Commit should raise if specified files isn't in basis or worktree"""
662
tree = self.make_branch_and_tree('.')
663
self.assertRaises(errors.PathsNotVersionedError, tree.commit,
664
'message', specific_files=['bogus'])
666
class Callback(object):
668
def __init__(self, message, testcase):
670
self.message = message
671
self.testcase = testcase
673
def __call__(self, commit_obj):
675
self.testcase.assertTrue(isinstance(commit_obj, Commit))
678
def test_commit_callback(self):
679
"""Commit should invoke a callback to get the message"""
681
tree = self.make_branch_and_tree('.')
685
self.assertTrue(isinstance(e, BzrError))
686
self.assertEqual('The message or message_callback keyword'
687
' parameter is required for commit().', str(e))
689
self.fail('exception not raised')
690
cb = self.Callback(u'commit 1', self)
691
tree.commit(message_callback=cb)
692
self.assertTrue(cb.called)
693
repository = tree.branch.repository
694
message = repository.get_revision(tree.last_revision()).message
695
self.assertEqual('commit 1', message)
697
def test_no_callback_pointless(self):
698
"""Callback should not be invoked for pointless commit"""
699
tree = self.make_branch_and_tree('.')
700
cb = self.Callback(u'commit 2', self)
701
self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
702
allow_pointless=False)
703
self.assertFalse(cb.called)
705
def test_no_callback_netfailure(self):
706
"""Callback should not be invoked if connectivity fails"""
707
tree = self.make_branch_and_tree('.')
708
cb = self.Callback(u'commit 2', self)
709
repository = tree.branch.repository
710
# simulate network failure
711
def raise_(self, arg, arg2):
712
raise errors.NoSuchFile('foo')
713
repository.add_inventory = raise_
714
self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
715
self.assertFalse(cb.called)
717
def test_selected_file_merge_commit(self):
718
"""Ensure the correct error is raised"""
719
tree = self.make_branch_and_tree('foo')
720
# pending merge would turn into a left parent
721
tree.commit('commit 1')
722
tree.add_parent_tree_id('example')
723
self.build_tree(['foo/bar', 'foo/baz'])
724
tree.add(['bar', 'baz'])
725
err = self.assertRaises(errors.CannotCommitSelectedFileMerge,
726
tree.commit, 'commit 2', specific_files=['bar', 'baz'])
727
self.assertEqual(['bar', 'baz'], err.files)
728
self.assertEqual('Selected-file commit of merges is not supported'
729
' yet: files bar, baz', str(err))
731
def test_commit_ordering(self):
732
"""Test of corner-case commit ordering error"""
733
tree = self.make_branch_and_tree('.')
734
self.build_tree(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
735
tree.add(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
737
self.build_tree(['a/c/d/'])
739
tree.rename_one('a/z/x', 'a/c/d/x')
740
tree.commit('test', specific_files=['a/z/y'])
742
def test_commit_no_author(self):
743
"""The default kwarg author in MutableTree.commit should not add
744
the 'author' revision property.
746
tree = self.make_branch_and_tree('foo')
747
rev_id = tree.commit('commit 1')
748
rev = tree.branch.repository.get_revision(rev_id)
749
self.assertFalse('author' in rev.properties)
750
self.assertFalse('authors' in rev.properties)
752
def test_commit_author(self):
753
"""Passing a non-empty author kwarg to MutableTree.commit should add
754
the 'author' revision property.
756
tree = self.make_branch_and_tree('foo')
757
rev_id = self.callDeprecated(['The parameter author was '
758
'deprecated in version 1.13. Use authors instead'],
759
tree.commit, 'commit 1', author='John Doe <jdoe@example.com>')
760
rev = tree.branch.repository.get_revision(rev_id)
761
self.assertEqual('John Doe <jdoe@example.com>',
762
rev.properties['authors'])
763
self.assertFalse('author' in rev.properties)
765
def test_commit_empty_authors_list(self):
766
"""Passing an empty list to authors shouldn't add the property."""
767
tree = self.make_branch_and_tree('foo')
768
rev_id = tree.commit('commit 1', authors=[])
769
rev = tree.branch.repository.get_revision(rev_id)
770
self.assertFalse('author' in rev.properties)
771
self.assertFalse('authors' in rev.properties)
773
def test_multiple_authors(self):
774
tree = self.make_branch_and_tree('foo')
775
rev_id = tree.commit('commit 1',
776
authors=['John Doe <jdoe@example.com>',
777
'Jane Rey <jrey@example.com>'])
778
rev = tree.branch.repository.get_revision(rev_id)
779
self.assertEqual('John Doe <jdoe@example.com>\n'
780
'Jane Rey <jrey@example.com>', rev.properties['authors'])
781
self.assertFalse('author' in rev.properties)
783
def test_author_and_authors_incompatible(self):
784
tree = self.make_branch_and_tree('foo')
785
self.assertRaises(AssertionError, tree.commit, 'commit 1',
786
authors=['John Doe <jdoe@example.com>',
787
'Jane Rey <jrey@example.com>'],
788
author="Jack Me <jme@example.com>")
790
def test_author_with_newline_rejected(self):
791
tree = self.make_branch_and_tree('foo')
792
self.assertRaises(AssertionError, tree.commit, 'commit 1',
793
authors=['John\nDoe <jdoe@example.com>'])
795
def test_commit_with_checkout_and_branch_sharing_repo(self):
796
repo = self.make_repository('repo', shared=True)
797
# make_branch_and_tree ignores shared repos
798
branch = bzrdir.BzrDir.create_branch_convenience('repo/branch')
799
tree2 = branch.create_checkout('repo/tree2')
800
tree2.commit('message', rev_id='rev1')
801
self.assertTrue(tree2.branch.repository.has_revision('rev1'))