/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: Jelmer Vernooij
  • Date: 2020-09-02 16:35:18 UTC
  • mto: (7490.40.109 work)
  • mto: This revision was merged to the branch mainline in revision 7526.
  • Revision ID: jelmer@jelmer.uk-20200902163518-sy9f4unbboljphgu
Handle duplicate directories entries for git.

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 ..test_bedding import override_whoami
 
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
 
        other_tree.lock_write()
232
 
        # perform the needed actions on the files and dirs.
233
 
        try:
 
318
        with other_tree.lock_write():
 
319
            # perform the needed actions on the files and dirs.
234
320
            other_tree.rename_one('dirtorename', 'renameddir')
235
321
            other_tree.rename_one('dirtoreparent', 'renameddir/reparenteddir')
236
322
            other_tree.rename_one('filetorename', 'renamedfile')
239
325
            other_tree.remove(['dirtoremove', 'filetoremove'])
240
326
            self.build_tree_contents([
241
327
                ('other/newdir/',),
242
 
                ('other/filetomodify', 'new content'),
243
 
                ('other/newfile', 'new file content')])
 
328
                ('other/filetomodify', b'new content'),
 
329
                ('other/newfile', b'new file content')])
244
330
            other_tree.add('newfile')
245
331
            other_tree.add('newdir/')
246
332
            other_tree.commit('modify all sample files and dirs.')
247
 
        finally:
248
 
            other_tree.unlock()
249
333
        this_tree.merge_from_branch(other_tree.branch)
250
 
        os.chdir('this')
251
 
        out,err = self.run_bzr('commit -m added')
 
334
        out, err = self.run_bzr('commit -m added', working_dir='this')
252
335
        self.assertEqual('', out)
253
 
        self.assertEqual(set([
254
 
            'Committing to: %s/' % osutils.getcwd(),
 
336
        self.assertEqual({
 
337
            'Committing to: %s/' % osutils.pathjoin(osutils.getcwd(), 'this'),
255
338
            'modified filetomodify',
256
339
            'added newdir',
257
340
            'added newfile',
263
346
            'deleted filetoremove',
264
347
            'Committed revision 2.',
265
348
            ''
266
 
            ]), set(err.split('\n')))
 
349
            }, set(err.split('\n')))
267
350
 
268
351
    def test_empty_commit_message(self):
269
352
        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.')
 
353
        self.build_tree_contents([('foo.c', b'int main() {}')])
 
354
        tree.add('foo.c')
 
355
        self.run_bzr('commit -m ""')
293
356
 
294
357
    def test_other_branch_commit(self):
295
358
        # this branch is to ensure consistent behaviour, whether we're run
297
360
        outer_tree = self.make_branch_and_tree('.')
298
361
        inner_tree = self.make_branch_and_tree('branch')
299
362
        self.build_tree_contents([
300
 
            ('branch/foo.c', 'int main() {}'),
301
 
            ('branch/bar.c', 'int main() {}')])
 
363
            ('branch/foo.c', b'int main() {}'),
 
364
            ('branch/bar.c', b'int main() {}')])
302
365
        inner_tree.add(['foo.c', 'bar.c'])
303
366
        # can't commit files in different trees; sane error
304
367
        self.run_bzr('commit -m newstuff branch/foo.c .', retcode=3)
307
370
        # can commit to branch - records bar.c
308
371
        self.run_bzr('commit -m newstuff branch')
309
372
        # No changes left
310
 
        self.run_bzr_error(["No changes to commit"], 'commit -m newstuff branch')
 
373
        self.run_bzr_error(["No changes to commit"],
 
374
                           'commit -m newstuff branch')
311
375
 
312
376
    def test_out_of_date_tree_commit(self):
313
377
        # check we get an error code and a clear message committing with an out
318
382
        # commit to the original branch to make the checkout out of date
319
383
        tree.commit('message branch', allow_pointless=True)
320
384
        # now commit to the checkout should emit
321
 
        # ERROR: Out of date with the branch, 'bzr update' is suggested
 
385
        # ERROR: Out of date with the branch, 'brz update' is suggested
322
386
        output = self.run_bzr('commit --unchanged -m checkout_message '
323
 
                             'checkout', retcode=3)
 
387
                              'checkout', retcode=3)
324
388
        self.assertEqual(output,
325
389
                         ('',
326
 
                          "bzr: ERROR: Working tree is out of date, please "
327
 
                          "run 'bzr update'.\n"))
 
390
                          "brz: ERROR: Working tree is out of date, please "
 
391
                          "run 'brz update'.\n"))
328
392
 
329
393
    def test_local_commit_unbound(self):
330
394
        # a --local commit on an unbound branch is an error
331
395
        self.make_branch_and_tree('.')
332
396
        out, err = self.run_bzr('commit --local', retcode=3)
333
397
        self.assertEqualDiff('', out)
334
 
        self.assertEqualDiff('bzr: ERROR: Cannot perform local-only commits '
 
398
        self.assertEqualDiff('brz: ERROR: Cannot perform local-only commits '
335
399
                             'on unbound branches.\n', err)
336
400
 
337
401
    def test_commit_a_text_merge_in_a_checkout(self):
343
407
        trunk = self.make_branch_and_tree('trunk')
344
408
 
345
409
        u1 = trunk.branch.create_checkout('u1')
346
 
        self.build_tree_contents([('u1/hosts', 'initial contents\n')])
 
410
        self.build_tree_contents([('u1/hosts', b'initial contents\n')])
347
411
        u1.add('hosts')
348
412
        self.run_bzr('commit -m add-hosts u1')
349
413
 
350
414
        u2 = trunk.branch.create_checkout('u2')
351
 
        self.build_tree_contents([('u2/hosts', 'altered in u2\n')])
 
415
        self.build_tree_contents([('u2/hosts', b'altered in u2\n')])
352
416
        self.run_bzr('commit -m checkin-from-u2 u2')
353
417
 
354
418
        # make an offline commits
355
 
        self.build_tree_contents([('u1/hosts', 'first offline change in u1\n')])
 
419
        self.build_tree_contents(
 
420
            [('u1/hosts', b'first offline change in u1\n')])
356
421
        self.run_bzr('commit -m checkin-offline --local u1')
357
422
 
358
423
        # now try to pull in online work from u2, and then commit our offline
359
424
        # work as a merge
360
425
        # retcode 1 as we expect a text conflict
361
426
        self.run_bzr('update u1', retcode=1)
362
 
        self.assertFileEqual('''\
 
427
        self.assertFileEqual(b'''\
363
428
<<<<<<< TREE
364
429
first offline change in u1
365
430
=======
372
437
        # add a text change here to represent resolving the merge conflicts in
373
438
        # favour of a new version of the file not identical to either the u1
374
439
        # version or the u2 version.
375
 
        self.build_tree_contents([('u1/hosts', 'merge resolution\n')])
 
440
        self.build_tree_contents([('u1/hosts', b'merge resolution\n')])
376
441
        self.run_bzr('commit -m checkin-merge-of-the-offline-work-from-u1 u1')
377
442
 
378
443
    def test_commit_exclude_excludes_modified_files(self):
411
476
        t.add(['file-a', 'dir-a', 'dir-a/file-b'])
412
477
        t.commit('Create')
413
478
        t.remove(['file-a', 'dir-a/file-b'])
414
 
        os.chdir('dir-a')
415
 
        result = self.run_bzr('commit . -m removed-file-b')[1]
 
479
        result = self.run_bzr('commit . -m removed-file-b',
 
480
                              working_dir='dir-a')[1]
416
481
        self.assertNotContainsRe(result, 'file-a')
417
 
        result = self.run_bzr('status')[0]
 
482
        result = self.run_bzr('status', working_dir='dir-a')[0]
418
483
        self.assertContainsRe(result, 'removed:\n  file-a')
419
484
 
420
485
    def test_strict_commit(self):
424
489
        self.build_tree(['tree/a'])
425
490
        tree.add('a')
426
491
        # A simple change should just work
427
 
        self.run_bzr('commit --strict -m adding-a',
428
 
                     working_dir='tree')
 
492
        self.run_bzr('commit --strict -m adding-a', working_dir='tree')
429
493
 
430
494
    def test_strict_commit_no_changes(self):
431
495
        """commit --strict gives "no changes" if there is nothing to commit"""
471
535
            'commit -m hello --fixes=lp:23452 tree/hello.txt')
472
536
        self.assertEqual('', output)
473
537
        self.assertContainsRe(err, 'Committing to: .*\n'
474
 
                              'added hello\.txt\n'
475
 
                              'Committed revision 1\.\n')
 
538
                              'added hello\\.txt\n'
 
539
                              'Committed revision 1\\.\n')
 
540
 
 
541
    def test_fixes_bug_unicode(self):
 
542
        """commit --fixes=lp:unicode succeeds without output."""
 
543
        tree = self.make_branch_and_tree('tree')
 
544
        self.build_tree(['tree/hello.txt'])
 
545
        tree.add('hello.txt')
 
546
        output, err = self.run_bzr_raw(
 
547
            ['commit', '-m', 'hello',
 
548
             u'--fixes=generic:\u20ac', 'tree/hello.txt'],
 
549
            encoding='utf-8', retcode=3)
 
550
        self.assertEqual(b'', output)
 
551
        self.assertContainsRe(err,
 
552
                              b'brz: ERROR: Unrecognized bug generic:\xe2\x82\xac\\. Commit refused.\n')
476
553
 
477
554
    def test_no_bugs_no_properties(self):
478
555
        """If no bugs are fixed, the bugs property is not set.
482
559
        tree = self.make_branch_and_tree('tree')
483
560
        self.build_tree(['tree/hello.txt'])
484
561
        tree.add('hello.txt')
485
 
        self.run_bzr( 'commit -m hello tree/hello.txt')
 
562
        self.run_bzr('commit -m hello tree/hello.txt')
486
563
        # Get the revision properties, ignoring the branch-nick property, which
487
564
        # we don't care about for this test.
488
565
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
490
567
        del properties['branch-nick']
491
568
        self.assertFalse('bugs' in properties)
492
569
 
 
570
    def test_bugs_sets_property(self):
 
571
        """commit --bugs=lp:234 sets the lp:234 revprop to 'related'."""
 
572
        tree = self.make_branch_and_tree('tree')
 
573
        self.build_tree(['tree/hello.txt'])
 
574
        tree.add('hello.txt')
 
575
        self.run_bzr('commit -m hello --bugs=lp:234 tree/hello.txt')
 
576
 
 
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[u'branch-nick']
 
582
 
 
583
        self.assertEqual({u'bugs': 'https://launchpad.net/bugs/234 related'},
 
584
                         properties)
 
585
 
493
586
    def test_fixes_bug_sets_property(self):
494
587
        """commit --fixes=lp:234 sets the lp:234 revprop to 'fixed'."""
495
588
        tree = self.make_branch_and_tree('tree')
501
594
        # we don't care about for this test.
502
595
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
503
596
        properties = dict(last_rev.properties)
504
 
        del properties['branch-nick']
 
597
        del properties[u'branch-nick']
505
598
 
506
 
        self.assertEqual({'bugs': 'https://launchpad.net/bugs/234 fixed'},
 
599
        self.assertEqual({u'bugs': 'https://launchpad.net/bugs/234 fixed'},
507
600
                         properties)
508
601
 
509
602
    def test_fixes_multiple_bugs_sets_properties(self):
521
614
        del properties['branch-nick']
522
615
 
523
616
        self.assertEqual(
524
 
            {'bugs': 'https://launchpad.net/bugs/123 fixed\n'
525
 
                     'https://launchpad.net/bugs/235 fixed'},
 
617
            {u'bugs': 'https://launchpad.net/bugs/123 fixed\n'
 
618
             'https://launchpad.net/bugs/235 fixed'},
526
619
            properties)
527
620
 
528
621
    def test_fixes_bug_with_alternate_trackers(self):
534
627
            'trac_twisted_url', 'http://twistedmatrix.com/trac')
535
628
        self.build_tree(['tree/hello.txt'])
536
629
        tree.add('hello.txt')
537
 
        self.run_bzr('commit -m hello --fixes=lp:123 --fixes=twisted:235 tree/')
 
630
        self.run_bzr(
 
631
            'commit -m hello --fixes=lp:123 --fixes=twisted:235 tree/')
538
632
 
539
633
        # Get the revision properties, ignoring the branch-nick property, which
540
634
        # we don't care about for this test.
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):
584
697
        tree = self.make_branch_and_tree('tree')
585
698
        self.build_tree(['tree/hello.txt'])
586
699
        tree.add('hello.txt')
587
 
        self.run_bzr( 'commit -m hello tree/hello.txt')
 
700
        self.run_bzr('commit -m hello tree/hello.txt')
588
701
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
589
702
        properties = last_rev.properties
590
703
        self.assertFalse('author' in properties)
598
711
        tree.add('hello.txt')
599
712
        self.run_bzr(["commit", '-m', 'hello',
600
713
                      '--author', u'John D\xf6 <jdoe@example.com>',
601
 
                     "tree/hello.txt"])
 
714
                      "tree/hello.txt"])
602
715
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
603
716
        properties = last_rev.properties
604
 
        self.assertEqual(u'John D\xf6 <jdoe@example.com>', properties['authors'])
 
717
        self.assertEqual(u'John D\xf6 <jdoe@example.com>',
 
718
                         properties['authors'])
605
719
 
606
720
    def test_author_no_email(self):
607
721
        """Author's name without an email address is allowed, too."""
630
744
        self.build_tree(['tree/hello.txt'])
631
745
        tree.add('hello.txt')
632
746
        out, err = self.run_bzr("commit -m hello "
633
 
            "--commit-time='2009-10-10 08:00:00 +0100' tree/hello.txt")
 
747
                                "--commit-time='2009-10-10 08:00:00 +0100' tree/hello.txt")
634
748
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
635
749
        self.assertEqual(
636
750
            'Sat 2009-10-10 08:00:00 +0100',
637
751
            osutils.format_date(last_rev.timestamp, last_rev.timezone))
638
 
        
 
752
 
639
753
    def test_commit_time_bad_time(self):
640
754
        tree = self.make_branch_and_tree('tree')
641
755
        self.build_tree(['tree/hello.txt'])
642
756
        tree.add('hello.txt')
643
757
        out, err = self.run_bzr("commit -m hello "
644
 
            "--commit-time='NOT A TIME' tree/hello.txt", retcode=3)
645
 
        self.assertStartsWith(
646
 
            err, "bzr: ERROR: Could not parse --commit-time:")
 
758
                                "--commit-time='NOT A TIME' tree/hello.txt", retcode=3)
 
759
        self.assertStartsWith(
 
760
            err, "brz: ERROR: Could not parse --commit-time:")
 
761
 
 
762
    def test_commit_time_missing_tz(self):
 
763
        tree = self.make_branch_and_tree('tree')
 
764
        self.build_tree(['tree/hello.txt'])
 
765
        tree.add('hello.txt')
 
766
        out, err = self.run_bzr("commit -m hello "
 
767
                                "--commit-time='2009-10-10 08:00:00' tree/hello.txt", retcode=3)
 
768
        self.assertStartsWith(
 
769
            err, "brz: ERROR: Could not parse --commit-time:")
 
770
        # Test that it is actually checking and does not simply crash with
 
771
        # some other exception
 
772
        self.assertContainsString(err, "missing a timezone offset")
647
773
 
648
774
    def test_partial_commit_with_renames_in_tree(self):
649
775
        # this test illustrates bug #140419
656
782
        # then during partial commit we have error
657
783
        # parent_id {dir-XXX} not in inventory
658
784
        t.rename_one('dir/a', 'a')
659
 
        self.build_tree_contents([('test', 'changes in test')])
 
785
        self.build_tree_contents([('test', b'changes in test')])
660
786
        # partial commit
661
787
        out, err = self.run_bzr('commit test -m "partial commit"')
662
 
        self.assertEquals('', out)
 
788
        self.assertEqual('', out)
663
789
        self.assertContainsRe(err, r'modified test\nCommitted revision 2.')
664
790
 
665
791
    def test_commit_readonly_checkout(self):
666
 
        # https://bugs.edge.launchpad.net/bzr/+bug/129701
 
792
        # https://bugs.launchpad.net/bzr/+bug/129701
667
793
        # "UnlockableTransport error trying to commit in checkout of readonly
668
794
        # branch"
669
795
        self.make_branch('master')
670
 
        master = BzrDir.open_from_transport(
 
796
        master = ControlDir.open_from_transport(
671
797
            self.get_readonly_transport('master')).open_branch()
672
798
        master.create_checkout('checkout')
673
799
        out, err = self.run_bzr(['commit', '--unchanged', '-mfoo', 'checkout'],
674
 
            retcode=3)
 
800
                                retcode=3)
675
801
        self.assertContainsRe(err,
676
 
            r'^bzr: ERROR: Cannot lock.*readonly transport')
 
802
                              r'^brz: ERROR: Cannot lock.*readonly transport')
677
803
 
678
804
    def setup_editor(self):
679
805
        # Test that commit template hooks work
680
806
        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")
 
807
            with open('fed.bat', 'w') as f:
 
808
                f.write('@rem dummy fed')
 
809
            self.overrideEnv('BRZ_EDITOR', "fed.bat")
685
810
        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")
 
811
            with open('fed.sh', 'wb') as f:
 
812
                f.write(b'#!/bin/sh\n')
 
813
            os.chmod('fed.sh', 0o755)
 
814
            self.overrideEnv('BRZ_EDITOR', "./fed.sh")
691
815
 
692
816
    def setup_commit_with_template(self):
693
817
        self.setup_editor()
694
818
        msgeditor.hooks.install_named_hook("commit_message_template",
695
 
                lambda commit_obj, msg: "save me some typing\n", None)
 
819
                                           lambda commit_obj, msg: "save me some typing\n", None)
696
820
        tree = self.make_branch_and_tree('tree')
697
821
        self.build_tree(['tree/hello.txt'])
698
822
        tree.add('hello.txt')
699
823
        return tree
700
824
 
 
825
    def test_edit_empty_message(self):
 
826
        tree = self.make_branch_and_tree('tree')
 
827
        self.setup_editor()
 
828
        self.build_tree(['tree/hello.txt'])
 
829
        tree.add('hello.txt')
 
830
        out, err = self.run_bzr("commit tree/hello.txt", retcode=3,
 
831
                                stdin="y\n")
 
832
        self.assertContainsRe(err,
 
833
                              "brz: ERROR: Empty commit message specified")
 
834
 
701
835
    def test_commit_hook_template_accepted(self):
702
836
        tree = self.setup_commit_with_template()
703
837
        out, err = self.run_bzr("commit tree/hello.txt", stdin="y\n")
707
841
    def test_commit_hook_template_rejected(self):
708
842
        tree = self.setup_commit_with_template()
709
843
        expected = tree.last_revision()
710
 
        out, err = self.run_bzr_error(["empty commit message"],
711
 
            "commit tree/hello.txt", stdin="n\n")
 
844
        out, err = self.run_bzr_error(["Empty commit message specified."
 
845
                                       " Please specify a commit message with either"
 
846
                                       " --message or --file or leave a blank message"
 
847
                                       " with --message \"\"."],
 
848
                                      "commit tree/hello.txt", stdin="n\n")
712
849
        self.assertEqual(expected, tree.last_revision())
 
850
 
 
851
    def test_set_commit_message(self):
 
852
        msgeditor.hooks.install_named_hook("set_commit_message",
 
853
                                           lambda commit_obj, msg: "save me some typing\n", None)
 
854
        tree = self.make_branch_and_tree('tree')
 
855
        self.build_tree(['tree/hello.txt'])
 
856
        tree.add('hello.txt')
 
857
        out, err = self.run_bzr("commit tree/hello.txt")
 
858
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
 
859
        self.assertEqual('save me some typing\n', last_rev.message)
 
860
 
 
861
    def test_commit_without_username(self):
 
862
        """Ensure commit error if username is not set.
 
863
        """
 
864
        self.run_bzr(['init', 'foo'])
 
865
        with open('foo/foo.txt', 'w') as f:
 
866
            f.write('hello')
 
867
        self.run_bzr(['add'], working_dir='foo')
 
868
        override_whoami(self)
 
869
        self.run_bzr_error(
 
870
            ['Unable to determine your name'],
 
871
            ['commit', '-m', 'initial'], working_dir='foo')
 
872
 
 
873
    def test_commit_recursive_checkout(self):
 
874
        """Ensure that a commit to a recursive checkout fails cleanly.
 
875
        """
 
876
        self.run_bzr(['init', 'test_branch'])
 
877
        self.run_bzr(['checkout', 'test_branch', 'test_checkout'])
 
878
        # bind to self
 
879
        self.run_bzr(['bind', '.'], working_dir='test_checkout')
 
880
        with open('test_checkout/foo.txt', 'w') as f:
 
881
            f.write('hello')
 
882
        self.run_bzr(['add'], working_dir='test_checkout')
 
883
        out, err = self.run_bzr_error(
 
884
            ['Branch.*test_checkout.*appears to be bound to itself'],
 
885
            ['commit', '-m', 'addedfoo'], working_dir='test_checkout')
 
886
 
 
887
    def test_mv_dirs_non_ascii(self):
 
888
        """Move directory with non-ascii name and containing files.
 
889
 
 
890
        Regression test for bug 185211.
 
891
        """
 
892
        tree = self.make_branch_and_tree('.')
 
893
        self.build_tree([u'abc\xa7/', u'abc\xa7/foo'])
 
894
 
 
895
        tree.add([u'abc\xa7/', u'abc\xa7/foo'])
 
896
        tree.commit('checkin')
 
897
 
 
898
        tree.rename_one(u'abc\xa7', 'abc')
 
899
 
 
900
        self.run_bzr('ci -m "non-ascii mv"')
 
901