387
411
bound = master.sprout('bound')
388
412
wt = bound.open_workingtree()
389
413
wt.branch.set_bound_location(os.path.realpath('master'))
415
orig_default = lockdir._DEFAULT_TIMEOUT_SECONDS
390
416
master_branch.lock_write()
418
lockdir._DEFAULT_TIMEOUT_SECONDS = 1
392
419
self.assertRaises(LockContention, wt.commit, 'silly')
421
lockdir._DEFAULT_TIMEOUT_SECONDS = orig_default
394
422
master_branch.unlock()
424
def test_commit_bound_merge(self):
425
# see bug #43959; commit of a merge in a bound branch fails to push
426
# the new commit into the master
427
master_branch = self.make_branch('master')
428
bound_tree = self.make_branch_and_tree('bound')
429
bound_tree.branch.bind(master_branch)
431
self.build_tree_contents([('bound/content_file', 'initial contents\n')])
432
bound_tree.add(['content_file'])
433
bound_tree.commit(message='woo!')
435
other_bzrdir = master_branch.bzrdir.sprout('other')
436
other_tree = other_bzrdir.open_workingtree()
438
# do a commit to the the other branch changing the content file so
439
# that our commit after merging will have a merged revision in the
440
# content file history.
441
self.build_tree_contents([('other/content_file', 'change in other\n')])
442
other_tree.commit('change in other')
444
# do a merge into the bound branch from other, and then change the
445
# content file locally to force a new revision (rather than using the
446
# revision from other). This forces extra processing in commit.
447
bound_tree.merge_from_branch(other_tree.branch)
448
self.build_tree_contents([('bound/content_file', 'change in bound\n')])
450
# before #34959 was fixed, this failed with 'revision not present in
451
# weave' when trying to implicitly push from the bound branch to the master
452
bound_tree.commit(message='commit of merge in bound tree')
454
def test_commit_reporting_after_merge(self):
455
# when doing a commit of a merge, the reporter needs to still
456
# be called for each item that is added/removed/deleted.
457
this_tree = self.make_branch_and_tree('this')
458
# we need a bunch of files and dirs, to perform one action on each.
461
'this/dirtoreparent/',
464
'this/filetoreparent',
481
this_tree.commit('create_files')
482
other_dir = this_tree.bzrdir.sprout('other')
483
other_tree = other_dir.open_workingtree()
484
other_tree.lock_write()
485
# perform the needed actions on the files and dirs.
487
other_tree.rename_one('dirtorename', 'renameddir')
488
other_tree.rename_one('dirtoreparent', 'renameddir/reparenteddir')
489
other_tree.rename_one('filetorename', 'renamedfile')
490
other_tree.rename_one('filetoreparent', 'renameddir/reparentedfile')
491
other_tree.remove(['dirtoremove', 'filetoremove'])
492
self.build_tree_contents([
494
('other/filetomodify', 'new content'),
495
('other/newfile', 'new file content')])
496
other_tree.add('newfile')
497
other_tree.add('newdir/')
498
other_tree.commit('modify all sample files and dirs.')
501
this_tree.merge_from_branch(other_tree.branch)
502
reporter = CapturingReporter()
503
this_tree.commit('do the commit', reporter=reporter)
505
('change', 'unchanged', ''),
506
('change', 'unchanged', 'dirtoleave'),
507
('change', 'unchanged', 'filetoleave'),
508
('change', 'modified', 'filetomodify'),
509
('change', 'added', 'newdir'),
510
('change', 'added', 'newfile'),
511
('renamed', 'renamed', 'dirtorename', 'renameddir'),
512
('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
513
('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
514
('renamed', 'renamed', 'filetorename', 'renamedfile'),
515
('deleted', 'dirtoremove'),
516
('deleted', 'filetoremove'),
520
def test_commit_removals_respects_filespec(self):
521
"""Commit respects the specified_files for removals."""
522
tree = self.make_branch_and_tree('.')
523
self.build_tree(['a', 'b'])
525
tree.commit('added a, b')
526
tree.remove(['a', 'b'])
527
tree.commit('removed a', specific_files='a')
528
basis = tree.basis_tree().inventory
529
self.assertIs(None, basis.path2id('a'))
530
self.assertFalse(basis.path2id('b') is None)
532
def test_commit_saves_1ms_timestamp(self):
533
"""Passing in a timestamp is saved with 1ms resolution"""
534
tree = self.make_branch_and_tree('.')
535
self.build_tree(['a'])
537
tree.commit('added a', timestamp=1153248633.4186721, timezone=0,
540
rev = tree.branch.repository.get_revision('a1')
541
self.assertEqual(1153248633.419, rev.timestamp)
543
def test_commit_has_1ms_resolution(self):
544
"""Allowing commit to generate the timestamp also has 1ms resolution"""
545
tree = self.make_branch_and_tree('.')
546
self.build_tree(['a'])
548
tree.commit('added a', rev_id='a1')
550
rev = tree.branch.repository.get_revision('a1')
551
timestamp = rev.timestamp
552
timestamp_1ms = round(timestamp, 3)
553
self.assertEqual(timestamp_1ms, timestamp)
555
def test_commit_unversioned_specified(self):
556
"""Commit should raise if specified files isn't in basis or worktree"""
557
tree = self.make_branch_and_tree('.')
558
self.assertRaises(errors.PathsNotVersionedError, tree.commit,
559
'message', specific_files=['bogus'])
561
class Callback(object):
563
def __init__(self, message, testcase):
565
self.message = message
566
self.testcase = testcase
568
def __call__(self, commit_obj):
570
self.testcase.assertTrue(isinstance(commit_obj, Commit))
573
def test_commit_callback(self):
574
"""Commit should invoke a callback to get the message"""
576
tree = self.make_branch_and_tree('.')
580
self.assertTrue(isinstance(e, BzrError))
581
self.assertEqual('The message or message_callback keyword'
582
' parameter is required for commit().', str(e))
584
self.fail('exception not raised')
585
cb = self.Callback(u'commit 1', self)
586
tree.commit(message_callback=cb)
587
self.assertTrue(cb.called)
588
repository = tree.branch.repository
589
message = repository.get_revision(tree.last_revision()).message
590
self.assertEqual('commit 1', message)
592
def test_no_callback_pointless(self):
593
"""Callback should not be invoked for pointless commit"""
594
tree = self.make_branch_and_tree('.')
595
cb = self.Callback(u'commit 2', self)
596
self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
597
allow_pointless=False)
598
self.assertFalse(cb.called)
600
def test_no_callback_netfailure(self):
601
"""Callback should not be invoked if connectivity fails"""
602
tree = self.make_branch_and_tree('.')
603
cb = self.Callback(u'commit 2', self)
604
repository = tree.branch.repository
605
# simulate network failure
606
def raise_(self, arg, arg2):
607
raise errors.NoSuchFile('foo')
608
repository.add_inventory = raise_
609
self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
610
self.assertFalse(cb.called)