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):
31
from bzrlib.bzrdir import BzrDir
32
from bzrlib.tests import (
36
from bzrlib.tests import TestCaseWithTransport
39
class TestCommit(TestCaseWithTransport):
35
41
def test_05_empty_commit(self):
36
42
"""Commit of tree with no versioned files should fail"""
37
43
# If forced, it should succeed, but this is not tested here.
44
self.make_branch_and_tree('.')
39
45
self.build_tree(['hello.txt'])
40
self.runbzr("commit -m empty", retcode=3)
46
out,err = self.run_bzr('commit -m empty', retcode=3)
47
self.assertEqual('', out)
48
self.assertContainsRe(err, 'bzr: ERROR: No changes to commit\.'
49
' Use --unchanged to commit anyhow.\n')
51
def test_commit_success(self):
52
"""Successful commit should not leave behind a bzr-commit-* file"""
53
self.make_branch_and_tree('.')
54
self.run_bzr('commit --unchanged -m message')
55
self.assertEqual('', self.run_bzr('unknowns')[0])
57
# same for unicode messages
58
self.run_bzr(["commit", "--unchanged", "-m", u'foo\xb5'])
59
self.assertEqual('', self.run_bzr('unknowns')[0])
61
def test_commit_with_path(self):
62
"""Commit tree with path of root specified"""
63
a_tree = self.make_branch_and_tree('a')
64
self.build_tree(['a/a_file'])
66
self.run_bzr(['commit', '-m', 'first commit', 'a'])
68
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
69
self.build_tree_contents([('b/a_file', 'changes in b')])
70
self.run_bzr(['commit', '-m', 'first commit in b', 'b'])
72
self.build_tree_contents([('a/a_file', 'new contents')])
73
self.run_bzr(['commit', '-m', 'change in a', 'a'])
75
b_tree.merge_from_branch(a_tree.branch)
76
self.assertEqual(len(b_tree.conflicts()), 1)
77
self.run_bzr('resolved b/a_file')
78
self.run_bzr(['commit', '-m', 'merge into b', 'b'])
42
81
def test_10_verbose_commit(self):
43
82
"""Add one file and examine verbose commit output"""
83
tree = self.make_branch_and_tree('.')
45
84
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):
86
out,err = self.run_bzr('commit -m added')
87
self.assertEqual('', out)
88
self.assertContainsRe(err, '^Committing to: .*\n'
90
'Committed revision 1.\n$',)
92
def prepare_simple_history(self):
93
"""Prepare and return a working tree with one commit of one file"""
94
# Commit with modified file should say so
95
wt = BzrDir.create_standalone_workingtree('.')
96
self.build_tree(['hello.txt', 'extra.txt'])
98
wt.commit(message='added')
101
def test_verbose_commit_modified(self):
102
# Verbose commit of modified file should say so
103
wt = self.prepare_simple_history()
104
self.build_tree_contents([('hello.txt', 'new contents')])
105
out, err = self.run_bzr('commit -m modified')
106
self.assertEqual('', out)
107
self.assertContainsRe(err, '^Committing to: .*\n'
108
'modified hello\.txt\n'
109
'Committed revision 2\.\n$')
111
def test_unicode_commit_message_is_filename(self):
112
"""Unicode commit message same as a filename (Bug #563646).
114
file_name = u'\N{euro sign}'
115
self.run_bzr(['init'])
116
open(file_name, 'w').write('hello world')
117
self.run_bzr(['add'])
118
out, err = self.run_bzr(['commit', '-m', file_name])
119
reflags = re.MULTILINE|re.DOTALL|re.UNICODE
120
te = osutils.get_terminal_encoding()
121
self.assertContainsRe(err.decode(te),
122
u'The commit message is a file name:',
125
# Run same test with a filename that causes encode
126
# error for the terminal encoding. We do this
127
# by forcing terminal encoding of ascii for
128
# osutils.get_terminal_encoding which is used
129
# by ui.text.show_warning
130
default_get_terminal_enc = osutils.get_terminal_encoding
132
osutils.get_terminal_encoding = lambda trace=None: 'ascii'
133
file_name = u'foo\u1234'
134
open(file_name, 'w').write('hello world')
135
self.run_bzr(['add'])
136
out, err = self.run_bzr(['commit', '-m', file_name])
137
reflags = re.MULTILINE|re.DOTALL|re.UNICODE
138
te = osutils.get_terminal_encoding()
139
self.assertContainsRe(err.decode(te, 'replace'),
140
u'The commit message is a file name:',
143
osutils.get_terminal_encoding = default_get_terminal_enc
145
def test_warn_about_forgotten_commit_message(self):
146
"""Test that the lack of -m parameter is caught"""
147
wt = self.make_branch_and_tree('.')
148
self.build_tree(['one', 'two'])
150
out, err = self.run_bzr('commit -m one two')
151
self.assertContainsRe(err, "The commit message is a file name")
153
def test_verbose_commit_renamed(self):
154
# Verbose commit of renamed file should say so
155
wt = self.prepare_simple_history()
156
wt.rename_one('hello.txt', 'gutentag.txt')
157
out, err = self.run_bzr('commit -m renamed')
158
self.assertEqual('', out)
159
self.assertContainsRe(err, '^Committing to: .*\n'
160
'renamed hello\.txt => gutentag\.txt\n'
161
'Committed revision 2\.$\n')
163
def test_verbose_commit_moved(self):
164
# Verbose commit of file moved to new directory should say so
165
wt = self.prepare_simple_history()
168
wt.rename_one('hello.txt', 'subdir/hello.txt')
169
out, err = self.run_bzr('commit -m renamed')
170
self.assertEqual('', out)
171
self.assertEqual(set([
172
'Committing to: %s/' % osutils.getcwd(),
174
'renamed hello.txt => subdir/hello.txt',
175
'Committed revision 2.',
177
]), set(err.split('\n')))
179
def test_verbose_commit_with_unknown(self):
54
180
"""Unknown files should not be listed by default in verbose output"""
55
181
# Is that really the best policy?
182
wt = BzrDir.create_standalone_workingtree('.')
57
183
self.build_tree(['hello.txt', 'extra.txt'])
58
self.runbzr("add hello.txt")
59
out,err = self.run_bzr("commit", "-m", "added")
184
wt.add(['hello.txt'])
185
out,err = self.run_bzr('commit -m added')
60
186
self.assertEqual('', out)
61
self.assertEqual('added hello.txt\n'
62
'Committed revision 1.\n',
187
self.assertContainsRe(err, '^Committing to: .*\n'
189
'Committed revision 1\.\n$')
65
def test_16_verbose_commit_with_unchanged(self):
191
def test_verbose_commit_with_unchanged(self):
66
192
"""Unchanged files should not be listed by default in verbose output"""
193
tree = self.make_branch_and_tree('.')
68
194
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',
195
tree.add('unchanged.txt')
196
self.run_bzr('commit -m unchanged unchanged.txt')
197
tree.add("hello.txt")
198
out,err = self.run_bzr('commit -m added')
199
self.assertEqual('', out)
200
self.assertContainsRe(err, '^Committing to: .*\n'
202
'Committed revision 2\.$\n')
204
def test_verbose_commit_includes_master_location(self):
205
"""Location of master is displayed when committing to bound branch"""
206
a_tree = self.make_branch_and_tree('a')
207
self.build_tree(['a/b'])
209
a_tree.commit(message='Initial message')
211
b_tree = a_tree.branch.create_checkout('b')
212
expected = "%s/" % (osutils.abspath('a'), )
213
out, err = self.run_bzr('commit -m blah --unchanged', working_dir='b')
214
self.assertEqual(err, 'Committing to: %s\n'
215
'Committed revision 2.\n' % expected)
217
def test_commit_sanitizes_CR_in_message(self):
218
# See bug #433779, basically Emacs likes to pass '\r\n' style line
219
# endings to 'bzr commit -m ""' which breaks because we don't allow
220
# '\r' in commit messages. (Mostly because of issues where XML style
221
# formats arbitrarily strip it out of the data while parsing.)
222
# To make life easier for users, we just always translate '\r\n' =>
223
# '\n'. And '\r' => '\n'.
224
a_tree = self.make_branch_and_tree('a')
225
self.build_tree(['a/b'])
227
self.run_bzr(['commit',
228
'-m', 'a string\r\n\r\nwith mixed\r\rendings\n'],
230
rev_id = a_tree.branch.last_revision()
231
rev = a_tree.branch.repository.get_revision(rev_id)
232
self.assertEqualDiff('a string\n\nwith mixed\n\nendings\n',
235
def test_commit_merge_reports_all_modified_files(self):
236
# the commit command should show all the files that are shown by
237
# bzr diff or bzr status when committing, even when they were not
238
# changed by the user but rather through doing a merge.
239
this_tree = self.make_branch_and_tree('this')
240
# we need a bunch of files and dirs, to perform one action on each.
243
'this/dirtoreparent/',
246
'this/filetoreparent',
263
this_tree.commit('create_files')
264
other_dir = this_tree.bzrdir.sprout('other')
265
other_tree = other_dir.open_workingtree()
266
other_tree.lock_write()
267
# perform the needed actions on the files and dirs.
269
other_tree.rename_one('dirtorename', 'renameddir')
270
other_tree.rename_one('dirtoreparent', 'renameddir/reparenteddir')
271
other_tree.rename_one('filetorename', 'renamedfile')
272
other_tree.rename_one('filetoreparent',
273
'renameddir/reparentedfile')
274
other_tree.remove(['dirtoremove', 'filetoremove'])
275
self.build_tree_contents([
277
('other/filetomodify', 'new content'),
278
('other/newfile', 'new file content')])
279
other_tree.add('newfile')
280
other_tree.add('newdir/')
281
other_tree.commit('modify all sample files and dirs.')
284
this_tree.merge_from_branch(other_tree.branch)
286
out,err = self.run_bzr('commit -m added')
287
self.assertEqual('', out)
288
self.assertEqual(set([
289
'Committing to: %s/' % osutils.getcwd(),
290
'modified filetomodify',
293
'renamed dirtorename => renameddir',
294
'renamed filetorename => renamedfile',
295
'renamed dirtoreparent => renameddir/reparenteddir',
296
'renamed filetoreparent => renameddir/reparentedfile',
297
'deleted dirtoremove',
298
'deleted filetoremove',
299
'Committed revision 2.',
301
]), set(err.split('\n')))
78
303
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)
304
tree = self.make_branch_and_tree('.')
305
self.build_tree_contents([('foo.c', 'int main() {}')])
307
self.run_bzr('commit -m ""', retcode=3)
309
def test_unsupported_encoding_commit_message(self):
310
if sys.platform == 'win32':
311
raise tests.TestNotApplicable('Win32 parses arguments directly'
312
' as Unicode, so we can\'t pass invalid non-ascii')
313
tree = self.make_branch_and_tree('.')
314
self.build_tree_contents([('foo.c', 'int main() {}')])
316
# LANG env variable has no effect on Windows
317
# but some characters anyway cannot be represented
318
# in default user encoding
319
char = probe_bad_non_ascii(osutils.get_user_encoding())
321
raise TestSkipped('Cannot find suitable non-ascii character'
322
'for user_encoding (%s)' % osutils.get_user_encoding())
323
out,err = self.run_bzr_subprocess('commit -m "%s"' % char,
325
env_changes={'LANG': 'C'})
326
self.assertContainsRe(err, r'bzrlib.errors.BzrError: Parameter.*is '
327
'unsupported by the current encoding.')
84
329
def test_other_branch_commit(self):
85
330
# this branch is to ensure consistent behaviour, whether we're run
86
331
# 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'])
332
outer_tree = self.make_branch_and_tree('.')
333
inner_tree = self.make_branch_and_tree('branch')
334
self.build_tree_contents([
335
('branch/foo.c', 'int main() {}'),
336
('branch/bar.c', 'int main() {}')])
337
inner_tree.add(['foo.c', 'bar.c'])
98
338
# 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)
339
self.run_bzr('commit -m newstuff branch/foo.c .', retcode=3)
340
# can commit to branch - records foo.c only
341
self.run_bzr('commit -m newstuff branch/foo.c')
342
# can commit to branch - records bar.c
343
self.run_bzr('commit -m newstuff branch')
345
self.run_bzr_error(["No changes to commit"], 'commit -m newstuff branch')
104
347
def test_out_of_date_tree_commit(self):
105
348
# check we get an error code and a clear message committing with an out
106
349
# of date checkout
107
self.make_branch_and_tree('branch')
350
tree = self.make_branch_and_tree('branch')
108
351
# make a checkout
109
self.runbzr('checkout --lightweight branch checkout')
352
checkout = tree.branch.create_checkout('checkout', lightweight=True)
110
353
# commit to the original branch to make the checkout out of date
111
self.runbzr('commit --unchanged -m message branch')
354
tree.commit('message branch', allow_pointless=True)
112
355
# now commit to the checkout should emit
113
356
# ERROR: Out of date with the branch, 'bzr update' is suggested
114
output = self.runbzr('commit --unchanged -m checkout_message '
357
output = self.run_bzr('commit --unchanged -m checkout_message '
115
358
'checkout', retcode=3)
116
359
self.assertEqual(output,
118
"bzr: ERROR: Working tree is out of date, please run "
361
"bzr: ERROR: Working tree is out of date, please "
362
"run 'bzr update'.\n"))
121
364
def test_local_commit_unbound(self):
122
365
# a --local commit on an unbound branch is an error
123
366
self.make_branch_and_tree('.')
124
out, err = self.run_bzr('commit', '--local', retcode=3)
367
out, err = self.run_bzr('commit --local', retcode=3)
125
368
self.assertEqualDiff('', out)
126
369
self.assertEqualDiff('bzr: ERROR: Cannot perform local-only commits '
127
370
'on unbound branches.\n', err)
372
def test_commit_a_text_merge_in_a_checkout(self):
373
# checkouts perform multiple actions in a transaction across bond
374
# branches and their master, and have been observed to fail in the
375
# past. This is a user story reported to fail in bug #43959 where
376
# a merge done in a checkout (using the update command) failed to
378
trunk = self.make_branch_and_tree('trunk')
380
u1 = trunk.branch.create_checkout('u1')
381
self.build_tree_contents([('u1/hosts', 'initial contents\n')])
383
self.run_bzr('commit -m add-hosts u1')
385
u2 = trunk.branch.create_checkout('u2')
386
self.build_tree_contents([('u2/hosts', 'altered in u2\n')])
387
self.run_bzr('commit -m checkin-from-u2 u2')
389
# make an offline commits
390
self.build_tree_contents([('u1/hosts', 'first offline change in u1\n')])
391
self.run_bzr('commit -m checkin-offline --local u1')
393
# now try to pull in online work from u2, and then commit our offline
395
# retcode 1 as we expect a text conflict
396
self.run_bzr('update u1', retcode=1)
397
self.assertFileEqual('''\
399
first offline change in u1
406
self.run_bzr('resolved u1/hosts')
407
# add a text change here to represent resolving the merge conflicts in
408
# favour of a new version of the file not identical to either the u1
409
# version or the u2 version.
410
self.build_tree_contents([('u1/hosts', 'merge resolution\n')])
411
self.run_bzr('commit -m checkin-merge-of-the-offline-work-from-u1 u1')
413
def test_commit_exclude_excludes_modified_files(self):
414
"""Commit -x foo should ignore changes to foo."""
415
tree = self.make_branch_and_tree('.')
416
self.build_tree(['a', 'b', 'c'])
417
tree.smart_add(['.'])
418
out, err = self.run_bzr(['commit', '-m', 'test', '-x', 'b'])
419
self.assertFalse('added b' in out)
420
self.assertFalse('added b' in err)
421
# If b was excluded it will still be 'added' in status.
422
out, err = self.run_bzr(['added'])
423
self.assertEqual('b\n', out)
424
self.assertEqual('', err)
426
def test_commit_exclude_twice_uses_both_rules(self):
427
"""Commit -x foo -x bar should ignore changes to foo and bar."""
428
tree = self.make_branch_and_tree('.')
429
self.build_tree(['a', 'b', 'c'])
430
tree.smart_add(['.'])
431
out, err = self.run_bzr(['commit', '-m', 'test', '-x', 'b', '-x', 'c'])
432
self.assertFalse('added b' in out)
433
self.assertFalse('added c' in out)
434
self.assertFalse('added b' in err)
435
self.assertFalse('added c' in err)
436
# If b was excluded it will still be 'added' in status.
437
out, err = self.run_bzr(['added'])
438
self.assertTrue('b\n' in out)
439
self.assertTrue('c\n' in out)
440
self.assertEqual('', err)
442
def test_commit_respects_spec_for_removals(self):
443
"""Commit with a file spec should only commit removals that match"""
444
t = self.make_branch_and_tree('.')
445
self.build_tree(['file-a', 'dir-a/', 'dir-a/file-b'])
446
t.add(['file-a', 'dir-a', 'dir-a/file-b'])
448
t.remove(['file-a', 'dir-a/file-b'])
450
result = self.run_bzr('commit . -m removed-file-b')[1]
451
self.assertNotContainsRe(result, 'file-a')
452
result = self.run_bzr('status')[0]
453
self.assertContainsRe(result, 'removed:\n file-a')
455
def test_strict_commit(self):
456
"""Commit with --strict works if everything is known"""
457
ignores._set_user_ignores([])
458
tree = self.make_branch_and_tree('tree')
459
self.build_tree(['tree/a'])
461
# A simple change should just work
462
self.run_bzr('commit --strict -m adding-a',
465
def test_strict_commit_no_changes(self):
466
"""commit --strict gives "no changes" if there is nothing to commit"""
467
tree = self.make_branch_and_tree('tree')
468
self.build_tree(['tree/a'])
470
tree.commit('adding a')
472
# With no changes, it should just be 'no changes'
473
# Make sure that commit is failing because there is nothing to do
474
self.run_bzr_error(['No changes to commit'],
475
'commit --strict -m no-changes',
478
# But --strict doesn't care if you supply --unchanged
479
self.run_bzr('commit --strict --unchanged -m no-changes',
482
def test_strict_commit_unknown(self):
483
"""commit --strict fails if a file is unknown"""
484
tree = self.make_branch_and_tree('tree')
485
self.build_tree(['tree/a'])
487
tree.commit('adding a')
489
# Add one file so there is a change, but forget the other
490
self.build_tree(['tree/b', 'tree/c'])
492
self.run_bzr_error(['Commit refused because there are unknown files'],
493
'commit --strict -m add-b',
496
# --no-strict overrides --strict
497
self.run_bzr('commit --strict -m add-b --no-strict',
500
def test_fixes_bug_output(self):
501
"""commit --fixes=lp:23452 succeeds without output."""
502
tree = self.make_branch_and_tree('tree')
503
self.build_tree(['tree/hello.txt'])
504
tree.add('hello.txt')
505
output, err = self.run_bzr(
506
'commit -m hello --fixes=lp:23452 tree/hello.txt')
507
self.assertEqual('', output)
508
self.assertContainsRe(err, 'Committing to: .*\n'
510
'Committed revision 1\.\n')
512
def test_no_bugs_no_properties(self):
513
"""If no bugs are fixed, the bugs property is not set.
515
see https://beta.launchpad.net/bzr/+bug/109613
517
tree = self.make_branch_and_tree('tree')
518
self.build_tree(['tree/hello.txt'])
519
tree.add('hello.txt')
520
self.run_bzr( 'commit -m hello tree/hello.txt')
521
# Get the revision properties, ignoring the branch-nick property, which
522
# we don't care about for this test.
523
last_rev = tree.branch.repository.get_revision(tree.last_revision())
524
properties = dict(last_rev.properties)
525
del properties['branch-nick']
526
self.assertFalse('bugs' in properties)
528
def test_fixes_bug_sets_property(self):
529
"""commit --fixes=lp:234 sets the lp:234 revprop to 'fixed'."""
530
tree = self.make_branch_and_tree('tree')
531
self.build_tree(['tree/hello.txt'])
532
tree.add('hello.txt')
533
self.run_bzr('commit -m hello --fixes=lp:234 tree/hello.txt')
535
# Get the revision properties, ignoring the branch-nick property, which
536
# we don't care about for this test.
537
last_rev = tree.branch.repository.get_revision(tree.last_revision())
538
properties = dict(last_rev.properties)
539
del properties['branch-nick']
541
self.assertEqual({'bugs': 'https://launchpad.net/bugs/234 fixed'},
544
def test_fixes_multiple_bugs_sets_properties(self):
545
"""--fixes can be used more than once to show that bugs are fixed."""
546
tree = self.make_branch_and_tree('tree')
547
self.build_tree(['tree/hello.txt'])
548
tree.add('hello.txt')
549
self.run_bzr('commit -m hello --fixes=lp:123 --fixes=lp:235'
552
# Get the revision properties, ignoring the branch-nick property, which
553
# we don't care about for this test.
554
last_rev = tree.branch.repository.get_revision(tree.last_revision())
555
properties = dict(last_rev.properties)
556
del properties['branch-nick']
559
{'bugs': 'https://launchpad.net/bugs/123 fixed\n'
560
'https://launchpad.net/bugs/235 fixed'},
563
def test_fixes_bug_with_alternate_trackers(self):
564
"""--fixes can be used on a properly configured branch to mark bug
565
fixes on multiple trackers.
567
tree = self.make_branch_and_tree('tree')
568
tree.branch.get_config().set_user_option(
569
'trac_twisted_url', 'http://twistedmatrix.com/trac')
570
self.build_tree(['tree/hello.txt'])
571
tree.add('hello.txt')
572
self.run_bzr('commit -m hello --fixes=lp:123 --fixes=twisted:235 tree/')
574
# Get the revision properties, ignoring the branch-nick property, which
575
# we don't care about for this test.
576
last_rev = tree.branch.repository.get_revision(tree.last_revision())
577
properties = dict(last_rev.properties)
578
del properties['branch-nick']
581
{'bugs': 'https://launchpad.net/bugs/123 fixed\n'
582
'http://twistedmatrix.com/trac/ticket/235 fixed'},
585
def test_fixes_unknown_bug_prefix(self):
586
tree = self.make_branch_and_tree('tree')
587
self.build_tree(['tree/hello.txt'])
588
tree.add('hello.txt')
590
["Unrecognized bug %s. Commit refused." % 'xxx:123'],
591
'commit -m add-b --fixes=xxx:123',
594
def test_fixes_invalid_bug_number(self):
595
tree = self.make_branch_and_tree('tree')
596
self.build_tree(['tree/hello.txt'])
597
tree.add('hello.txt')
599
["Did not understand bug identifier orange: Must be an integer. "
600
"See \"bzr help bugs\" for more information on this feature.\n"
602
'commit -m add-b --fixes=lp:orange',
605
def test_fixes_invalid_argument(self):
606
"""Raise an appropriate error when the fixes argument isn't tag:id."""
607
tree = self.make_branch_and_tree('tree')
608
self.build_tree(['tree/hello.txt'])
609
tree.add('hello.txt')
611
[r"Invalid bug orange. Must be in the form of 'tracker:id'\. "
612
r"See \"bzr help bugs\" for more information on this feature.\n"
613
r"Commit refused\."],
614
'commit -m add-b --fixes=orange',
617
def test_no_author(self):
618
"""If the author is not specified, the author property is not set."""
619
tree = self.make_branch_and_tree('tree')
620
self.build_tree(['tree/hello.txt'])
621
tree.add('hello.txt')
622
self.run_bzr( 'commit -m hello tree/hello.txt')
623
last_rev = tree.branch.repository.get_revision(tree.last_revision())
624
properties = last_rev.properties
625
self.assertFalse('author' in properties)
627
def test_author_sets_property(self):
628
"""commit --author='John Doe <jdoe@example.com>' sets the author
631
tree = self.make_branch_and_tree('tree')
632
self.build_tree(['tree/hello.txt'])
633
tree.add('hello.txt')
634
self.run_bzr(["commit", '-m', 'hello',
635
'--author', u'John D\xf6 <jdoe@example.com>',
637
last_rev = tree.branch.repository.get_revision(tree.last_revision())
638
properties = last_rev.properties
639
self.assertEqual(u'John D\xf6 <jdoe@example.com>', properties['authors'])
641
def test_author_no_email(self):
642
"""Author's name without an email address is allowed, too."""
643
tree = self.make_branch_and_tree('tree')
644
self.build_tree(['tree/hello.txt'])
645
tree.add('hello.txt')
646
out, err = self.run_bzr("commit -m hello --author='John Doe' "
648
last_rev = tree.branch.repository.get_revision(tree.last_revision())
649
properties = last_rev.properties
650
self.assertEqual('John Doe', properties['authors'])
652
def test_multiple_authors(self):
653
"""Multiple authors can be specyfied, and all are stored."""
654
tree = self.make_branch_and_tree('tree')
655
self.build_tree(['tree/hello.txt'])
656
tree.add('hello.txt')
657
out, err = self.run_bzr("commit -m hello --author='John Doe' "
658
"--author='Jane Rey' tree/hello.txt")
659
last_rev = tree.branch.repository.get_revision(tree.last_revision())
660
properties = last_rev.properties
661
self.assertEqual('John Doe\nJane Rey', properties['authors'])
663
def test_commit_time(self):
664
tree = self.make_branch_and_tree('tree')
665
self.build_tree(['tree/hello.txt'])
666
tree.add('hello.txt')
667
out, err = self.run_bzr("commit -m hello "
668
"--commit-time='2009-10-10 08:00:00 +0100' tree/hello.txt")
669
last_rev = tree.branch.repository.get_revision(tree.last_revision())
671
'Sat 2009-10-10 08:00:00 +0100',
672
osutils.format_date(last_rev.timestamp, last_rev.timezone))
674
def test_commit_time_bad_time(self):
675
tree = self.make_branch_and_tree('tree')
676
self.build_tree(['tree/hello.txt'])
677
tree.add('hello.txt')
678
out, err = self.run_bzr("commit -m hello "
679
"--commit-time='NOT A TIME' tree/hello.txt", retcode=3)
680
self.assertStartsWith(
681
err, "bzr: ERROR: Could not parse --commit-time:")
683
def test_partial_commit_with_renames_in_tree(self):
684
# this test illustrates bug #140419
685
t = self.make_branch_and_tree('.')
686
self.build_tree(['dir/', 'dir/a', 'test'])
687
t.add(['dir/', 'dir/a', 'test'])
688
t.commit('initial commit')
689
# important part: file dir/a should change parent
690
# and should appear before old parent
691
# then during partial commit we have error
692
# parent_id {dir-XXX} not in inventory
693
t.rename_one('dir/a', 'a')
694
self.build_tree_contents([('test', 'changes in test')])
696
out, err = self.run_bzr('commit test -m "partial commit"')
697
self.assertEquals('', out)
698
self.assertContainsRe(err, r'modified test\nCommitted revision 2.')
700
def test_commit_readonly_checkout(self):
701
# https://bugs.launchpad.net/bzr/+bug/129701
702
# "UnlockableTransport error trying to commit in checkout of readonly
704
self.make_branch('master')
705
master = BzrDir.open_from_transport(
706
self.get_readonly_transport('master')).open_branch()
707
master.create_checkout('checkout')
708
out, err = self.run_bzr(['commit', '--unchanged', '-mfoo', 'checkout'],
710
self.assertContainsRe(err,
711
r'^bzr: ERROR: Cannot lock.*readonly transport')
713
def setup_editor(self):
714
# Test that commit template hooks work
715
if sys.platform == "win32":
716
f = file('fed.bat', 'w')
717
f.write('@rem dummy fed')
719
osutils.set_or_unset_env('BZR_EDITOR', "fed.bat")
721
f = file('fed.sh', 'wb')
722
f.write('#!/bin/sh\n')
724
os.chmod('fed.sh', 0755)
725
osutils.set_or_unset_env('BZR_EDITOR', "./fed.sh")
727
def setup_commit_with_template(self):
729
msgeditor.hooks.install_named_hook("commit_message_template",
730
lambda commit_obj, msg: "save me some typing\n", None)
731
tree = self.make_branch_and_tree('tree')
732
self.build_tree(['tree/hello.txt'])
733
tree.add('hello.txt')
736
def test_commit_hook_template_accepted(self):
737
tree = self.setup_commit_with_template()
738
out, err = self.run_bzr("commit tree/hello.txt", stdin="y\n")
739
last_rev = tree.branch.repository.get_revision(tree.last_revision())
740
self.assertEqual('save me some typing\n', last_rev.message)
742
def test_commit_hook_template_rejected(self):
743
tree = self.setup_commit_with_template()
744
expected = tree.last_revision()
745
out, err = self.run_bzr_error(["empty commit message"],
746
"commit tree/hello.txt", stdin="n\n")
747
self.assertEqual(expected, tree.last_revision())
749
def test_commit_without_username(self):
750
"""Ensure commit error if username is not set.
752
self.run_bzr(['init', 'foo'])
754
open('foo.txt', 'w').write('hello')
755
self.run_bzr(['add'])
756
osutils.set_or_unset_env('EMAIL', None)
757
osutils.set_or_unset_env('BZR_EMAIL', None)
758
out, err = self.run_bzr(['commit', '-m', 'initial'], 3)
759
self.assertContainsRe(err, 'Unable to determine your name')