58
59
brz: ERROR: No changes to commit.\
59
60
Please 'brz add' the files you want to commit,\
60
61
or use --unchanged to force an empty commit.
61
""", flags=doctest.ELLIPSIS|doctest.REPORT_UDIFF))
62
""", flags=doctest.ELLIPSIS | doctest.REPORT_UDIFF))
63
64
def test_commit_success(self):
64
65
"""Successful commit should not leave behind a bzr-commit-* file"""
79
80
def test_commit_lossy_foreign(self):
80
81
test_foreign.register_dummy_foreign_for_test(self)
81
82
self.make_branch_and_tree('.',
82
format=test_foreign.DummyForeignVcsDirFormat())
83
format=test_foreign.DummyForeignVcsDirFormat())
83
84
self.run_bzr('commit --lossy --unchanged -m message')
84
85
output = self.run_bzr('revision-info')[0]
85
86
self.assertTrue(output.startswith('1 dummy-'))
92
93
self.run_bzr(['commit', '-m', 'first commit', 'a'])
94
95
b_tree = a_tree.controldir.sprout('b').open_workingtree()
95
self.build_tree_contents([('b/a_file', 'changes in b')])
96
self.build_tree_contents([('b/a_file', b'changes in b')])
96
97
self.run_bzr(['commit', '-m', 'first commit in b', 'b'])
98
self.build_tree_contents([('a/a_file', 'new contents')])
99
self.build_tree_contents([('a/a_file', b'new contents')])
99
100
self.run_bzr(['commit', '-m', 'change in a', 'a'])
101
102
b_tree.merge_from_branch(a_tree.branch)
126
127
def test_verbose_commit_modified(self):
127
128
# Verbose commit of modified file should say so
128
129
wt = self.prepare_simple_history()
129
self.build_tree_contents([('hello.txt', 'new contents')])
130
self.build_tree_contents([('hello.txt', b'new contents')])
130
131
out, err = self.run_bzr('commit -m modified')
131
132
self.assertEqual('', out)
132
133
self.assertContainsRe(err, '^Committing to: .*\n'
139
140
self.requireFeature(features.UnicodeFilenameFeature)
140
141
file_name = u'\N{euro sign}'
141
142
self.run_bzr(['init'])
142
with open(file_name, 'w') as f: f.write('hello world')
143
with open(file_name, 'w') as f:
144
f.write('hello world')
143
145
self.run_bzr(['add'])
144
146
out, err = self.run_bzr(['commit', '-m', file_name])
145
reflags = re.MULTILINE|re.DOTALL|re.UNICODE
147
reflags = re.MULTILINE | re.DOTALL | re.UNICODE
146
148
te = osutils.get_terminal_encoding()
147
self.assertContainsRe(err.decode(te),
148
u'The commit message is a file name:',
149
self.assertContainsRe(err,
150
u'The commit message is a file name:',
151
153
# Run same test with a filename that causes encode
152
154
# error for the terminal encoding. We do this
158
160
osutils.get_terminal_encoding = lambda trace=None: 'ascii'
159
161
file_name = u'foo\u1234'
160
with open(file_name, 'w') as f: f.write('hello world')
162
with open(file_name, 'w') as f:
163
f.write('hello world')
161
164
self.run_bzr(['add'])
162
165
out, err = self.run_bzr(['commit', '-m', file_name])
163
reflags = re.MULTILINE|re.DOTALL|re.UNICODE
166
reflags = re.MULTILINE | re.DOTALL | re.UNICODE
164
167
te = osutils.get_terminal_encoding()
165
self.assertContainsRe(err.decode(te, 'replace'),
166
u'The commit message is a file name:',
168
self.assertContainsRe(err,
169
u'The commit message is a file name:',
169
172
osutils.get_terminal_encoding = default_get_terminal_enc
173
176
tree = self.make_branch_and_tree(".")
174
177
self.build_tree(["f"])
176
out, err = self.run_bzr(["commit", "-m", "Wrong filename", u"\xa7"],
177
encoding="utf-8", retcode=3)
178
self.assertContainsRe(err, "(?m)not versioned: \"\xc2\xa7\"$")
179
out, err = self.run_bzr_raw(["commit", "-m", "Wrong filename", u"\xa7"],
180
encoding="utf-8", retcode=3)
181
self.assertContainsRe(err, b"(?m)not versioned: \"\xc2\xa7\"$")
180
183
def test_non_ascii_file_unversioned_iso_8859_5(self):
181
184
self.requireFeature(features.UnicodeFilenameFeature)
182
185
tree = self.make_branch_and_tree(".")
183
186
self.build_tree(["f"])
185
out, err = self.run_bzr(["commit", "-m", "Wrong filename", u"\xa7"],
186
encoding="iso-8859-5", retcode=3)
187
self.expectFailure("Error messages are always written as UTF-8",
188
self.assertNotContainsString, err, "\xc2\xa7")
189
self.assertContainsRe(err, "(?m)not versioned: \"\xfd\"$")
188
out, err = self.run_bzr_raw(["commit", "-m", "Wrong filename", u"\xa7"],
189
encoding="iso-8859-5", retcode=3)
190
self.assertNotContainsString(err, b"\xc2\xa7")
191
self.assertContainsRe(err, b"(?m)not versioned: \"\xfd\"$")
191
193
def test_warn_about_forgotten_commit_message(self):
192
194
"""Test that the lack of -m parameter is caught"""
309
311
this_tree.commit('create_files')
310
312
other_dir = this_tree.controldir.sprout('other')
311
313
other_tree = other_dir.open_workingtree()
312
other_tree.lock_write()
313
# perform the needed actions on the files and dirs.
314
with other_tree.lock_write():
315
# perform the needed actions on the files and dirs.
315
316
other_tree.rename_one('dirtorename', 'renameddir')
316
317
other_tree.rename_one('dirtoreparent', 'renameddir/reparenteddir')
317
318
other_tree.rename_one('filetorename', 'renamedfile')
320
321
other_tree.remove(['dirtoremove', 'filetoremove'])
321
322
self.build_tree_contents([
322
323
('other/newdir/',),
323
('other/filetomodify', 'new content'),
324
('other/newfile', 'new file content')])
324
('other/filetomodify', b'new content'),
325
('other/newfile', b'new file content')])
325
326
other_tree.add('newfile')
326
327
other_tree.add('newdir/')
327
328
other_tree.commit('modify all sample files and dirs.')
330
329
this_tree.merge_from_branch(other_tree.branch)
331
330
out, err = self.run_bzr('commit -m added', working_dir='this')
332
331
self.assertEqual('', out)
348
347
def test_empty_commit_message(self):
349
348
tree = self.make_branch_and_tree('.')
350
self.build_tree_contents([('foo.c', 'int main() {}')])
349
self.build_tree_contents([('foo.c', b'int main() {}')])
351
350
tree.add('foo.c')
352
351
self.run_bzr('commit -m ""')
357
356
outer_tree = self.make_branch_and_tree('.')
358
357
inner_tree = self.make_branch_and_tree('branch')
359
358
self.build_tree_contents([
360
('branch/foo.c', 'int main() {}'),
361
('branch/bar.c', 'int main() {}')])
359
('branch/foo.c', b'int main() {}'),
360
('branch/bar.c', b'int main() {}')])
362
361
inner_tree.add(['foo.c', 'bar.c'])
363
362
# can't commit files in different trees; sane error
364
363
self.run_bzr('commit -m newstuff branch/foo.c .', retcode=3)
367
366
# can commit to branch - records bar.c
368
367
self.run_bzr('commit -m newstuff branch')
369
368
# No changes left
370
self.run_bzr_error(["No changes to commit"], 'commit -m newstuff branch')
369
self.run_bzr_error(["No changes to commit"],
370
'commit -m newstuff branch')
372
372
def test_out_of_date_tree_commit(self):
373
373
# check we get an error code and a clear message committing with an out
380
380
# now commit to the checkout should emit
381
381
# ERROR: Out of date with the branch, 'brz update' is suggested
382
382
output = self.run_bzr('commit --unchanged -m checkout_message '
383
'checkout', retcode=3)
383
'checkout', retcode=3)
384
384
self.assertEqual(output,
386
386
"brz: ERROR: Working tree is out of date, please "
403
403
trunk = self.make_branch_and_tree('trunk')
405
405
u1 = trunk.branch.create_checkout('u1')
406
self.build_tree_contents([('u1/hosts', 'initial contents\n')])
406
self.build_tree_contents([('u1/hosts', b'initial contents\n')])
408
408
self.run_bzr('commit -m add-hosts u1')
410
410
u2 = trunk.branch.create_checkout('u2')
411
self.build_tree_contents([('u2/hosts', 'altered in u2\n')])
411
self.build_tree_contents([('u2/hosts', b'altered in u2\n')])
412
412
self.run_bzr('commit -m checkin-from-u2 u2')
414
414
# make an offline commits
415
self.build_tree_contents([('u1/hosts', 'first offline change in u1\n')])
415
self.build_tree_contents(
416
[('u1/hosts', b'first offline change in u1\n')])
416
417
self.run_bzr('commit -m checkin-offline --local u1')
418
419
# now try to pull in online work from u2, and then commit our offline
419
420
# work as a merge
420
421
# retcode 1 as we expect a text conflict
421
422
self.run_bzr('update u1', retcode=1)
422
self.assertFileEqual('''\
423
self.assertFileEqual(b'''\
424
425
first offline change in u1
432
433
# add a text change here to represent resolving the merge conflicts in
433
434
# favour of a new version of the file not identical to either the u1
434
435
# version or the u2 version.
435
self.build_tree_contents([('u1/hosts', 'merge resolution\n')])
436
self.build_tree_contents([('u1/hosts', b'merge resolution\n')])
436
437
self.run_bzr('commit -m checkin-merge-of-the-offline-work-from-u1 u1')
438
439
def test_commit_exclude_excludes_modified_files(self):
538
539
tree = self.make_branch_and_tree('tree')
539
540
self.build_tree(['tree/hello.txt'])
540
541
tree.add('hello.txt')
541
output, err = self.run_bzr(
542
output, err = self.run_bzr_raw(
542
543
['commit', '-m', 'hello',
543
544
u'--fixes=generic:\u20ac', 'tree/hello.txt'],
544
545
encoding='utf-8', retcode=3)
545
546
self.assertEqual(b'', output)
546
547
self.assertContainsRe(err,
547
b'brz: ERROR: Unrecognized bug generic:\xe2\x82\xac\\. Commit refused.\n')
548
b'brz: ERROR: Unrecognized bug generic:\xe2\x82\xac\\. Commit refused.\n')
549
550
def test_no_bugs_no_properties(self):
550
551
"""If no bugs are fixed, the bugs property is not set.
562
563
del properties['branch-nick']
563
564
self.assertFalse('bugs' in properties)
566
def test_bugs_sets_property(self):
567
"""commit --bugs=lp:234 sets the lp:234 revprop to 'related'."""
568
tree = self.make_branch_and_tree('tree')
569
self.build_tree(['tree/hello.txt'])
570
tree.add('hello.txt')
571
self.run_bzr('commit -m hello --bugs=lp:234 tree/hello.txt')
573
# Get the revision properties, ignoring the branch-nick property, which
574
# we don't care about for this test.
575
last_rev = tree.branch.repository.get_revision(tree.last_revision())
576
properties = dict(last_rev.properties)
577
del properties[u'branch-nick']
579
self.assertEqual({u'bugs': 'https://launchpad.net/bugs/234 related'},
565
582
def test_fixes_bug_sets_property(self):
566
583
"""commit --fixes=lp:234 sets the lp:234 revprop to 'fixed'."""
567
584
tree = self.make_branch_and_tree('tree')
573
590
# we don't care about for this test.
574
591
last_rev = tree.branch.repository.get_revision(tree.last_revision())
575
592
properties = dict(last_rev.properties)
576
del properties['branch-nick']
593
del properties[u'branch-nick']
578
self.assertEqual({'bugs': 'https://launchpad.net/bugs/234 fixed'},
595
self.assertEqual({u'bugs': 'https://launchpad.net/bugs/234 fixed'},
581
598
def test_fixes_multiple_bugs_sets_properties(self):
593
610
del properties['branch-nick']
595
612
self.assertEqual(
596
{'bugs': 'https://launchpad.net/bugs/123 fixed\n'
597
'https://launchpad.net/bugs/235 fixed'},
613
{u'bugs': 'https://launchpad.net/bugs/123 fixed\n'
614
'https://launchpad.net/bugs/235 fixed'},
600
617
def test_fixes_bug_with_alternate_trackers(self):
606
623
'trac_twisted_url', 'http://twistedmatrix.com/trac')
607
624
self.build_tree(['tree/hello.txt'])
608
625
tree.add('hello.txt')
609
self.run_bzr('commit -m hello --fixes=lp:123 --fixes=twisted:235 tree/')
627
'commit -m hello --fixes=lp:123 --fixes=twisted:235 tree/')
611
629
# Get the revision properties, ignoring the branch-nick property, which
612
630
# we don't care about for this test.
635
653
tree.add('hello.txt')
636
654
self.run_bzr_error(
637
655
["brz: ERROR: No tracker specified for bug 123. Use the form "
638
"'tracker:id' or specify a default bug tracker using the "
639
"`bugtracker` option.\n"
640
"See \"brz help bugs\" for more information on this feature. "
656
"'tracker:id' or specify a default bug tracker using the "
657
"`bugtracker` option.\n"
658
"See \"brz help bugs\" for more information on this feature. "
642
660
'commit -m add-b --fixes=123',
643
661
working_dir='tree')
644
662
tree.branch.get_config_stack().set("bugtracker", "lp")
675
693
tree = self.make_branch_and_tree('tree')
676
694
self.build_tree(['tree/hello.txt'])
677
695
tree.add('hello.txt')
678
self.run_bzr( 'commit -m hello tree/hello.txt')
696
self.run_bzr('commit -m hello tree/hello.txt')
679
697
last_rev = tree.branch.repository.get_revision(tree.last_revision())
680
698
properties = last_rev.properties
681
699
self.assertFalse('author' in properties)
689
707
tree.add('hello.txt')
690
708
self.run_bzr(["commit", '-m', 'hello',
691
709
'--author', u'John D\xf6 <jdoe@example.com>',
693
711
last_rev = tree.branch.repository.get_revision(tree.last_revision())
694
712
properties = last_rev.properties
695
self.assertEqual(u'John D\xf6 <jdoe@example.com>', properties['authors'])
713
self.assertEqual(u'John D\xf6 <jdoe@example.com>',
714
properties['authors'])
697
716
def test_author_no_email(self):
698
717
"""Author's name without an email address is allowed, too."""
721
740
self.build_tree(['tree/hello.txt'])
722
741
tree.add('hello.txt')
723
742
out, err = self.run_bzr("commit -m hello "
724
"--commit-time='2009-10-10 08:00:00 +0100' tree/hello.txt")
743
"--commit-time='2009-10-10 08:00:00 +0100' tree/hello.txt")
725
744
last_rev = tree.branch.repository.get_revision(tree.last_revision())
726
745
self.assertEqual(
727
746
'Sat 2009-10-10 08:00:00 +0100',
728
747
osutils.format_date(last_rev.timestamp, last_rev.timezone))
730
749
def test_commit_time_bad_time(self):
731
750
tree = self.make_branch_and_tree('tree')
732
751
self.build_tree(['tree/hello.txt'])
733
752
tree.add('hello.txt')
734
753
out, err = self.run_bzr("commit -m hello "
735
"--commit-time='NOT A TIME' tree/hello.txt", retcode=3)
754
"--commit-time='NOT A TIME' tree/hello.txt", retcode=3)
736
755
self.assertStartsWith(
737
756
err, "brz: ERROR: Could not parse --commit-time:")
741
760
self.build_tree(['tree/hello.txt'])
742
761
tree.add('hello.txt')
743
762
out, err = self.run_bzr("commit -m hello "
744
"--commit-time='2009-10-10 08:00:00' tree/hello.txt", retcode=3)
763
"--commit-time='2009-10-10 08:00:00' tree/hello.txt", retcode=3)
745
764
self.assertStartsWith(
746
765
err, "brz: ERROR: Could not parse --commit-time:")
747
766
# Test that it is actually checking and does not simply crash with
759
778
# then during partial commit we have error
760
779
# parent_id {dir-XXX} not in inventory
761
780
t.rename_one('dir/a', 'a')
762
self.build_tree_contents([('test', 'changes in test')])
781
self.build_tree_contents([('test', b'changes in test')])
764
783
out, err = self.run_bzr('commit test -m "partial commit"')
765
784
self.assertEqual('', out)
774
793
self.get_readonly_transport('master')).open_branch()
775
794
master.create_checkout('checkout')
776
795
out, err = self.run_bzr(['commit', '--unchanged', '-mfoo', 'checkout'],
778
797
self.assertContainsRe(err,
779
r'^brz: ERROR: Cannot lock.*readonly transport')
798
r'^brz: ERROR: Cannot lock.*readonly transport')
781
800
def setup_editor(self):
782
801
# Test that commit template hooks work
783
802
if sys.platform == "win32":
784
f = file('fed.bat', 'w')
785
f.write('@rem dummy fed')
803
with open('fed.bat', 'w') as f:
804
f.write('@rem dummy fed')
787
805
self.overrideEnv('BRZ_EDITOR', "fed.bat")
789
f = file('fed.sh', 'wb')
790
f.write('#!/bin/sh\n')
807
with open('fed.sh', 'wb') as f:
808
f.write(b'#!/bin/sh\n')
792
809
os.chmod('fed.sh', 0o755)
793
810
self.overrideEnv('BRZ_EDITOR', "./fed.sh")
795
812
def setup_commit_with_template(self):
796
813
self.setup_editor()
797
814
msgeditor.hooks.install_named_hook("commit_message_template",
798
lambda commit_obj, msg: "save me some typing\n", None)
815
lambda commit_obj, msg: "save me some typing\n", None)
799
816
tree = self.make_branch_and_tree('tree')
800
817
self.build_tree(['tree/hello.txt'])
801
818
tree.add('hello.txt')
807
824
self.build_tree(['tree/hello.txt'])
808
825
tree.add('hello.txt')
809
826
out, err = self.run_bzr("commit tree/hello.txt", retcode=3,
811
828
self.assertContainsRe(err,
812
"brz: ERROR: Empty commit message specified")
829
"brz: ERROR: Empty commit message specified")
814
831
def test_commit_hook_template_accepted(self):
815
832
tree = self.setup_commit_with_template()
821
838
tree = self.setup_commit_with_template()
822
839
expected = tree.last_revision()
823
840
out, err = self.run_bzr_error(["Empty commit message specified."
824
" Please specify a commit message with either"
825
" --message or --file or leave a blank message"
826
" with --message \"\"."],
827
"commit tree/hello.txt", stdin="n\n")
841
" Please specify a commit message with either"
842
" --message or --file or leave a blank message"
843
" with --message \"\"."],
844
"commit tree/hello.txt", stdin="n\n")
828
845
self.assertEqual(expected, tree.last_revision())
830
847
def test_set_commit_message(self):
831
848
msgeditor.hooks.install_named_hook("set_commit_message",
832
lambda commit_obj, msg: "save me some typing\n", None)
849
lambda commit_obj, msg: "save me some typing\n", None)
833
850
tree = self.make_branch_and_tree('tree')
834
851
self.build_tree(['tree/hello.txt'])
835
852
tree.add('hello.txt')
844
861
with open('foo/foo.txt', 'w') as f:
846
863
self.run_bzr(['add'], working_dir='foo')
847
self.overrideEnv('EMAIL', None)
848
self.overrideEnv('BRZ_EMAIL', None)
849
# Also, make sure that it's not inferred from mailname.
850
self.overrideAttr(config, '_auto_user_id',
851
lambda: (None, None))
864
override_whoami(self)
852
865
self.run_bzr_error(
853
866
['Unable to determine your name'],
854
867
['commit', '-m', 'initial'], working_dir='foo')
859
872
self.run_bzr(['init', 'test_branch'])
860
873
self.run_bzr(['checkout', 'test_branch', 'test_checkout'])
861
self.run_bzr(['bind', '.'], working_dir='test_checkout') # bind to self
875
self.run_bzr(['bind', '.'], working_dir='test_checkout')
862
876
with open('test_checkout/foo.txt', 'w') as f:
864
878
self.run_bzr(['add'], working_dir='test_checkout')
890
904
for count in range(9):
891
905
t.commit(message='commit %d' % count)
892
906
out, err = self.run_bzr(['checkout', '--lightweight', self.get_url('from'),
894
908
self.reset_smart_call_log()
895
909
self.build_tree(['target/afile'])
896
910
self.run_bzr(['add', 'target/afile'])
903
917
self.assertLength(211, self.hpss_calls)
904
918
self.assertLength(2, self.hpss_connections)
905
919
self.expectFailure("commit still uses VFS calls",
906
self.assertThat, self.hpss_calls, ContainsNoVfsCalls)
920
self.assertThat, self.hpss_calls, ContainsNoVfsCalls)