/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 breezy/tests/blackbox/test_commit.py

  • Committer: Martin
  • Date: 2018-11-16 16:38:22 UTC
  • mto: This revision was merged to the branch mainline in revision 7172.
  • Revision ID: gzlist@googlemail.com-20181116163822-yg1h1cdng6w7w9kn
Make --profile-imports work on Python 3

Also tweak heading to line up correctly.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2012, 2016 Canonical Ltd
2
2
#
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
17
17
 
18
18
"""Tests for the commit CLI of bzr."""
19
19
 
 
20
import doctest
20
21
import os
 
22
import re
21
23
import sys
22
24
 
23
 
from bzrlib import (
 
25
from testtools.matchers import DocTestMatches
 
26
 
 
27
from ... import (
 
28
    config,
24
29
    osutils,
25
30
    ignores,
26
31
    msgeditor,
27
 
    osutils,
28
 
    tests,
29
 
    )
30
 
from bzrlib.bzrdir import BzrDir
31
 
from bzrlib.tests import (
32
 
    probe_bad_non_ascii,
33
 
    TestSkipped,
34
 
    )
35
 
from bzrlib.tests.blackbox import ExternalBase
36
 
 
37
 
 
38
 
class TestCommit(ExternalBase):
 
32
    )
 
33
from ...controldir import ControlDir
 
34
from ...sixish import PY3
 
35
from .. import (
 
36
    test_foreign,
 
37
    features,
 
38
    )
 
39
from .. import TestCaseWithTransport
 
40
from ..matchers import ContainsNoVfsCalls
 
41
 
 
42
 
 
43
class TestCommit(TestCaseWithTransport):
39
44
 
40
45
    def test_05_empty_commit(self):
41
46
        """Commit of tree with no versioned files should fail"""
42
47
        # If forced, it should succeed, but this is not tested here.
43
48
        self.make_branch_and_tree('.')
44
49
        self.build_tree(['hello.txt'])
45
 
        out,err = self.run_bzr('commit -m empty', retcode=3)
 
50
        out, err = self.run_bzr('commit -m empty', retcode=3)
46
51
        self.assertEqual('', out)
47
 
        self.assertContainsRe(err, 'bzr: ERROR: No changes to commit\.'
48
 
                                  ' Use --unchanged to commit anyhow.\n')
 
52
        # Two ugly bits here.
 
53
        # 1) We really don't want 'aborting commit write group' anymore.
 
54
        # 2) brz: ERROR: is a really long line, so we wrap it with '\'
 
55
        self.assertThat(
 
56
            err,
 
57
            DocTestMatches("""\
 
58
Committing to: ...
 
59
brz: ERROR: No changes to commit.\
 
60
 Please 'brz add' the files you want to commit,\
 
61
 or use --unchanged to force an empty commit.
 
62
""", flags=doctest.ELLIPSIS|doctest.REPORT_UDIFF))
49
63
 
50
64
    def test_commit_success(self):
51
65
        """Successful commit should not leave behind a bzr-commit-* file"""
57
71
        self.run_bzr(["commit", "--unchanged", "-m", u'foo\xb5'])
58
72
        self.assertEqual('', self.run_bzr('unknowns')[0])
59
73
 
 
74
    def test_commit_lossy_native(self):
 
75
        """A --lossy option to commit is supported."""
 
76
        self.make_branch_and_tree('.')
 
77
        self.run_bzr('commit --lossy --unchanged -m message')
 
78
        self.assertEqual('', self.run_bzr('unknowns')[0])
 
79
 
 
80
    def test_commit_lossy_foreign(self):
 
81
        test_foreign.register_dummy_foreign_for_test(self)
 
82
        self.make_branch_and_tree('.',
 
83
            format=test_foreign.DummyForeignVcsDirFormat())
 
84
        self.run_bzr('commit --lossy --unchanged -m message')
 
85
        output = self.run_bzr('revision-info')[0]
 
86
        self.assertTrue(output.startswith('1 dummy-'))
 
87
 
60
88
    def test_commit_with_path(self):
61
89
        """Commit tree with path of root specified"""
62
90
        a_tree = self.make_branch_and_tree('a')
64
92
        a_tree.add('a_file')
65
93
        self.run_bzr(['commit', '-m', 'first commit', 'a'])
66
94
 
67
 
        b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
68
 
        self.build_tree_contents([('b/a_file', 'changes in b')])
 
95
        b_tree = a_tree.controldir.sprout('b').open_workingtree()
 
96
        self.build_tree_contents([('b/a_file', b'changes in b')])
69
97
        self.run_bzr(['commit', '-m', 'first commit in b', 'b'])
70
98
 
71
 
        self.build_tree_contents([('a/a_file', 'new contents')])
 
99
        self.build_tree_contents([('a/a_file', b'new contents')])
72
100
        self.run_bzr(['commit', '-m', 'change in a', 'a'])
73
101
 
74
102
        b_tree.merge_from_branch(a_tree.branch)
76
104
        self.run_bzr('resolved b/a_file')
77
105
        self.run_bzr(['commit', '-m', 'merge into b', 'b'])
78
106
 
79
 
 
80
107
    def test_10_verbose_commit(self):
81
108
        """Add one file and examine verbose commit output"""
82
109
        tree = self.make_branch_and_tree('.')
83
110
        self.build_tree(['hello.txt'])
84
111
        tree.add("hello.txt")
85
 
        out,err = self.run_bzr('commit -m added')
 
112
        out, err = self.run_bzr('commit -m added')
86
113
        self.assertEqual('', out)
87
114
        self.assertContainsRe(err, '^Committing to: .*\n'
88
115
                              'added hello.txt\n'
91
118
    def prepare_simple_history(self):
92
119
        """Prepare and return a working tree with one commit of one file"""
93
120
        # Commit with modified file should say so
94
 
        wt = BzrDir.create_standalone_workingtree('.')
 
121
        wt = ControlDir.create_standalone_workingtree('.')
95
122
        self.build_tree(['hello.txt', 'extra.txt'])
96
123
        wt.add(['hello.txt'])
97
124
        wt.commit(message='added')
100
127
    def test_verbose_commit_modified(self):
101
128
        # Verbose commit of modified file should say so
102
129
        wt = self.prepare_simple_history()
103
 
        self.build_tree_contents([('hello.txt', 'new contents')])
 
130
        self.build_tree_contents([('hello.txt', b'new contents')])
104
131
        out, err = self.run_bzr('commit -m modified')
105
132
        self.assertEqual('', out)
106
133
        self.assertContainsRe(err, '^Committing to: .*\n'
107
 
                              'modified hello\.txt\n'
108
 
                              'Committed revision 2\.\n$')
 
134
                              'modified hello\\.txt\n'
 
135
                              'Committed revision 2\\.\n$')
 
136
 
 
137
    def test_unicode_commit_message_is_filename(self):
 
138
        """Unicode commit message same as a filename (Bug #563646).
 
139
        """
 
140
        self.requireFeature(features.UnicodeFilenameFeature)
 
141
        file_name = u'\N{euro sign}'
 
142
        self.run_bzr(['init'])
 
143
        with open(file_name, 'w') as f:
 
144
            f.write('hello world')
 
145
        self.run_bzr(['add'])
 
146
        out, err = self.run_bzr(['commit', '-m', file_name])
 
147
        reflags = re.MULTILINE|re.DOTALL|re.UNICODE
 
148
        te = osutils.get_terminal_encoding()
 
149
        self.assertContainsRe(err if PY3 else err.decode(te),
 
150
            u'The commit message is a file name:',
 
151
            flags=reflags)
 
152
 
 
153
        # Run same test with a filename that causes encode
 
154
        # error for the terminal encoding. We do this
 
155
        # by forcing terminal encoding of ascii for
 
156
        # osutils.get_terminal_encoding which is used
 
157
        # by ui.text.show_warning
 
158
        default_get_terminal_enc = osutils.get_terminal_encoding
 
159
        try:
 
160
            osutils.get_terminal_encoding = lambda trace=None: 'ascii'
 
161
            file_name = u'foo\u1234'
 
162
            with open(file_name, 'w') as f:
 
163
                f.write('hello world')
 
164
            self.run_bzr(['add'])
 
165
            out, err = self.run_bzr(['commit', '-m', file_name])
 
166
            reflags = re.MULTILINE|re.DOTALL|re.UNICODE
 
167
            te = osutils.get_terminal_encoding()
 
168
            self.assertContainsRe(err if PY3 else err.decode(te, 'replace'),
 
169
                u'The commit message is a file name:',
 
170
                flags=reflags)
 
171
        finally:
 
172
            osutils.get_terminal_encoding = default_get_terminal_enc
 
173
 
 
174
    def test_non_ascii_file_unversioned_utf8(self):
 
175
        self.requireFeature(features.UnicodeFilenameFeature)
 
176
        tree = self.make_branch_and_tree(".")
 
177
        self.build_tree(["f"])
 
178
        tree.add(["f"])
 
179
        out, err = self.run_bzr_raw(["commit", "-m", "Wrong filename", u"\xa7"],
 
180
            encoding="utf-8", retcode=3)
 
181
        self.assertContainsRe(err, b"(?m)not versioned: \"\xc2\xa7\"$")
 
182
 
 
183
    def test_non_ascii_file_unversioned_iso_8859_5(self):
 
184
        self.requireFeature(features.UnicodeFilenameFeature)
 
185
        tree = self.make_branch_and_tree(".")
 
186
        self.build_tree(["f"])
 
187
        tree.add(["f"])
 
188
        out, err = self.run_bzr_raw(["commit", "-m", "Wrong filename", u"\xa7"],
 
189
            encoding="iso-8859-5", retcode=3)
 
190
        if not PY3:
 
191
            self.expectFailure("Error messages are always written as UTF-8",
 
192
                self.assertNotContainsString, err, b"\xc2\xa7")
 
193
        else:
 
194
            self.assertNotContainsString(err, b"\xc2\xa7")
 
195
        self.assertContainsRe(err, b"(?m)not versioned: \"\xfd\"$")
109
196
 
110
197
    def test_warn_about_forgotten_commit_message(self):
111
198
        """Test that the lack of -m parameter is caught"""
122
209
        out, err = self.run_bzr('commit -m renamed')
123
210
        self.assertEqual('', out)
124
211
        self.assertContainsRe(err, '^Committing to: .*\n'
125
 
                              'renamed hello\.txt => gutentag\.txt\n'
126
 
                              'Committed revision 2\.$\n')
 
212
                              'renamed hello\\.txt => gutentag\\.txt\n'
 
213
                              'Committed revision 2\\.$\n')
127
214
 
128
215
    def test_verbose_commit_moved(self):
129
216
        # Verbose commit of file moved to new directory should say so
133
220
        wt.rename_one('hello.txt', 'subdir/hello.txt')
134
221
        out, err = self.run_bzr('commit -m renamed')
135
222
        self.assertEqual('', out)
136
 
        self.assertEqual(set([
 
223
        self.assertEqual({
137
224
            'Committing to: %s/' % osutils.getcwd(),
138
225
            'added subdir',
139
226
            'renamed hello.txt => subdir/hello.txt',
140
227
            'Committed revision 2.',
141
228
            '',
142
 
            ]), set(err.split('\n')))
 
229
            }, set(err.split('\n')))
143
230
 
144
231
    def test_verbose_commit_with_unknown(self):
145
232
        """Unknown files should not be listed by default in verbose output"""
146
233
        # Is that really the best policy?
147
 
        wt = BzrDir.create_standalone_workingtree('.')
 
234
        wt = ControlDir.create_standalone_workingtree('.')
148
235
        self.build_tree(['hello.txt', 'extra.txt'])
149
236
        wt.add(['hello.txt'])
150
 
        out,err = self.run_bzr('commit -m added')
 
237
        out, err = self.run_bzr('commit -m added')
151
238
        self.assertEqual('', out)
152
239
        self.assertContainsRe(err, '^Committing to: .*\n'
153
 
                              'added hello\.txt\n'
154
 
                              'Committed revision 1\.\n$')
 
240
                              'added hello\\.txt\n'
 
241
                              'Committed revision 1\\.\n$')
155
242
 
156
243
    def test_verbose_commit_with_unchanged(self):
157
244
        """Unchanged files should not be listed by default in verbose output"""
160
247
        tree.add('unchanged.txt')
161
248
        self.run_bzr('commit -m unchanged unchanged.txt')
162
249
        tree.add("hello.txt")
163
 
        out,err = self.run_bzr('commit -m added')
 
250
        out, err = self.run_bzr('commit -m added')
164
251
        self.assertEqual('', out)
165
252
        self.assertContainsRe(err, '^Committing to: .*\n'
166
 
                              'added hello\.txt\n'
167
 
                              'Committed revision 2\.$\n')
 
253
                              'added hello\\.txt\n'
 
254
                              'Committed revision 2\\.$\n')
168
255
 
169
256
    def test_verbose_commit_includes_master_location(self):
170
257
        """Location of master is displayed when committing to bound branch"""
181
268
 
182
269
    def test_commit_sanitizes_CR_in_message(self):
183
270
        # See bug #433779, basically Emacs likes to pass '\r\n' style line
184
 
        # endings to 'bzr commit -m ""' which breaks because we don't allow
 
271
        # endings to 'brz commit -m ""' which breaks because we don't allow
185
272
        # '\r' in commit messages. (Mostly because of issues where XML style
186
273
        # formats arbitrarily strip it out of the data while parsing.)
187
274
        # To make life easier for users, we just always translate '\r\n' =>
199
286
 
200
287
    def test_commit_merge_reports_all_modified_files(self):
201
288
        # the commit command should show all the files that are shown by
202
 
        # bzr diff or bzr status when committing, even when they were not
 
289
        # brz diff or brz status when committing, even when they were not
203
290
        # changed by the user but rather through doing a merge.
204
291
        this_tree = self.make_branch_and_tree('this')
205
292
        # we need a bunch of files and dirs, to perform one action on each.
226
313
            'filetoleave']
227
314
            )
228
315
        this_tree.commit('create_files')
229
 
        other_dir = this_tree.bzrdir.sprout('other')
 
316
        other_dir = this_tree.controldir.sprout('other')
230
317
        other_tree = other_dir.open_workingtree()
231
318
        other_tree.lock_write()
232
319
        # perform the needed actions on the files and dirs.
239
326
            other_tree.remove(['dirtoremove', 'filetoremove'])
240
327
            self.build_tree_contents([
241
328
                ('other/newdir/',),
242
 
                ('other/filetomodify', 'new content'),
243
 
                ('other/newfile', 'new file content')])
 
329
                ('other/filetomodify', b'new content'),
 
330
                ('other/newfile', b'new file content')])
244
331
            other_tree.add('newfile')
245
332
            other_tree.add('newdir/')
246
333
            other_tree.commit('modify all sample files and dirs.')
247
334
        finally:
248
335
            other_tree.unlock()
249
336
        this_tree.merge_from_branch(other_tree.branch)
250
 
        os.chdir('this')
251
 
        out,err = self.run_bzr('commit -m added')
 
337
        out, err = self.run_bzr('commit -m added', working_dir='this')
252
338
        self.assertEqual('', out)
253
 
        self.assertEqual(set([
254
 
            'Committing to: %s/' % osutils.getcwd(),
 
339
        self.assertEqual({
 
340
            'Committing to: %s/' % osutils.pathjoin(osutils.getcwd(), 'this'),
255
341
            'modified filetomodify',
256
342
            'added newdir',
257
343
            'added newfile',
263
349
            'deleted filetoremove',
264
350
            'Committed revision 2.',
265
351
            ''
266
 
            ]), set(err.split('\n')))
 
352
            }, set(err.split('\n')))
267
353
 
268
354
    def test_empty_commit_message(self):
269
355
        tree = self.make_branch_and_tree('.')
270
 
        self.build_tree_contents([('foo.c', 'int main() {}')])
271
 
        tree.add('foo.c')
272
 
        self.run_bzr('commit -m ""', retcode=3)
273
 
 
274
 
    def test_unsupported_encoding_commit_message(self):
275
 
        if sys.platform == 'win32':
276
 
            raise tests.TestNotApplicable('Win32 parses arguments directly'
277
 
                ' as Unicode, so we can\'t pass invalid non-ascii')
278
 
        tree = self.make_branch_and_tree('.')
279
 
        self.build_tree_contents([('foo.c', 'int main() {}')])
280
 
        tree.add('foo.c')
281
 
        # LANG env variable has no effect on Windows
282
 
        # but some characters anyway cannot be represented
283
 
        # in default user encoding
284
 
        char = probe_bad_non_ascii(osutils.get_user_encoding())
285
 
        if char is None:
286
 
            raise TestSkipped('Cannot find suitable non-ascii character'
287
 
                'for user_encoding (%s)' % osutils.get_user_encoding())
288
 
        out,err = self.run_bzr_subprocess('commit -m "%s"' % char,
289
 
                                          retcode=1,
290
 
                                          env_changes={'LANG': 'C'})
291
 
        self.assertContainsRe(err, r'bzrlib.errors.BzrError: Parameter.*is '
292
 
                                    'unsupported by the current encoding.')
 
356
        self.build_tree_contents([('foo.c', b'int main() {}')])
 
357
        tree.add('foo.c')
 
358
        self.run_bzr('commit -m ""')
293
359
 
294
360
    def test_other_branch_commit(self):
295
361
        # this branch is to ensure consistent behaviour, whether we're run
297
363
        outer_tree = self.make_branch_and_tree('.')
298
364
        inner_tree = self.make_branch_and_tree('branch')
299
365
        self.build_tree_contents([
300
 
            ('branch/foo.c', 'int main() {}'),
301
 
            ('branch/bar.c', 'int main() {}')])
 
366
            ('branch/foo.c', b'int main() {}'),
 
367
            ('branch/bar.c', b'int main() {}')])
302
368
        inner_tree.add(['foo.c', 'bar.c'])
303
369
        # can't commit files in different trees; sane error
304
370
        self.run_bzr('commit -m newstuff branch/foo.c .', retcode=3)
318
384
        # commit to the original branch to make the checkout out of date
319
385
        tree.commit('message branch', allow_pointless=True)
320
386
        # now commit to the checkout should emit
321
 
        # ERROR: Out of date with the branch, 'bzr update' is suggested
 
387
        # ERROR: Out of date with the branch, 'brz update' is suggested
322
388
        output = self.run_bzr('commit --unchanged -m checkout_message '
323
389
                             'checkout', retcode=3)
324
390
        self.assertEqual(output,
325
391
                         ('',
326
 
                          "bzr: ERROR: Working tree is out of date, please "
327
 
                          "run 'bzr update'.\n"))
 
392
                          "brz: ERROR: Working tree is out of date, please "
 
393
                          "run 'brz update'.\n"))
328
394
 
329
395
    def test_local_commit_unbound(self):
330
396
        # a --local commit on an unbound branch is an error
331
397
        self.make_branch_and_tree('.')
332
398
        out, err = self.run_bzr('commit --local', retcode=3)
333
399
        self.assertEqualDiff('', out)
334
 
        self.assertEqualDiff('bzr: ERROR: Cannot perform local-only commits '
 
400
        self.assertEqualDiff('brz: ERROR: Cannot perform local-only commits '
335
401
                             'on unbound branches.\n', err)
336
402
 
337
403
    def test_commit_a_text_merge_in_a_checkout(self):
343
409
        trunk = self.make_branch_and_tree('trunk')
344
410
 
345
411
        u1 = trunk.branch.create_checkout('u1')
346
 
        self.build_tree_contents([('u1/hosts', 'initial contents\n')])
 
412
        self.build_tree_contents([('u1/hosts', b'initial contents\n')])
347
413
        u1.add('hosts')
348
414
        self.run_bzr('commit -m add-hosts u1')
349
415
 
350
416
        u2 = trunk.branch.create_checkout('u2')
351
 
        self.build_tree_contents([('u2/hosts', 'altered in u2\n')])
 
417
        self.build_tree_contents([('u2/hosts', b'altered in u2\n')])
352
418
        self.run_bzr('commit -m checkin-from-u2 u2')
353
419
 
354
420
        # make an offline commits
355
 
        self.build_tree_contents([('u1/hosts', 'first offline change in u1\n')])
 
421
        self.build_tree_contents([('u1/hosts', b'first offline change in u1\n')])
356
422
        self.run_bzr('commit -m checkin-offline --local u1')
357
423
 
358
424
        # now try to pull in online work from u2, and then commit our offline
359
425
        # work as a merge
360
426
        # retcode 1 as we expect a text conflict
361
427
        self.run_bzr('update u1', retcode=1)
362
 
        self.assertFileEqual('''\
 
428
        self.assertFileEqual(b'''\
363
429
<<<<<<< TREE
364
430
first offline change in u1
365
431
=======
372
438
        # add a text change here to represent resolving the merge conflicts in
373
439
        # favour of a new version of the file not identical to either the u1
374
440
        # version or the u2 version.
375
 
        self.build_tree_contents([('u1/hosts', 'merge resolution\n')])
 
441
        self.build_tree_contents([('u1/hosts', b'merge resolution\n')])
376
442
        self.run_bzr('commit -m checkin-merge-of-the-offline-work-from-u1 u1')
377
443
 
378
444
    def test_commit_exclude_excludes_modified_files(self):
411
477
        t.add(['file-a', 'dir-a', 'dir-a/file-b'])
412
478
        t.commit('Create')
413
479
        t.remove(['file-a', 'dir-a/file-b'])
414
 
        os.chdir('dir-a')
415
 
        result = self.run_bzr('commit . -m removed-file-b')[1]
 
480
        result = self.run_bzr('commit . -m removed-file-b',
 
481
                              working_dir='dir-a')[1]
416
482
        self.assertNotContainsRe(result, 'file-a')
417
 
        result = self.run_bzr('status')[0]
 
483
        result = self.run_bzr('status', working_dir='dir-a')[0]
418
484
        self.assertContainsRe(result, 'removed:\n  file-a')
419
485
 
420
486
    def test_strict_commit(self):
424
490
        self.build_tree(['tree/a'])
425
491
        tree.add('a')
426
492
        # A simple change should just work
427
 
        self.run_bzr('commit --strict -m adding-a',
428
 
                     working_dir='tree')
 
493
        self.run_bzr('commit --strict -m adding-a', working_dir='tree')
429
494
 
430
495
    def test_strict_commit_no_changes(self):
431
496
        """commit --strict gives "no changes" if there is nothing to commit"""
471
536
            'commit -m hello --fixes=lp:23452 tree/hello.txt')
472
537
        self.assertEqual('', output)
473
538
        self.assertContainsRe(err, 'Committing to: .*\n'
474
 
                              'added hello\.txt\n'
475
 
                              'Committed revision 1\.\n')
 
539
                              'added hello\\.txt\n'
 
540
                              'Committed revision 1\\.\n')
 
541
 
 
542
    def test_fixes_bug_unicode(self):
 
543
        """commit --fixes=lp:unicode succeeds without output."""
 
544
        tree = self.make_branch_and_tree('tree')
 
545
        self.build_tree(['tree/hello.txt'])
 
546
        tree.add('hello.txt')
 
547
        output, err = self.run_bzr_raw(
 
548
            ['commit', '-m', 'hello',
 
549
             u'--fixes=generic:\u20ac', 'tree/hello.txt'],
 
550
            encoding='utf-8', retcode=3)
 
551
        self.assertEqual(b'', output)
 
552
        self.assertContainsRe(err,
 
553
            b'brz: ERROR: Unrecognized bug generic:\xe2\x82\xac\\. Commit refused.\n')
476
554
 
477
555
    def test_no_bugs_no_properties(self):
478
556
        """If no bugs are fixed, the bugs property is not set.
482
560
        tree = self.make_branch_and_tree('tree')
483
561
        self.build_tree(['tree/hello.txt'])
484
562
        tree.add('hello.txt')
485
 
        self.run_bzr( 'commit -m hello tree/hello.txt')
 
563
        self.run_bzr('commit -m hello tree/hello.txt')
486
564
        # Get the revision properties, ignoring the branch-nick property, which
487
565
        # we don't care about for this test.
488
566
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
490
568
        del properties['branch-nick']
491
569
        self.assertFalse('bugs' in properties)
492
570
 
 
571
    def test_bugs_sets_property(self):
 
572
        """commit --bugs=lp:234 sets the lp:234 revprop to 'related'."""
 
573
        tree = self.make_branch_and_tree('tree')
 
574
        self.build_tree(['tree/hello.txt'])
 
575
        tree.add('hello.txt')
 
576
        self.run_bzr('commit -m hello --bugs=lp:234 tree/hello.txt')
 
577
 
 
578
        # Get the revision properties, ignoring the branch-nick property, which
 
579
        # we don't care about for this test.
 
580
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
581
        properties = dict(last_rev.properties)
 
582
        del properties[u'branch-nick']
 
583
 
 
584
        self.assertEqual({u'bugs': 'https://launchpad.net/bugs/234 related'},
 
585
                         properties)
 
586
 
493
587
    def test_fixes_bug_sets_property(self):
494
588
        """commit --fixes=lp:234 sets the lp:234 revprop to 'fixed'."""
495
589
        tree = self.make_branch_and_tree('tree')
501
595
        # we don't care about for this test.
502
596
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
503
597
        properties = dict(last_rev.properties)
504
 
        del properties['branch-nick']
 
598
        del properties[u'branch-nick']
505
599
 
506
 
        self.assertEqual({'bugs': 'https://launchpad.net/bugs/234 fixed'},
 
600
        self.assertEqual({u'bugs': 'https://launchpad.net/bugs/234 fixed'},
507
601
                         properties)
508
602
 
509
603
    def test_fixes_multiple_bugs_sets_properties(self):
521
615
        del properties['branch-nick']
522
616
 
523
617
        self.assertEqual(
524
 
            {'bugs': 'https://launchpad.net/bugs/123 fixed\n'
 
618
            {u'bugs': 'https://launchpad.net/bugs/123 fixed\n'
525
619
                     'https://launchpad.net/bugs/235 fixed'},
526
620
            properties)
527
621
 
556
650
            'commit -m add-b --fixes=xxx:123',
557
651
            working_dir='tree')
558
652
 
 
653
    def test_fixes_bug_with_default_tracker(self):
 
654
        """commit --fixes=234 uses the default bug tracker."""
 
655
        tree = self.make_branch_and_tree('tree')
 
656
        self.build_tree(['tree/hello.txt'])
 
657
        tree.add('hello.txt')
 
658
        self.run_bzr_error(
 
659
            ["brz: ERROR: No tracker specified for bug 123. Use the form "
 
660
            "'tracker:id' or specify a default bug tracker using the "
 
661
            "`bugtracker` option.\n"
 
662
            "See \"brz help bugs\" for more information on this feature. "
 
663
            "Commit refused."],
 
664
            'commit -m add-b --fixes=123',
 
665
            working_dir='tree')
 
666
        tree.branch.get_config_stack().set("bugtracker", "lp")
 
667
        self.run_bzr('commit -m hello --fixes=234 tree/hello.txt')
 
668
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
669
        self.assertEqual('https://launchpad.net/bugs/234 fixed',
 
670
                         last_rev.properties['bugs'])
 
671
 
559
672
    def test_fixes_invalid_bug_number(self):
560
673
        tree = self.make_branch_and_tree('tree')
561
674
        self.build_tree(['tree/hello.txt'])
562
675
        tree.add('hello.txt')
563
676
        self.run_bzr_error(
564
677
            ["Did not understand bug identifier orange: Must be an integer. "
565
 
             "See \"bzr help bugs\" for more information on this feature.\n"
 
678
             "See \"brz help bugs\" for more information on this feature.\n"
566
679
             "Commit refused."],
567
680
            'commit -m add-b --fixes=lp:orange',
568
681
            working_dir='tree')
573
686
        self.build_tree(['tree/hello.txt'])
574
687
        tree.add('hello.txt')
575
688
        self.run_bzr_error(
576
 
            [r"Invalid bug orange. Must be in the form of 'tracker:id'\. "
577
 
             r"See \"bzr help bugs\" for more information on this feature.\n"
578
 
             r"Commit refused\."],
579
 
            'commit -m add-b --fixes=orange',
 
689
            [r"Invalid bug orange:apples:bananas. Must be in the form of "
 
690
             r"'tracker:id'\. See \"brz help bugs\" for more information on "
 
691
             r"this feature.\nCommit refused\."],
 
692
            'commit -m add-b --fixes=orange:apples:bananas',
580
693
            working_dir='tree')
581
694
 
582
695
    def test_no_author(self):
643
756
        out, err = self.run_bzr("commit -m hello "
644
757
            "--commit-time='NOT A TIME' tree/hello.txt", retcode=3)
645
758
        self.assertStartsWith(
646
 
            err, "bzr: ERROR: Could not parse --commit-time:")
 
759
            err, "brz: ERROR: Could not parse --commit-time:")
 
760
 
 
761
    def test_commit_time_missing_tz(self):
 
762
        tree = self.make_branch_and_tree('tree')
 
763
        self.build_tree(['tree/hello.txt'])
 
764
        tree.add('hello.txt')
 
765
        out, err = self.run_bzr("commit -m hello "
 
766
            "--commit-time='2009-10-10 08:00:00' tree/hello.txt", retcode=3)
 
767
        self.assertStartsWith(
 
768
            err, "brz: ERROR: Could not parse --commit-time:")
 
769
        # Test that it is actually checking and does not simply crash with
 
770
        # some other exception
 
771
        self.assertContainsString(err, "missing a timezone offset")
647
772
 
648
773
    def test_partial_commit_with_renames_in_tree(self):
649
774
        # this test illustrates bug #140419
656
781
        # then during partial commit we have error
657
782
        # parent_id {dir-XXX} not in inventory
658
783
        t.rename_one('dir/a', 'a')
659
 
        self.build_tree_contents([('test', 'changes in test')])
 
784
        self.build_tree_contents([('test', b'changes in test')])
660
785
        # partial commit
661
786
        out, err = self.run_bzr('commit test -m "partial commit"')
662
 
        self.assertEquals('', out)
 
787
        self.assertEqual('', out)
663
788
        self.assertContainsRe(err, r'modified test\nCommitted revision 2.')
664
789
 
665
790
    def test_commit_readonly_checkout(self):
666
 
        # https://bugs.edge.launchpad.net/bzr/+bug/129701
 
791
        # https://bugs.launchpad.net/bzr/+bug/129701
667
792
        # "UnlockableTransport error trying to commit in checkout of readonly
668
793
        # branch"
669
794
        self.make_branch('master')
670
 
        master = BzrDir.open_from_transport(
 
795
        master = ControlDir.open_from_transport(
671
796
            self.get_readonly_transport('master')).open_branch()
672
797
        master.create_checkout('checkout')
673
798
        out, err = self.run_bzr(['commit', '--unchanged', '-mfoo', 'checkout'],
674
799
            retcode=3)
675
800
        self.assertContainsRe(err,
676
 
            r'^bzr: ERROR: Cannot lock.*readonly transport')
 
801
            r'^brz: ERROR: Cannot lock.*readonly transport')
677
802
 
678
803
    def setup_editor(self):
679
804
        # Test that commit template hooks work
680
805
        if sys.platform == "win32":
681
 
            f = file('fed.bat', 'w')
682
 
            f.write('@rem dummy fed')
683
 
            f.close()
684
 
            osutils.set_or_unset_env('BZR_EDITOR', "fed.bat")
 
806
            with open('fed.bat', 'w') as f:
 
807
                f.write('@rem dummy fed')
 
808
            self.overrideEnv('BRZ_EDITOR', "fed.bat")
685
809
        else:
686
 
            f = file('fed.sh', 'wb')
687
 
            f.write('#!/bin/sh\n')
688
 
            f.close()
689
 
            os.chmod('fed.sh', 0755)
690
 
            osutils.set_or_unset_env('BZR_EDITOR', "./fed.sh")
 
810
            with open('fed.sh', 'wb') as f:
 
811
                f.write(b'#!/bin/sh\n')
 
812
            os.chmod('fed.sh', 0o755)
 
813
            self.overrideEnv('BRZ_EDITOR', "./fed.sh")
691
814
 
692
815
    def setup_commit_with_template(self):
693
816
        self.setup_editor()
698
821
        tree.add('hello.txt')
699
822
        return tree
700
823
 
 
824
    def test_edit_empty_message(self):
 
825
        tree = self.make_branch_and_tree('tree')
 
826
        self.setup_editor()
 
827
        self.build_tree(['tree/hello.txt'])
 
828
        tree.add('hello.txt')
 
829
        out, err = self.run_bzr("commit tree/hello.txt", retcode=3,
 
830
            stdin="y\n")
 
831
        self.assertContainsRe(err,
 
832
            "brz: ERROR: Empty commit message specified")
 
833
 
701
834
    def test_commit_hook_template_accepted(self):
702
835
        tree = self.setup_commit_with_template()
703
836
        out, err = self.run_bzr("commit tree/hello.txt", stdin="y\n")
707
840
    def test_commit_hook_template_rejected(self):
708
841
        tree = self.setup_commit_with_template()
709
842
        expected = tree.last_revision()
710
 
        out, err = self.run_bzr_error(["empty commit message"],
 
843
        out, err = self.run_bzr_error(["Empty commit message specified."
 
844
                  " Please specify a commit message with either"
 
845
                  " --message or --file or leave a blank message"
 
846
                  " with --message \"\"."],
711
847
            "commit tree/hello.txt", stdin="n\n")
712
848
        self.assertEqual(expected, tree.last_revision())
 
849
 
 
850
    def test_set_commit_message(self):
 
851
        msgeditor.hooks.install_named_hook("set_commit_message",
 
852
                lambda commit_obj, msg: "save me some typing\n", None)
 
853
        tree = self.make_branch_and_tree('tree')
 
854
        self.build_tree(['tree/hello.txt'])
 
855
        tree.add('hello.txt')
 
856
        out, err = self.run_bzr("commit tree/hello.txt")
 
857
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
858
        self.assertEqual('save me some typing\n', last_rev.message)
 
859
 
 
860
    def test_commit_without_username(self):
 
861
        """Ensure commit error if username is not set.
 
862
        """
 
863
        self.run_bzr(['init', 'foo'])
 
864
        with open('foo/foo.txt', 'w') as f:
 
865
            f.write('hello')
 
866
        self.run_bzr(['add'], working_dir='foo')
 
867
        self.overrideEnv('EMAIL', None)
 
868
        self.overrideEnv('BRZ_EMAIL', None)
 
869
        # Also, make sure that it's not inferred from mailname.
 
870
        self.overrideAttr(config, '_auto_user_id',
 
871
            lambda: (None, None))
 
872
        self.run_bzr_error(
 
873
            ['Unable to determine your name'],
 
874
            ['commit', '-m', 'initial'], working_dir='foo')
 
875
 
 
876
    def test_commit_recursive_checkout(self):
 
877
        """Ensure that a commit to a recursive checkout fails cleanly.
 
878
        """
 
879
        self.run_bzr(['init', 'test_branch'])
 
880
        self.run_bzr(['checkout', 'test_branch', 'test_checkout'])
 
881
        self.run_bzr(['bind', '.'], working_dir='test_checkout') # bind to self
 
882
        with open('test_checkout/foo.txt', 'w') as f:
 
883
            f.write('hello')
 
884
        self.run_bzr(['add'], working_dir='test_checkout')
 
885
        out, err = self.run_bzr_error(
 
886
            ['Branch.*test_checkout.*appears to be bound to itself'],
 
887
            ['commit', '-m', 'addedfoo'], working_dir='test_checkout')
 
888
 
 
889
    def test_mv_dirs_non_ascii(self):
 
890
        """Move directory with non-ascii name and containing files.
 
891
 
 
892
        Regression test for bug 185211.
 
893
        """
 
894
        tree = self.make_branch_and_tree('.')
 
895
        self.build_tree([u'abc\xa7/', u'abc\xa7/foo'])
 
896
 
 
897
        tree.add([u'abc\xa7/', u'abc\xa7/foo'])
 
898
        tree.commit('checkin')
 
899
 
 
900
        tree.rename_one(u'abc\xa7', 'abc')
 
901
 
 
902
        self.run_bzr('ci -m "non-ascii mv"')
 
903
 
 
904
 
 
905
class TestSmartServerCommit(TestCaseWithTransport):
 
906
 
 
907
    def test_commit_to_lightweight(self):
 
908
        self.setup_smart_server_with_call_log()
 
909
        t = self.make_branch_and_tree('from')
 
910
        for count in range(9):
 
911
            t.commit(message='commit %d' % count)
 
912
        out, err = self.run_bzr(['checkout', '--lightweight', self.get_url('from'),
 
913
            'target'])
 
914
        self.reset_smart_call_log()
 
915
        self.build_tree(['target/afile'])
 
916
        self.run_bzr(['add', 'target/afile'])
 
917
        out, err = self.run_bzr(['commit', '-m', 'do something', 'target'])
 
918
        # This figure represent the amount of work to perform this use case. It
 
919
        # is entirely ok to reduce this number if a test fails due to rpc_count
 
920
        # being too low. If rpc_count increases, more network roundtrips have
 
921
        # become necessary for this use case. Please do not adjust this number
 
922
        # upwards without agreement from bzr's network support maintainers.
 
923
        self.assertLength(211, self.hpss_calls)
 
924
        self.assertLength(2, self.hpss_connections)
 
925
        self.expectFailure("commit still uses VFS calls",
 
926
            self.assertThat, self.hpss_calls, ContainsNoVfsCalls)