/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/blackbox/test_commit.py

  • Committer: mernst at mit
  • Date: 2008-10-16 10:57:16 UTC
  • mto: This revision was merged to the branch mainline in revision 3799.
  • Revision ID: mernst@csail.mit.edu-20081016105716-v8x8n5t2pf7f6uds
Improved documentation of stacked and lightweight branches

These patches improve the User Guide's documentation of stacked and
lightweight branches.

Section "1.2.6 Putting the concepts together" should mention stacked
branches and the difference between them and lightweight branches.  It
should also contain links to further details of the common scenarios.

Section "5.3.4 Getting a lightweight checkout" should mention stacked
branches as an option, and should link to all the options, not just some of
them.  It should also clarify that lightweight only applies to checkouts,
not to arbitrary branches.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
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
 
16
 
 
17
 
 
18
"""Tests for the commit CLI of bzr."""
 
19
 
 
20
import os
 
21
import sys
 
22
 
 
23
from bzrlib import (
 
24
    osutils,
 
25
    ignores,
 
26
    osutils,
 
27
    )
 
28
from bzrlib.bzrdir import BzrDir
 
29
from bzrlib.tests import (
 
30
    probe_bad_non_ascii,
 
31
    TestSkipped,
 
32
    )
 
33
from bzrlib.tests.blackbox import ExternalBase
 
34
 
 
35
 
 
36
class TestCommit(ExternalBase):
 
37
 
 
38
    def test_05_empty_commit(self):
 
39
        """Commit of tree with no versioned files should fail"""
 
40
        # If forced, it should succeed, but this is not tested here.
 
41
        self.make_branch_and_tree('.')
 
42
        self.build_tree(['hello.txt'])
 
43
        out,err = self.run_bzr('commit -m empty', retcode=3)
 
44
        self.assertEqual('', out)
 
45
        self.assertContainsRe(err, 'bzr: ERROR: no changes to commit\.'
 
46
                                  ' use --unchanged to commit anyhow\n')
 
47
 
 
48
    def test_commit_success(self):
 
49
        """Successful commit should not leave behind a bzr-commit-* file"""
 
50
        self.make_branch_and_tree('.')
 
51
        self.run_bzr('commit --unchanged -m message')
 
52
        self.assertEqual('', self.run_bzr('unknowns')[0])
 
53
 
 
54
        # same for unicode messages
 
55
        self.run_bzr(["commit", "--unchanged", "-m", u'foo\xb5'])
 
56
        self.assertEqual('', self.run_bzr('unknowns')[0])
 
57
 
 
58
    def test_commit_with_path(self):
 
59
        """Commit tree with path of root specified"""
 
60
        a_tree = self.make_branch_and_tree('a')
 
61
        self.build_tree(['a/a_file'])
 
62
        a_tree.add('a_file')
 
63
        self.run_bzr(['commit', '-m', 'first commit', 'a'])
 
64
 
 
65
        b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
 
66
        self.build_tree_contents([('b/a_file', 'changes in b')])
 
67
        self.run_bzr(['commit', '-m', 'first commit in b', 'b'])
 
68
 
 
69
        self.build_tree_contents([('a/a_file', 'new contents')])
 
70
        self.run_bzr(['commit', '-m', 'change in a', 'a'])
 
71
 
 
72
        b_tree.merge_from_branch(a_tree.branch)
 
73
        self.assertEqual(len(b_tree.conflicts()), 1)
 
74
        self.run_bzr('resolved b/a_file')
 
75
        self.run_bzr(['commit', '-m', 'merge into b', 'b'])
 
76
 
 
77
 
 
78
    def test_10_verbose_commit(self):
 
79
        """Add one file and examine verbose commit output"""
 
80
        tree = self.make_branch_and_tree('.')
 
81
        self.build_tree(['hello.txt'])
 
82
        tree.add("hello.txt")
 
83
        out,err = self.run_bzr('commit -m added')
 
84
        self.assertEqual('', out)
 
85
        self.assertContainsRe(err, '^Committing to: .*\n'
 
86
                              'added hello.txt\n'
 
87
                              'Committed revision 1.\n$',)
 
88
 
 
89
    def prepare_simple_history(self):
 
90
        """Prepare and return a working tree with one commit of one file"""
 
91
        # Commit with modified file should say so
 
92
        wt = BzrDir.create_standalone_workingtree('.')
 
93
        self.build_tree(['hello.txt', 'extra.txt'])
 
94
        wt.add(['hello.txt'])
 
95
        wt.commit(message='added')
 
96
        return wt
 
97
 
 
98
    def test_verbose_commit_modified(self):
 
99
        # Verbose commit of modified file should say so
 
100
        wt = self.prepare_simple_history()
 
101
        self.build_tree_contents([('hello.txt', 'new contents')])
 
102
        out, err = self.run_bzr('commit -m modified')
 
103
        self.assertEqual('', out)
 
104
        self.assertContainsRe(err, '^Committing to: .*\n'
 
105
                              'modified hello\.txt\n'
 
106
                              'Committed revision 2\.\n$')
 
107
 
 
108
    def test_verbose_commit_renamed(self):
 
109
        # Verbose commit of renamed file should say so
 
110
        wt = self.prepare_simple_history()
 
111
        wt.rename_one('hello.txt', 'gutentag.txt')
 
112
        out, err = self.run_bzr('commit -m renamed')
 
113
        self.assertEqual('', out)
 
114
        self.assertContainsRe(err, '^Committing to: .*\n'
 
115
                              'renamed hello\.txt => gutentag\.txt\n'
 
116
                              'Committed revision 2\.$\n')
 
117
 
 
118
    def test_verbose_commit_moved(self):
 
119
        # Verbose commit of file moved to new directory should say so
 
120
        wt = self.prepare_simple_history()
 
121
        os.mkdir('subdir')
 
122
        wt.add(['subdir'])
 
123
        wt.rename_one('hello.txt', 'subdir/hello.txt')
 
124
        out, err = self.run_bzr('commit -m renamed')
 
125
        self.assertEqual('', out)
 
126
        self.assertContainsRe(err, '^Committing to: .*\n'
 
127
                              'added subdir\n'
 
128
                              'renamed hello\.txt => subdir/hello\.txt\n'
 
129
                              'Committed revision 2\.\n$')
 
130
 
 
131
    def test_verbose_commit_with_unknown(self):
 
132
        """Unknown files should not be listed by default in verbose output"""
 
133
        # Is that really the best policy?
 
134
        wt = BzrDir.create_standalone_workingtree('.')
 
135
        self.build_tree(['hello.txt', 'extra.txt'])
 
136
        wt.add(['hello.txt'])
 
137
        out,err = self.run_bzr('commit -m added')
 
138
        self.assertEqual('', out)
 
139
        self.assertContainsRe(err, '^Committing to: .*\n'
 
140
                              'added hello\.txt\n'
 
141
                              'Committed revision 1\.\n$')
 
142
 
 
143
    def test_verbose_commit_with_unchanged(self):
 
144
        """Unchanged files should not be listed by default in verbose output"""
 
145
        tree = self.make_branch_and_tree('.')
 
146
        self.build_tree(['hello.txt', 'unchanged.txt'])
 
147
        tree.add('unchanged.txt')
 
148
        self.run_bzr('commit -m unchanged unchanged.txt')
 
149
        tree.add("hello.txt")
 
150
        out,err = self.run_bzr('commit -m added')
 
151
        self.assertEqual('', out)
 
152
        self.assertContainsRe(err, '^Committing to: .*\n'
 
153
                              'added hello\.txt\n'
 
154
                              'Committed revision 2\.$\n')
 
155
 
 
156
    def test_verbose_commit_includes_master_location(self):
 
157
        """Location of master is displayed when committing to bound branch"""
 
158
        a_tree = self.make_branch_and_tree('a')
 
159
        self.build_tree(['a/b'])
 
160
        a_tree.add('b')
 
161
        a_tree.commit(message='Initial message')
 
162
 
 
163
        b_tree = a_tree.branch.create_checkout('b')
 
164
        expected = "%s/" % (osutils.abspath('a'), )
 
165
        out, err = self.run_bzr('commit -m blah --unchanged', working_dir='b')
 
166
        self.assertEqual(err, 'Committing to: %s\n'
 
167
                         'Committed revision 2.\n' % expected)
 
168
 
 
169
    def test_commit_merge_reports_all_modified_files(self):
 
170
        # the commit command should show all the files that are shown by
 
171
        # bzr diff or bzr status when committing, even when they were not
 
172
        # changed by the user but rather through doing a merge.
 
173
        this_tree = self.make_branch_and_tree('this')
 
174
        # we need a bunch of files and dirs, to perform one action on each.
 
175
        self.build_tree([
 
176
            'this/dirtorename/',
 
177
            'this/dirtoreparent/',
 
178
            'this/dirtoleave/',
 
179
            'this/dirtoremove/',
 
180
            'this/filetoreparent',
 
181
            'this/filetorename',
 
182
            'this/filetomodify',
 
183
            'this/filetoremove',
 
184
            'this/filetoleave']
 
185
            )
 
186
        this_tree.add([
 
187
            'dirtorename',
 
188
            'dirtoreparent',
 
189
            'dirtoleave',
 
190
            'dirtoremove',
 
191
            'filetoreparent',
 
192
            'filetorename',
 
193
            'filetomodify',
 
194
            'filetoremove',
 
195
            'filetoleave']
 
196
            )
 
197
        this_tree.commit('create_files')
 
198
        other_dir = this_tree.bzrdir.sprout('other')
 
199
        other_tree = other_dir.open_workingtree()
 
200
        other_tree.lock_write()
 
201
        # perform the needed actions on the files and dirs.
 
202
        try:
 
203
            other_tree.rename_one('dirtorename', 'renameddir')
 
204
            other_tree.rename_one('dirtoreparent', 'renameddir/reparenteddir')
 
205
            other_tree.rename_one('filetorename', 'renamedfile')
 
206
            other_tree.rename_one('filetoreparent',
 
207
                                  'renameddir/reparentedfile')
 
208
            other_tree.remove(['dirtoremove', 'filetoremove'])
 
209
            self.build_tree_contents([
 
210
                ('other/newdir/',),
 
211
                ('other/filetomodify', 'new content'),
 
212
                ('other/newfile', 'new file content')])
 
213
            other_tree.add('newfile')
 
214
            other_tree.add('newdir/')
 
215
            other_tree.commit('modify all sample files and dirs.')
 
216
        finally:
 
217
            other_tree.unlock()
 
218
        this_tree.merge_from_branch(other_tree.branch)
 
219
        os.chdir('this')
 
220
        out,err = self.run_bzr('commit -m added')
 
221
        self.assertEqual('', out)
 
222
        expected = '%s/' % (osutils.getcwd(), )
 
223
        self.assertEqualDiff(
 
224
            'Committing to: %s\n'
 
225
            'modified filetomodify\n'
 
226
            'added newdir\n'
 
227
            'added newfile\n'
 
228
            'renamed dirtorename => renameddir\n'
 
229
            'renamed filetorename => renamedfile\n'
 
230
            'renamed dirtoreparent => renameddir/reparenteddir\n'
 
231
            'renamed filetoreparent => renameddir/reparentedfile\n'
 
232
            'deleted dirtoremove\n'
 
233
            'deleted filetoremove\n'
 
234
            'Committed revision 2.\n' % (expected, ),
 
235
            err)
 
236
 
 
237
    def test_empty_commit_message(self):
 
238
        tree = self.make_branch_and_tree('.')
 
239
        self.build_tree_contents([('foo.c', 'int main() {}')])
 
240
        tree.add('foo.c')
 
241
        self.run_bzr('commit -m ""', retcode=3)
 
242
 
 
243
    def test_unsupported_encoding_commit_message(self):
 
244
        tree = self.make_branch_and_tree('.')
 
245
        self.build_tree_contents([('foo.c', 'int main() {}')])
 
246
        tree.add('foo.c')
 
247
        # LANG env variable has no effect on Windows
 
248
        # but some characters anyway cannot be represented
 
249
        # in default user encoding
 
250
        char = probe_bad_non_ascii(osutils.get_user_encoding())
 
251
        if char is None:
 
252
            raise TestSkipped('Cannot find suitable non-ascii character'
 
253
                'for user_encoding (%s)' % osutils.get_user_encoding())
 
254
        out,err = self.run_bzr_subprocess('commit -m "%s"' % char,
 
255
                                          retcode=1,
 
256
                                          env_changes={'LANG': 'C'})
 
257
        self.assertContainsRe(err, r'bzrlib.errors.BzrError: Parameter.*is '
 
258
                                    'unsupported by the current encoding.')
 
259
 
 
260
    def test_other_branch_commit(self):
 
261
        # this branch is to ensure consistent behaviour, whether we're run
 
262
        # inside a branch, or not.
 
263
        outer_tree = self.make_branch_and_tree('.')
 
264
        inner_tree = self.make_branch_and_tree('branch')
 
265
        self.build_tree_contents([
 
266
            ('branch/foo.c', 'int main() {}'),
 
267
            ('branch/bar.c', 'int main() {}')])
 
268
        inner_tree.add('foo.c')
 
269
        inner_tree.add('bar.c')
 
270
        # can't commit files in different trees; sane error
 
271
        self.run_bzr('commit -m newstuff branch/foo.c .', retcode=3)
 
272
        self.run_bzr('commit -m newstuff branch/foo.c')
 
273
        self.run_bzr('commit -m newstuff branch')
 
274
        self.run_bzr('commit -m newstuff branch', retcode=3)
 
275
 
 
276
    def test_out_of_date_tree_commit(self):
 
277
        # check we get an error code and a clear message committing with an out
 
278
        # of date checkout
 
279
        tree = self.make_branch_and_tree('branch')
 
280
        # make a checkout
 
281
        checkout = tree.branch.create_checkout('checkout', lightweight=True)
 
282
        # commit to the original branch to make the checkout out of date
 
283
        tree.commit('message branch', allow_pointless=True)
 
284
        # now commit to the checkout should emit
 
285
        # ERROR: Out of date with the branch, 'bzr update' is suggested
 
286
        output = self.run_bzr('commit --unchanged -m checkout_message '
 
287
                             'checkout', retcode=3)
 
288
        self.assertEqual(output,
 
289
                         ('',
 
290
                          "bzr: ERROR: Working tree is out of date, please "
 
291
                          "run 'bzr update'.\n"))
 
292
 
 
293
    def test_local_commit_unbound(self):
 
294
        # a --local commit on an unbound branch is an error
 
295
        self.make_branch_and_tree('.')
 
296
        out, err = self.run_bzr('commit --local', retcode=3)
 
297
        self.assertEqualDiff('', out)
 
298
        self.assertEqualDiff('bzr: ERROR: Cannot perform local-only commits '
 
299
                             'on unbound branches.\n', err)
 
300
 
 
301
    def test_commit_a_text_merge_in_a_checkout(self):
 
302
        # checkouts perform multiple actions in a transaction across bond
 
303
        # branches and their master, and have been observed to fail in the
 
304
        # past. This is a user story reported to fail in bug #43959 where 
 
305
        # a merge done in a checkout (using the update command) failed to
 
306
        # commit correctly.
 
307
        trunk = self.make_branch_and_tree('trunk')
 
308
 
 
309
        u1 = trunk.branch.create_checkout('u1')
 
310
        self.build_tree_contents([('u1/hosts', 'initial contents')])
 
311
        u1.add('hosts')
 
312
        self.run_bzr('commit -m add-hosts u1')
 
313
 
 
314
        u2 = trunk.branch.create_checkout('u2')
 
315
        self.build_tree_contents([('u2/hosts', 'altered in u2')])
 
316
        self.run_bzr('commit -m checkin-from-u2 u2')
 
317
 
 
318
        # make an offline commits
 
319
        self.build_tree_contents([('u1/hosts', 'first offline change in u1')])
 
320
        self.run_bzr('commit -m checkin-offline --local u1')
 
321
 
 
322
        # now try to pull in online work from u2, and then commit our offline
 
323
        # work as a merge
 
324
        # retcode 1 as we expect a text conflict
 
325
        self.run_bzr('update u1', retcode=1)
 
326
        self.run_bzr('resolved u1/hosts')
 
327
        # add a text change here to represent resolving the merge conflicts in
 
328
        # favour of a new version of the file not identical to either the u1
 
329
        # version or the u2 version.
 
330
        self.build_tree_contents([('u1/hosts', 'merge resolution\n')])
 
331
        self.run_bzr('commit -m checkin-merge-of-the-offline-work-from-u1 u1')
 
332
 
 
333
    def test_commit_exclude_excludes_modified_files(self):
 
334
        """Commit -x foo should ignore changes to foo."""
 
335
        tree = self.make_branch_and_tree('.')
 
336
        self.build_tree(['a', 'b', 'c'])
 
337
        tree.smart_add(['.'])
 
338
        out, err = self.run_bzr(['commit', '-m', 'test', '-x', 'b'])
 
339
        self.assertFalse('added b' in out)
 
340
        self.assertFalse('added b' in err)
 
341
        # If b was excluded it will still be 'added' in status.
 
342
        out, err = self.run_bzr(['added'])
 
343
        self.assertEqual('b\n', out)
 
344
        self.assertEqual('', err)
 
345
 
 
346
    def test_commit_exclude_twice_uses_both_rules(self):
 
347
        """Commit -x foo -x bar should ignore changes to foo and bar."""
 
348
        tree = self.make_branch_and_tree('.')
 
349
        self.build_tree(['a', 'b', 'c'])
 
350
        tree.smart_add(['.'])
 
351
        out, err = self.run_bzr(['commit', '-m', 'test', '-x', 'b', '-x', 'c'])
 
352
        self.assertFalse('added b' in out)
 
353
        self.assertFalse('added c' in out)
 
354
        self.assertFalse('added b' in err)
 
355
        self.assertFalse('added c' in err)
 
356
        # If b was excluded it will still be 'added' in status.
 
357
        out, err = self.run_bzr(['added'])
 
358
        self.assertTrue('b\n' in out)
 
359
        self.assertTrue('c\n' in out)
 
360
        self.assertEqual('', err)
 
361
 
 
362
    def test_commit_respects_spec_for_removals(self):
 
363
        """Commit with a file spec should only commit removals that match"""
 
364
        t = self.make_branch_and_tree('.')
 
365
        self.build_tree(['file-a', 'dir-a/', 'dir-a/file-b'])
 
366
        t.add(['file-a', 'dir-a', 'dir-a/file-b'])
 
367
        t.commit('Create')
 
368
        t.remove(['file-a', 'dir-a/file-b'])
 
369
        os.chdir('dir-a')
 
370
        result = self.run_bzr('commit . -m removed-file-b')[1]
 
371
        self.assertNotContainsRe(result, 'file-a')
 
372
        result = self.run_bzr('status')[0]
 
373
        self.assertContainsRe(result, 'removed:\n  file-a')
 
374
 
 
375
    def test_strict_commit(self):
 
376
        """Commit with --strict works if everything is known"""
 
377
        ignores._set_user_ignores([])
 
378
        tree = self.make_branch_and_tree('tree')
 
379
        self.build_tree(['tree/a'])
 
380
        tree.add('a')
 
381
        # A simple change should just work
 
382
        self.run_bzr('commit --strict -m adding-a',
 
383
                     working_dir='tree')
 
384
 
 
385
    def test_strict_commit_no_changes(self):
 
386
        """commit --strict gives "no changes" if there is nothing to commit"""
 
387
        tree = self.make_branch_and_tree('tree')
 
388
        self.build_tree(['tree/a'])
 
389
        tree.add('a')
 
390
        tree.commit('adding a')
 
391
 
 
392
        # With no changes, it should just be 'no changes'
 
393
        # Make sure that commit is failing because there is nothing to do
 
394
        self.run_bzr_error(['no changes to commit'],
 
395
                           'commit --strict -m no-changes',
 
396
                           working_dir='tree')
 
397
 
 
398
        # But --strict doesn't care if you supply --unchanged
 
399
        self.run_bzr('commit --strict --unchanged -m no-changes',
 
400
                     working_dir='tree')
 
401
 
 
402
    def test_strict_commit_unknown(self):
 
403
        """commit --strict fails if a file is unknown"""
 
404
        tree = self.make_branch_and_tree('tree')
 
405
        self.build_tree(['tree/a'])
 
406
        tree.add('a')
 
407
        tree.commit('adding a')
 
408
 
 
409
        # Add one file so there is a change, but forget the other
 
410
        self.build_tree(['tree/b', 'tree/c'])
 
411
        tree.add('b')
 
412
        self.run_bzr_error(['Commit refused because there are unknown files'],
 
413
                           'commit --strict -m add-b',
 
414
                           working_dir='tree')
 
415
 
 
416
        # --no-strict overrides --strict
 
417
        self.run_bzr('commit --strict -m add-b --no-strict',
 
418
                     working_dir='tree')
 
419
 
 
420
    def test_fixes_bug_output(self):
 
421
        """commit --fixes=lp:23452 succeeds without output."""
 
422
        tree = self.make_branch_and_tree('tree')
 
423
        self.build_tree(['tree/hello.txt'])
 
424
        tree.add('hello.txt')
 
425
        output, err = self.run_bzr(
 
426
            'commit -m hello --fixes=lp:23452 tree/hello.txt')
 
427
        self.assertEqual('', output)
 
428
        self.assertContainsRe(err, 'Committing to: .*\n'
 
429
                              'added hello\.txt\n'
 
430
                              'Committed revision 1\.\n')
 
431
 
 
432
    def test_no_bugs_no_properties(self):
 
433
        """If no bugs are fixed, the bugs property is not set.
 
434
 
 
435
        see https://beta.launchpad.net/bzr/+bug/109613
 
436
        """
 
437
        tree = self.make_branch_and_tree('tree')
 
438
        self.build_tree(['tree/hello.txt'])
 
439
        tree.add('hello.txt')
 
440
        self.run_bzr( 'commit -m hello tree/hello.txt')
 
441
        # Get the revision properties, ignoring the branch-nick property, which
 
442
        # we don't care about for this test.
 
443
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
444
        properties = dict(last_rev.properties)
 
445
        del properties['branch-nick']
 
446
        self.assertFalse('bugs' in properties)
 
447
 
 
448
    def test_fixes_bug_sets_property(self):
 
449
        """commit --fixes=lp:234 sets the lp:234 revprop to 'fixed'."""
 
450
        tree = self.make_branch_and_tree('tree')
 
451
        self.build_tree(['tree/hello.txt'])
 
452
        tree.add('hello.txt')
 
453
        self.run_bzr('commit -m hello --fixes=lp:234 tree/hello.txt')
 
454
 
 
455
        # Get the revision properties, ignoring the branch-nick property, which
 
456
        # we don't care about for this test.
 
457
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
458
        properties = dict(last_rev.properties)
 
459
        del properties['branch-nick']
 
460
 
 
461
        self.assertEqual({'bugs': 'https://launchpad.net/bugs/234 fixed'},
 
462
                         properties)
 
463
 
 
464
    def test_fixes_multiple_bugs_sets_properties(self):
 
465
        """--fixes can be used more than once to show that bugs are fixed."""
 
466
        tree = self.make_branch_and_tree('tree')
 
467
        self.build_tree(['tree/hello.txt'])
 
468
        tree.add('hello.txt')
 
469
        self.run_bzr('commit -m hello --fixes=lp:123 --fixes=lp:235'
 
470
                     ' tree/hello.txt')
 
471
 
 
472
        # Get the revision properties, ignoring the branch-nick property, which
 
473
        # we don't care about for this test.
 
474
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
475
        properties = dict(last_rev.properties)
 
476
        del properties['branch-nick']
 
477
 
 
478
        self.assertEqual(
 
479
            {'bugs': 'https://launchpad.net/bugs/123 fixed\n'
 
480
                     'https://launchpad.net/bugs/235 fixed'},
 
481
            properties)
 
482
 
 
483
    def test_fixes_bug_with_alternate_trackers(self):
 
484
        """--fixes can be used on a properly configured branch to mark bug
 
485
        fixes on multiple trackers.
 
486
        """
 
487
        tree = self.make_branch_and_tree('tree')
 
488
        tree.branch.get_config().set_user_option(
 
489
            'trac_twisted_url', 'http://twistedmatrix.com/trac')
 
490
        self.build_tree(['tree/hello.txt'])
 
491
        tree.add('hello.txt')
 
492
        self.run_bzr('commit -m hello --fixes=lp:123 --fixes=twisted:235 tree/')
 
493
 
 
494
        # Get the revision properties, ignoring the branch-nick property, which
 
495
        # we don't care about for this test.
 
496
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
497
        properties = dict(last_rev.properties)
 
498
        del properties['branch-nick']
 
499
 
 
500
        self.assertEqual(
 
501
            {'bugs': 'https://launchpad.net/bugs/123 fixed\n'
 
502
                     'http://twistedmatrix.com/trac/ticket/235 fixed'},
 
503
            properties)
 
504
 
 
505
    def test_fixes_unknown_bug_prefix(self):
 
506
        tree = self.make_branch_and_tree('tree')
 
507
        self.build_tree(['tree/hello.txt'])
 
508
        tree.add('hello.txt')
 
509
        self.run_bzr_error(
 
510
            ["Unrecognized bug %s. Commit refused." % 'xxx:123'],
 
511
            'commit -m add-b --fixes=xxx:123',
 
512
            working_dir='tree')
 
513
 
 
514
    def test_fixes_invalid_bug_number(self):
 
515
        tree = self.make_branch_and_tree('tree')
 
516
        self.build_tree(['tree/hello.txt'])
 
517
        tree.add('hello.txt')
 
518
        self.run_bzr_error(
 
519
            ["Invalid bug identifier for %s. Commit refused." % 'lp:orange'],
 
520
            'commit -m add-b --fixes=lp:orange',
 
521
            working_dir='tree')
 
522
 
 
523
    def test_fixes_invalid_argument(self):
 
524
        """Raise an appropriate error when the fixes argument isn't tag:id."""
 
525
        tree = self.make_branch_and_tree('tree')
 
526
        self.build_tree(['tree/hello.txt'])
 
527
        tree.add('hello.txt')
 
528
        self.run_bzr_error(
 
529
            [r"Invalid bug orange. Must be in the form of 'tag:id'\. "
 
530
             r"Commit refused\."],
 
531
            'commit -m add-b --fixes=orange',
 
532
            working_dir='tree')
 
533
 
 
534
    def test_no_author(self):
 
535
        """If the author is not specified, the author property is not set."""
 
536
        tree = self.make_branch_and_tree('tree')
 
537
        self.build_tree(['tree/hello.txt'])
 
538
        tree.add('hello.txt')
 
539
        self.run_bzr( 'commit -m hello tree/hello.txt')
 
540
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
541
        properties = last_rev.properties
 
542
        self.assertFalse('author' in properties)
 
543
 
 
544
    def test_author_sets_property(self):
 
545
        """commit --author='John Doe <jdoe@example.com>' sets the author
 
546
           revprop.
 
547
        """
 
548
        tree = self.make_branch_and_tree('tree')
 
549
        self.build_tree(['tree/hello.txt'])
 
550
        tree.add('hello.txt')
 
551
        self.run_bzr(["commit", '-m', 'hello',
 
552
                      '--author', u'John D\xf6 <jdoe@example.com>',
 
553
                     "tree/hello.txt"])
 
554
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
555
        properties = last_rev.properties
 
556
        self.assertEqual(u'John D\xf6 <jdoe@example.com>', properties['author'])
 
557
 
 
558
    def test_author_no_email(self):
 
559
        """Author's name without an email address is allowed, too."""
 
560
        tree = self.make_branch_and_tree('tree')
 
561
        self.build_tree(['tree/hello.txt'])
 
562
        tree.add('hello.txt')
 
563
        out, err = self.run_bzr("commit -m hello --author='John Doe' "
 
564
                                "tree/hello.txt")
 
565
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
566
        properties = last_rev.properties
 
567
        self.assertEqual('John Doe', properties['author'])
 
568
 
 
569
    def test_partial_commit_with_renames_in_tree(self):
 
570
        # this test illustrates bug #140419
 
571
        t = self.make_branch_and_tree('.')
 
572
        self.build_tree(['dir/', 'dir/a', 'test'])
 
573
        t.add(['dir/', 'dir/a', 'test'])
 
574
        t.commit('initial commit')
 
575
        # important part: file dir/a should change parent
 
576
        # and should appear before old parent
 
577
        # then during partial commit we have error
 
578
        # parent_id {dir-XXX} not in inventory
 
579
        t.rename_one('dir/a', 'a')
 
580
        self.build_tree_contents([('test', 'changes in test')])
 
581
        # partial commit
 
582
        out, err = self.run_bzr('commit test -m "partial commit"')
 
583
        self.assertEquals('', out)
 
584
        self.assertContainsRe(err, r'modified test\nCommitted revision 2.')
 
585
 
 
586
    def test_commit_readonly_checkout(self):
 
587
        # https://bugs.edge.launchpad.net/bzr/+bug/129701
 
588
        # "UnlockableTransport error trying to commit in checkout of readonly
 
589
        # branch"
 
590
        self.make_branch('master')
 
591
        master = BzrDir.open_from_transport(
 
592
            self.get_readonly_transport('master')).open_branch()
 
593
        master.create_checkout('checkout')
 
594
        out, err = self.run_bzr(['commit', '--unchanged', '-mfoo', 'checkout'],
 
595
            retcode=3)
 
596
        self.assertContainsRe(err,
 
597
            r'^bzr: ERROR: Cannot lock.*readonly transport')