1
# Copyright (C) 2005, 2006 by Canonical Ltd
1
# Copyright (C) 2006-2010 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
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
18
18
"""Tests for the commit CLI of bzr."""
20
from cStringIO import StringIO
26
from bzrlib.branch import Branch
27
import bzrlib.bzrdir as bzrdir
28
from bzrlib.errors import BzrCommandError
29
from bzrlib.tests.blackbox import ExternalBase
30
from bzrlib.workingtree import WorkingTree
33
class TestCommit(ExternalBase):
32
from bzrlib.bzrdir import BzrDir
33
from bzrlib.tests import (
37
from bzrlib.tests import TestCaseWithTransport
40
class TestCommit(TestCaseWithTransport):
35
42
def test_05_empty_commit(self):
36
43
"""Commit of tree with no versioned files should fail"""
37
44
# If forced, it should succeed, but this is not tested here.
45
self.make_branch_and_tree('.')
39
46
self.build_tree(['hello.txt'])
40
self.runbzr("commit -m empty", retcode=3)
47
out,err = self.run_bzr('commit -m empty', retcode=3)
48
self.assertEqual('', out)
49
self.assertContainsRe(err, 'bzr: ERROR: No changes to commit\.'
50
' Use --unchanged to commit anyhow.\n')
52
def test_commit_success(self):
53
"""Successful commit should not leave behind a bzr-commit-* file"""
54
self.make_branch_and_tree('.')
55
self.run_bzr('commit --unchanged -m message')
56
self.assertEqual('', self.run_bzr('unknowns')[0])
58
# same for unicode messages
59
self.run_bzr(["commit", "--unchanged", "-m", u'foo\xb5'])
60
self.assertEqual('', self.run_bzr('unknowns')[0])
62
def test_commit_with_path(self):
63
"""Commit tree with path of root specified"""
64
a_tree = self.make_branch_and_tree('a')
65
self.build_tree(['a/a_file'])
67
self.run_bzr(['commit', '-m', 'first commit', 'a'])
69
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
70
self.build_tree_contents([('b/a_file', 'changes in b')])
71
self.run_bzr(['commit', '-m', 'first commit in b', 'b'])
73
self.build_tree_contents([('a/a_file', 'new contents')])
74
self.run_bzr(['commit', '-m', 'change in a', 'a'])
76
b_tree.merge_from_branch(a_tree.branch)
77
self.assertEqual(len(b_tree.conflicts()), 1)
78
self.run_bzr('resolved b/a_file')
79
self.run_bzr(['commit', '-m', 'merge into b', 'b'])
42
82
def test_10_verbose_commit(self):
43
83
"""Add one file and examine verbose commit output"""
84
tree = self.make_branch_and_tree('.')
45
85
self.build_tree(['hello.txt'])
46
self.runbzr("add hello.txt")
47
out,err = self.run_bzr("commit", "-m", "added")
48
self.assertEqual('', out)
49
self.assertEqual('added hello.txt\n'
50
'Committed revision 1.\n',
53
def test_15_verbose_commit_with_unknown(self):
87
out,err = self.run_bzr('commit -m added')
88
self.assertEqual('', out)
89
self.assertContainsRe(err, '^Committing to: .*\n'
91
'Committed revision 1.\n$',)
93
def prepare_simple_history(self):
94
"""Prepare and return a working tree with one commit of one file"""
95
# Commit with modified file should say so
96
wt = BzrDir.create_standalone_workingtree('.')
97
self.build_tree(['hello.txt', 'extra.txt'])
99
wt.commit(message='added')
102
def test_verbose_commit_modified(self):
103
# Verbose commit of modified file should say so
104
wt = self.prepare_simple_history()
105
self.build_tree_contents([('hello.txt', 'new contents')])
106
out, err = self.run_bzr('commit -m modified')
107
self.assertEqual('', out)
108
self.assertContainsRe(err, '^Committing to: .*\n'
109
'modified hello\.txt\n'
110
'Committed revision 2\.\n$')
112
def test_unicode_commit_message_is_filename(self):
113
"""Unicode commit message same as a filename (Bug #563646).
115
file_name = u'\N{euro sign}'
116
self.run_bzr(['init'])
117
open(file_name, 'w').write('hello world')
118
self.run_bzr(['add'])
119
out, err = self.run_bzr(['commit', '-m', file_name])
120
reflags = re.MULTILINE|re.DOTALL|re.UNICODE
121
te = osutils.get_terminal_encoding()
122
self.assertContainsRe(err.decode(te),
123
u'The commit message is a file name:',
126
# Run same test with a filename that causes encode
127
# error for the terminal encoding. We do this
128
# by forcing terminal encoding of ascii for
129
# osutils.get_terminal_encoding which is used
130
# by ui.text.show_warning
131
default_get_terminal_enc = osutils.get_terminal_encoding
133
osutils.get_terminal_encoding = lambda trace=None: 'ascii'
134
file_name = u'foo\u1234'
135
open(file_name, 'w').write('hello world')
136
self.run_bzr(['add'])
137
out, err = self.run_bzr(['commit', '-m', file_name])
138
reflags = re.MULTILINE|re.DOTALL|re.UNICODE
139
te = osutils.get_terminal_encoding()
140
self.assertContainsRe(err.decode(te, 'replace'),
141
u'The commit message is a file name:',
144
osutils.get_terminal_encoding = default_get_terminal_enc
146
def test_warn_about_forgotten_commit_message(self):
147
"""Test that the lack of -m parameter is caught"""
148
wt = self.make_branch_and_tree('.')
149
self.build_tree(['one', 'two'])
151
out, err = self.run_bzr('commit -m one two')
152
self.assertContainsRe(err, "The commit message is a file name")
154
def test_verbose_commit_renamed(self):
155
# Verbose commit of renamed file should say so
156
wt = self.prepare_simple_history()
157
wt.rename_one('hello.txt', 'gutentag.txt')
158
out, err = self.run_bzr('commit -m renamed')
159
self.assertEqual('', out)
160
self.assertContainsRe(err, '^Committing to: .*\n'
161
'renamed hello\.txt => gutentag\.txt\n'
162
'Committed revision 2\.$\n')
164
def test_verbose_commit_moved(self):
165
# Verbose commit of file moved to new directory should say so
166
wt = self.prepare_simple_history()
169
wt.rename_one('hello.txt', 'subdir/hello.txt')
170
out, err = self.run_bzr('commit -m renamed')
171
self.assertEqual('', out)
172
self.assertEqual(set([
173
'Committing to: %s/' % osutils.getcwd(),
175
'renamed hello.txt => subdir/hello.txt',
176
'Committed revision 2.',
178
]), set(err.split('\n')))
180
def test_verbose_commit_with_unknown(self):
54
181
"""Unknown files should not be listed by default in verbose output"""
55
182
# Is that really the best policy?
183
wt = BzrDir.create_standalone_workingtree('.')
57
184
self.build_tree(['hello.txt', 'extra.txt'])
58
self.runbzr("add hello.txt")
59
out,err = self.run_bzr("commit", "-m", "added")
185
wt.add(['hello.txt'])
186
out,err = self.run_bzr('commit -m added')
60
187
self.assertEqual('', out)
61
self.assertEqual('added hello.txt\n'
62
'Committed revision 1.\n',
188
self.assertContainsRe(err, '^Committing to: .*\n'
190
'Committed revision 1\.\n$')
65
def test_16_verbose_commit_with_unchanged(self):
192
def test_verbose_commit_with_unchanged(self):
66
193
"""Unchanged files should not be listed by default in verbose output"""
194
tree = self.make_branch_and_tree('.')
68
195
self.build_tree(['hello.txt', 'unchanged.txt'])
69
self.runbzr('add unchanged.txt')
70
self.runbzr('commit -m unchanged unchanged.txt')
71
self.runbzr("add hello.txt")
72
out,err = self.run_bzr("commit", "-m", "added")
73
self.assertEqual('', out)
74
self.assertEqual('added hello.txt\n'
75
'Committed revision 2.\n',
196
tree.add('unchanged.txt')
197
self.run_bzr('commit -m unchanged unchanged.txt')
198
tree.add("hello.txt")
199
out,err = self.run_bzr('commit -m added')
200
self.assertEqual('', out)
201
self.assertContainsRe(err, '^Committing to: .*\n'
203
'Committed revision 2\.$\n')
205
def test_verbose_commit_includes_master_location(self):
206
"""Location of master is displayed when committing to bound branch"""
207
a_tree = self.make_branch_and_tree('a')
208
self.build_tree(['a/b'])
210
a_tree.commit(message='Initial message')
212
b_tree = a_tree.branch.create_checkout('b')
213
expected = "%s/" % (osutils.abspath('a'), )
214
out, err = self.run_bzr('commit -m blah --unchanged', working_dir='b')
215
self.assertEqual(err, 'Committing to: %s\n'
216
'Committed revision 2.\n' % expected)
218
def test_commit_sanitizes_CR_in_message(self):
219
# See bug #433779, basically Emacs likes to pass '\r\n' style line
220
# endings to 'bzr commit -m ""' which breaks because we don't allow
221
# '\r' in commit messages. (Mostly because of issues where XML style
222
# formats arbitrarily strip it out of the data while parsing.)
223
# To make life easier for users, we just always translate '\r\n' =>
224
# '\n'. And '\r' => '\n'.
225
a_tree = self.make_branch_and_tree('a')
226
self.build_tree(['a/b'])
228
self.run_bzr(['commit',
229
'-m', 'a string\r\n\r\nwith mixed\r\rendings\n'],
231
rev_id = a_tree.branch.last_revision()
232
rev = a_tree.branch.repository.get_revision(rev_id)
233
self.assertEqualDiff('a string\n\nwith mixed\n\nendings\n',
236
def test_commit_merge_reports_all_modified_files(self):
237
# the commit command should show all the files that are shown by
238
# bzr diff or bzr status when committing, even when they were not
239
# changed by the user but rather through doing a merge.
240
this_tree = self.make_branch_and_tree('this')
241
# we need a bunch of files and dirs, to perform one action on each.
244
'this/dirtoreparent/',
247
'this/filetoreparent',
264
this_tree.commit('create_files')
265
other_dir = this_tree.bzrdir.sprout('other')
266
other_tree = other_dir.open_workingtree()
267
other_tree.lock_write()
268
# perform the needed actions on the files and dirs.
270
other_tree.rename_one('dirtorename', 'renameddir')
271
other_tree.rename_one('dirtoreparent', 'renameddir/reparenteddir')
272
other_tree.rename_one('filetorename', 'renamedfile')
273
other_tree.rename_one('filetoreparent',
274
'renameddir/reparentedfile')
275
other_tree.remove(['dirtoremove', 'filetoremove'])
276
self.build_tree_contents([
278
('other/filetomodify', 'new content'),
279
('other/newfile', 'new file content')])
280
other_tree.add('newfile')
281
other_tree.add('newdir/')
282
other_tree.commit('modify all sample files and dirs.')
285
this_tree.merge_from_branch(other_tree.branch)
287
out,err = self.run_bzr('commit -m added')
288
self.assertEqual('', out)
289
self.assertEqual(set([
290
'Committing to: %s/' % osutils.getcwd(),
291
'modified filetomodify',
294
'renamed dirtorename => renameddir',
295
'renamed filetorename => renamedfile',
296
'renamed dirtoreparent => renameddir/reparenteddir',
297
'renamed filetoreparent => renameddir/reparentedfile',
298
'deleted dirtoremove',
299
'deleted filetoremove',
300
'Committed revision 2.',
302
]), set(err.split('\n')))
78
304
def test_empty_commit_message(self):
80
file('foo.c', 'wt').write('int main() {}')
81
self.runbzr(['add', 'foo.c'])
82
self.runbzr(["commit", "-m", ""] , retcode=3)
305
tree = self.make_branch_and_tree('.')
306
self.build_tree_contents([('foo.c', 'int main() {}')])
308
self.run_bzr('commit -m ""', retcode=3)
310
def test_unsupported_encoding_commit_message(self):
311
if sys.platform == 'win32':
312
raise tests.TestNotApplicable('Win32 parses arguments directly'
313
' as Unicode, so we can\'t pass invalid non-ascii')
314
tree = self.make_branch_and_tree('.')
315
self.build_tree_contents([('foo.c', 'int main() {}')])
317
# LANG env variable has no effect on Windows
318
# but some characters anyway cannot be represented
319
# in default user encoding
320
char = probe_bad_non_ascii(osutils.get_user_encoding())
322
raise TestSkipped('Cannot find suitable non-ascii character'
323
'for user_encoding (%s)' % osutils.get_user_encoding())
324
out,err = self.run_bzr_subprocess('commit -m "%s"' % char,
326
env_changes={'LANG': 'C'})
327
self.assertContainsRe(err, r'bzrlib.errors.BzrError: Parameter.*is '
328
'unsupported by the current encoding.')
84
330
def test_other_branch_commit(self):
85
331
# this branch is to ensure consistent behaviour, whether we're run
86
332
# inside a branch, or not.
87
os.mkdir('empty_branch')
88
os.chdir('empty_branch')
93
file('foo.c', 'wt').write('int main() {}')
94
file('bar.c', 'wt').write('int main() {}')
96
self.runbzr(['add', 'branch/foo.c'])
97
self.runbzr(['add', 'branch'])
333
outer_tree = self.make_branch_and_tree('.')
334
inner_tree = self.make_branch_and_tree('branch')
335
self.build_tree_contents([
336
('branch/foo.c', 'int main() {}'),
337
('branch/bar.c', 'int main() {}')])
338
inner_tree.add(['foo.c', 'bar.c'])
98
339
# can't commit files in different trees; sane error
99
self.runbzr('commit -m newstuff branch/foo.c .', retcode=3)
100
self.runbzr('commit -m newstuff branch/foo.c')
101
self.runbzr('commit -m newstuff branch')
102
self.runbzr('commit -m newstuff branch', retcode=3)
340
self.run_bzr('commit -m newstuff branch/foo.c .', retcode=3)
341
# can commit to branch - records foo.c only
342
self.run_bzr('commit -m newstuff branch/foo.c')
343
# can commit to branch - records bar.c
344
self.run_bzr('commit -m newstuff branch')
346
self.run_bzr_error(["No changes to commit"], 'commit -m newstuff branch')
104
348
def test_out_of_date_tree_commit(self):
105
349
# check we get an error code and a clear message committing with an out
106
350
# of date checkout
107
self.make_branch_and_tree('branch')
351
tree = self.make_branch_and_tree('branch')
108
352
# make a checkout
109
self.runbzr('checkout --lightweight branch checkout')
353
checkout = tree.branch.create_checkout('checkout', lightweight=True)
110
354
# commit to the original branch to make the checkout out of date
111
self.runbzr('commit --unchanged -m message branch')
355
tree.commit('message branch', allow_pointless=True)
112
356
# now commit to the checkout should emit
113
357
# ERROR: Out of date with the branch, 'bzr update' is suggested
114
output = self.runbzr('commit --unchanged -m checkout_message '
358
output = self.run_bzr('commit --unchanged -m checkout_message '
115
359
'checkout', retcode=3)
116
360
self.assertEqual(output,
118
"bzr: ERROR: Working tree is out of date, please run "
362
"bzr: ERROR: Working tree is out of date, please "
363
"run 'bzr update'.\n"))
121
365
def test_local_commit_unbound(self):
122
366
# a --local commit on an unbound branch is an error
123
367
self.make_branch_and_tree('.')
124
out, err = self.run_bzr('commit', '--local', retcode=3)
368
out, err = self.run_bzr('commit --local', retcode=3)
125
369
self.assertEqualDiff('', out)
126
370
self.assertEqualDiff('bzr: ERROR: Cannot perform local-only commits '
127
371
'on unbound branches.\n', err)
373
def test_commit_a_text_merge_in_a_checkout(self):
374
# checkouts perform multiple actions in a transaction across bond
375
# branches and their master, and have been observed to fail in the
376
# past. This is a user story reported to fail in bug #43959 where
377
# a merge done in a checkout (using the update command) failed to
379
trunk = self.make_branch_and_tree('trunk')
381
u1 = trunk.branch.create_checkout('u1')
382
self.build_tree_contents([('u1/hosts', 'initial contents\n')])
384
self.run_bzr('commit -m add-hosts u1')
386
u2 = trunk.branch.create_checkout('u2')
387
self.build_tree_contents([('u2/hosts', 'altered in u2\n')])
388
self.run_bzr('commit -m checkin-from-u2 u2')
390
# make an offline commits
391
self.build_tree_contents([('u1/hosts', 'first offline change in u1\n')])
392
self.run_bzr('commit -m checkin-offline --local u1')
394
# now try to pull in online work from u2, and then commit our offline
396
# retcode 1 as we expect a text conflict
397
self.run_bzr('update u1', retcode=1)
398
self.assertFileEqual('''\
400
first offline change in u1
407
self.run_bzr('resolved u1/hosts')
408
# add a text change here to represent resolving the merge conflicts in
409
# favour of a new version of the file not identical to either the u1
410
# version or the u2 version.
411
self.build_tree_contents([('u1/hosts', 'merge resolution\n')])
412
self.run_bzr('commit -m checkin-merge-of-the-offline-work-from-u1 u1')
414
def test_commit_exclude_excludes_modified_files(self):
415
"""Commit -x foo should ignore changes to foo."""
416
tree = self.make_branch_and_tree('.')
417
self.build_tree(['a', 'b', 'c'])
418
tree.smart_add(['.'])
419
out, err = self.run_bzr(['commit', '-m', 'test', '-x', 'b'])
420
self.assertFalse('added b' in out)
421
self.assertFalse('added b' in err)
422
# If b was excluded it will still be 'added' in status.
423
out, err = self.run_bzr(['added'])
424
self.assertEqual('b\n', out)
425
self.assertEqual('', err)
427
def test_commit_exclude_twice_uses_both_rules(self):
428
"""Commit -x foo -x bar should ignore changes to foo and bar."""
429
tree = self.make_branch_and_tree('.')
430
self.build_tree(['a', 'b', 'c'])
431
tree.smart_add(['.'])
432
out, err = self.run_bzr(['commit', '-m', 'test', '-x', 'b', '-x', 'c'])
433
self.assertFalse('added b' in out)
434
self.assertFalse('added c' in out)
435
self.assertFalse('added b' in err)
436
self.assertFalse('added c' in err)
437
# If b was excluded it will still be 'added' in status.
438
out, err = self.run_bzr(['added'])
439
self.assertTrue('b\n' in out)
440
self.assertTrue('c\n' in out)
441
self.assertEqual('', err)
443
def test_commit_respects_spec_for_removals(self):
444
"""Commit with a file spec should only commit removals that match"""
445
t = self.make_branch_and_tree('.')
446
self.build_tree(['file-a', 'dir-a/', 'dir-a/file-b'])
447
t.add(['file-a', 'dir-a', 'dir-a/file-b'])
449
t.remove(['file-a', 'dir-a/file-b'])
451
result = self.run_bzr('commit . -m removed-file-b')[1]
452
self.assertNotContainsRe(result, 'file-a')
453
result = self.run_bzr('status')[0]
454
self.assertContainsRe(result, 'removed:\n file-a')
456
def test_strict_commit(self):
457
"""Commit with --strict works if everything is known"""
458
ignores._set_user_ignores([])
459
tree = self.make_branch_and_tree('tree')
460
self.build_tree(['tree/a'])
462
# A simple change should just work
463
self.run_bzr('commit --strict -m adding-a',
466
def test_strict_commit_no_changes(self):
467
"""commit --strict gives "no changes" if there is nothing to commit"""
468
tree = self.make_branch_and_tree('tree')
469
self.build_tree(['tree/a'])
471
tree.commit('adding a')
473
# With no changes, it should just be 'no changes'
474
# Make sure that commit is failing because there is nothing to do
475
self.run_bzr_error(['No changes to commit'],
476
'commit --strict -m no-changes',
479
# But --strict doesn't care if you supply --unchanged
480
self.run_bzr('commit --strict --unchanged -m no-changes',
483
def test_strict_commit_unknown(self):
484
"""commit --strict fails if a file is unknown"""
485
tree = self.make_branch_and_tree('tree')
486
self.build_tree(['tree/a'])
488
tree.commit('adding a')
490
# Add one file so there is a change, but forget the other
491
self.build_tree(['tree/b', 'tree/c'])
493
self.run_bzr_error(['Commit refused because there are unknown files'],
494
'commit --strict -m add-b',
497
# --no-strict overrides --strict
498
self.run_bzr('commit --strict -m add-b --no-strict',
501
def test_fixes_bug_output(self):
502
"""commit --fixes=lp:23452 succeeds without output."""
503
tree = self.make_branch_and_tree('tree')
504
self.build_tree(['tree/hello.txt'])
505
tree.add('hello.txt')
506
output, err = self.run_bzr(
507
'commit -m hello --fixes=lp:23452 tree/hello.txt')
508
self.assertEqual('', output)
509
self.assertContainsRe(err, 'Committing to: .*\n'
511
'Committed revision 1\.\n')
513
def test_no_bugs_no_properties(self):
514
"""If no bugs are fixed, the bugs property is not set.
516
see https://beta.launchpad.net/bzr/+bug/109613
518
tree = self.make_branch_and_tree('tree')
519
self.build_tree(['tree/hello.txt'])
520
tree.add('hello.txt')
521
self.run_bzr( 'commit -m hello tree/hello.txt')
522
# Get the revision properties, ignoring the branch-nick property, which
523
# we don't care about for this test.
524
last_rev = tree.branch.repository.get_revision(tree.last_revision())
525
properties = dict(last_rev.properties)
526
del properties['branch-nick']
527
self.assertFalse('bugs' in properties)
529
def test_fixes_bug_sets_property(self):
530
"""commit --fixes=lp:234 sets the lp:234 revprop to 'fixed'."""
531
tree = self.make_branch_and_tree('tree')
532
self.build_tree(['tree/hello.txt'])
533
tree.add('hello.txt')
534
self.run_bzr('commit -m hello --fixes=lp:234 tree/hello.txt')
536
# Get the revision properties, ignoring the branch-nick property, which
537
# we don't care about for this test.
538
last_rev = tree.branch.repository.get_revision(tree.last_revision())
539
properties = dict(last_rev.properties)
540
del properties['branch-nick']
542
self.assertEqual({'bugs': 'https://launchpad.net/bugs/234 fixed'},
545
def test_fixes_multiple_bugs_sets_properties(self):
546
"""--fixes can be used more than once to show that bugs are fixed."""
547
tree = self.make_branch_and_tree('tree')
548
self.build_tree(['tree/hello.txt'])
549
tree.add('hello.txt')
550
self.run_bzr('commit -m hello --fixes=lp:123 --fixes=lp:235'
553
# Get the revision properties, ignoring the branch-nick property, which
554
# we don't care about for this test.
555
last_rev = tree.branch.repository.get_revision(tree.last_revision())
556
properties = dict(last_rev.properties)
557
del properties['branch-nick']
560
{'bugs': 'https://launchpad.net/bugs/123 fixed\n'
561
'https://launchpad.net/bugs/235 fixed'},
564
def test_fixes_bug_with_alternate_trackers(self):
565
"""--fixes can be used on a properly configured branch to mark bug
566
fixes on multiple trackers.
568
tree = self.make_branch_and_tree('tree')
569
tree.branch.get_config().set_user_option(
570
'trac_twisted_url', 'http://twistedmatrix.com/trac')
571
self.build_tree(['tree/hello.txt'])
572
tree.add('hello.txt')
573
self.run_bzr('commit -m hello --fixes=lp:123 --fixes=twisted:235 tree/')
575
# Get the revision properties, ignoring the branch-nick property, which
576
# we don't care about for this test.
577
last_rev = tree.branch.repository.get_revision(tree.last_revision())
578
properties = dict(last_rev.properties)
579
del properties['branch-nick']
582
{'bugs': 'https://launchpad.net/bugs/123 fixed\n'
583
'http://twistedmatrix.com/trac/ticket/235 fixed'},
586
def test_fixes_unknown_bug_prefix(self):
587
tree = self.make_branch_and_tree('tree')
588
self.build_tree(['tree/hello.txt'])
589
tree.add('hello.txt')
591
["Unrecognized bug %s. Commit refused." % 'xxx:123'],
592
'commit -m add-b --fixes=xxx:123',
595
def test_fixes_invalid_bug_number(self):
596
tree = self.make_branch_and_tree('tree')
597
self.build_tree(['tree/hello.txt'])
598
tree.add('hello.txt')
600
["Did not understand bug identifier orange: Must be an integer. "
601
"See \"bzr help bugs\" for more information on this feature.\n"
603
'commit -m add-b --fixes=lp:orange',
606
def test_fixes_invalid_argument(self):
607
"""Raise an appropriate error when the fixes argument isn't tag:id."""
608
tree = self.make_branch_and_tree('tree')
609
self.build_tree(['tree/hello.txt'])
610
tree.add('hello.txt')
612
[r"Invalid bug orange. Must be in the form of 'tracker:id'\. "
613
r"See \"bzr help bugs\" for more information on this feature.\n"
614
r"Commit refused\."],
615
'commit -m add-b --fixes=orange',
618
def test_no_author(self):
619
"""If the author is not specified, the author property is not set."""
620
tree = self.make_branch_and_tree('tree')
621
self.build_tree(['tree/hello.txt'])
622
tree.add('hello.txt')
623
self.run_bzr( 'commit -m hello tree/hello.txt')
624
last_rev = tree.branch.repository.get_revision(tree.last_revision())
625
properties = last_rev.properties
626
self.assertFalse('author' in properties)
628
def test_author_sets_property(self):
629
"""commit --author='John Doe <jdoe@example.com>' sets the author
632
tree = self.make_branch_and_tree('tree')
633
self.build_tree(['tree/hello.txt'])
634
tree.add('hello.txt')
635
self.run_bzr(["commit", '-m', 'hello',
636
'--author', u'John D\xf6 <jdoe@example.com>',
638
last_rev = tree.branch.repository.get_revision(tree.last_revision())
639
properties = last_rev.properties
640
self.assertEqual(u'John D\xf6 <jdoe@example.com>', properties['authors'])
642
def test_author_no_email(self):
643
"""Author's name without an email address is allowed, too."""
644
tree = self.make_branch_and_tree('tree')
645
self.build_tree(['tree/hello.txt'])
646
tree.add('hello.txt')
647
out, err = self.run_bzr("commit -m hello --author='John Doe' "
649
last_rev = tree.branch.repository.get_revision(tree.last_revision())
650
properties = last_rev.properties
651
self.assertEqual('John Doe', properties['authors'])
653
def test_multiple_authors(self):
654
"""Multiple authors can be specyfied, and all are stored."""
655
tree = self.make_branch_and_tree('tree')
656
self.build_tree(['tree/hello.txt'])
657
tree.add('hello.txt')
658
out, err = self.run_bzr("commit -m hello --author='John Doe' "
659
"--author='Jane Rey' tree/hello.txt")
660
last_rev = tree.branch.repository.get_revision(tree.last_revision())
661
properties = last_rev.properties
662
self.assertEqual('John Doe\nJane Rey', properties['authors'])
664
def test_commit_time(self):
665
tree = self.make_branch_and_tree('tree')
666
self.build_tree(['tree/hello.txt'])
667
tree.add('hello.txt')
668
out, err = self.run_bzr("commit -m hello "
669
"--commit-time='2009-10-10 08:00:00 +0100' tree/hello.txt")
670
last_rev = tree.branch.repository.get_revision(tree.last_revision())
672
'Sat 2009-10-10 08:00:00 +0100',
673
osutils.format_date(last_rev.timestamp, last_rev.timezone))
675
def test_commit_time_bad_time(self):
676
tree = self.make_branch_and_tree('tree')
677
self.build_tree(['tree/hello.txt'])
678
tree.add('hello.txt')
679
out, err = self.run_bzr("commit -m hello "
680
"--commit-time='NOT A TIME' tree/hello.txt", retcode=3)
681
self.assertStartsWith(
682
err, "bzr: ERROR: Could not parse --commit-time:")
684
def test_partial_commit_with_renames_in_tree(self):
685
# this test illustrates bug #140419
686
t = self.make_branch_and_tree('.')
687
self.build_tree(['dir/', 'dir/a', 'test'])
688
t.add(['dir/', 'dir/a', 'test'])
689
t.commit('initial commit')
690
# important part: file dir/a should change parent
691
# and should appear before old parent
692
# then during partial commit we have error
693
# parent_id {dir-XXX} not in inventory
694
t.rename_one('dir/a', 'a')
695
self.build_tree_contents([('test', 'changes in test')])
697
out, err = self.run_bzr('commit test -m "partial commit"')
698
self.assertEquals('', out)
699
self.assertContainsRe(err, r'modified test\nCommitted revision 2.')
701
def test_commit_readonly_checkout(self):
702
# https://bugs.launchpad.net/bzr/+bug/129701
703
# "UnlockableTransport error trying to commit in checkout of readonly
705
self.make_branch('master')
706
master = BzrDir.open_from_transport(
707
self.get_readonly_transport('master')).open_branch()
708
master.create_checkout('checkout')
709
out, err = self.run_bzr(['commit', '--unchanged', '-mfoo', 'checkout'],
711
self.assertContainsRe(err,
712
r'^bzr: ERROR: Cannot lock.*readonly transport')
714
def setup_editor(self):
715
# Test that commit template hooks work
716
if sys.platform == "win32":
717
f = file('fed.bat', 'w')
718
f.write('@rem dummy fed')
720
osutils.set_or_unset_env('BZR_EDITOR', "fed.bat")
722
f = file('fed.sh', 'wb')
723
f.write('#!/bin/sh\n')
725
os.chmod('fed.sh', 0755)
726
osutils.set_or_unset_env('BZR_EDITOR', "./fed.sh")
728
def setup_commit_with_template(self):
730
msgeditor.hooks.install_named_hook("commit_message_template",
731
lambda commit_obj, msg: "save me some typing\n", None)
732
tree = self.make_branch_and_tree('tree')
733
self.build_tree(['tree/hello.txt'])
734
tree.add('hello.txt')
737
def test_commit_hook_template_accepted(self):
738
tree = self.setup_commit_with_template()
739
out, err = self.run_bzr("commit tree/hello.txt", stdin="y\n")
740
last_rev = tree.branch.repository.get_revision(tree.last_revision())
741
self.assertEqual('save me some typing\n', last_rev.message)
743
def test_commit_hook_template_rejected(self):
744
tree = self.setup_commit_with_template()
745
expected = tree.last_revision()
746
out, err = self.run_bzr_error(["empty commit message"],
747
"commit tree/hello.txt", stdin="n\n")
748
self.assertEqual(expected, tree.last_revision())
750
def test_commit_without_username(self):
751
"""Ensure commit error if username is not set.
753
self.run_bzr(['init', 'foo'])
755
open('foo.txt', 'w').write('hello')
756
self.run_bzr(['add'])
757
osutils.set_or_unset_env('EMAIL', None)
758
osutils.set_or_unset_env('BZR_EMAIL', None)
759
out, err = self.run_bzr(['commit', '-m', 'initial'], 3)
760
self.assertContainsRe(err, 'Unable to determine your name')
762
def test_commit_recursive_checkout(self):
763
"""Ensure that a commit to a recursive checkout fails cleanly.
765
self.run_bzr(['init', 'test_branch'])
766
self.run_bzr(['checkout', 'test_branch', 'test_checkout'])
767
os.chdir('test_checkout')
768
self.run_bzr(['bind', '.']) # bind to self
769
open('foo.txt', 'w').write('hello')
770
self.run_bzr(['add'])
771
out, err = self.run_bzr(['commit', '-m', 'addedfoo'], 3)
772
self.assertEqual(out, '')
773
self.assertContainsRe(err,
774
'Branch.*test_checkout.*appears to be bound to itself')