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