18
18
from cStringIO import StringIO
20
20
from bzrlib import (
32
class TestLogMixin(object):
34
def wt_commit(self, wt, message, **kwargs):
35
"""Use some mostly fixed values for commits to simplify tests.
37
Tests can use this function to get some commit attributes. The time
38
stamp is incremented at each commit.
40
if getattr(self, 'timestamp', None) is None:
41
self.timestamp = 1132617600 # Mon 2005-11-22 00:00:00 +0000
43
self.timestamp += 1 # 1 second between each commit
44
kwargs.setdefault('timestamp', self.timestamp)
45
kwargs.setdefault('timezone', 0) # UTC
46
kwargs.setdefault('committer', 'Joe Foo <joe@foo.com>')
48
return wt.commit(message, **kwargs)
51
class TestCaseForLogFormatter(tests.TestCaseWithTransport, TestLogMixin):
30
class TestCaseWithoutPropsHandler(tests.TestCaseWithTransport):
54
super(TestCaseForLogFormatter, self).setUp()
33
super(TestCaseWithoutPropsHandler, self).setUp()
55
34
# keep a reference to the "current" custom prop. handler registry
56
35
self.properties_handler_registry = log.properties_handler_registry
57
# Use a clean registry for log
36
# clean up the registry in log
58
37
log.properties_handler_registry = registry.Registry()
61
log.properties_handler_registry = self.properties_handler_registry
62
self.addCleanup(restore)
64
def assertFormatterResult(self, result, branch, formatter_class,
65
formatter_kwargs=None, show_log_kwargs=None):
66
logfile = self.make_utf8_encoded_stringio()
67
if formatter_kwargs is None:
69
formatter = formatter_class(to_file=logfile, **formatter_kwargs)
70
if show_log_kwargs is None:
72
log.show_log(branch, formatter, **show_log_kwargs)
73
self.assertEqualDiff(result, logfile.getvalue())
75
def make_standard_commit(self, branch_nick, **kwargs):
76
wt = self.make_branch_and_tree('.')
78
self.addCleanup(wt.unlock)
79
self.build_tree(['a'])
81
wt.branch.nick = branch_nick
82
kwargs.setdefault('committer', 'Lorem Ipsum <test@example.com>')
83
kwargs.setdefault('authors', ['John Doe <jdoe@example.com>'])
84
self.wt_commit(wt, 'add a', **kwargs)
87
def make_commits_with_trailing_newlines(self, wt):
88
"""Helper method for LogFormatter tests"""
91
self.build_tree_contents([('a', 'hello moto\n')])
92
self.wt_commit(wt, 'simple log message', rev_id='a1')
93
self.build_tree_contents([('b', 'goodbye\n')])
95
self.wt_commit(wt, 'multiline\nlog\nmessage\n', rev_id='a2')
97
self.build_tree_contents([('c', 'just another manic monday\n')])
99
self.wt_commit(wt, 'single line with trailing newline\n', rev_id='a3')
102
def _prepare_tree_with_merges(self, with_tags=False):
103
wt = self.make_branch_and_memory_tree('.')
105
self.addCleanup(wt.unlock)
107
self.wt_commit(wt, 'rev-1', rev_id='rev-1')
108
self.wt_commit(wt, 'rev-merged', rev_id='rev-2a')
109
wt.set_parent_ids(['rev-1', 'rev-2a'])
110
wt.branch.set_last_revision_info(1, 'rev-1')
111
self.wt_commit(wt, 'rev-2', rev_id='rev-2b')
114
branch.tags.set_tag('v0.2', 'rev-2b')
115
self.wt_commit(wt, 'rev-3', rev_id='rev-3')
116
branch.tags.set_tag('v1.0rc1', 'rev-3')
117
branch.tags.set_tag('v1.0', 'rev-3')
40
super(TestCaseWithoutPropsHandler, self)._cleanup()
41
# restore the custom properties handler registry
42
log.properties_handler_registry = self.properties_handler_registry
121
45
class LogCatcher(log.LogFormatter):
122
"""Pull log messages into a list rather than displaying them.
124
To simplify testing we save logged revisions here rather than actually
125
formatting anything, so that we can precisely check the result without
126
being dependent on the formatting.
46
"""Pull log messages into list rather than displaying them.
48
For ease of testing we save log messages here rather than actually
49
formatting them, so that we can precisely check the result without
50
being too dependent on the exact formatting.
52
We should also test the LogFormatter.
129
supports_merge_revisions = True
130
55
supports_delta = True
134
def __init__(self, *args, **kwargs):
135
kwargs.update(dict(to_file=None))
136
super(LogCatcher, self).__init__(*args, **kwargs)
58
super(LogCatcher, self).__init__(to_file=None)
139
61
def log_revision(self, revision):
140
self.revisions.append(revision)
62
self.logs.append(revision)
143
65
class TestShowLog(tests.TestCaseWithTransport):
263
181
lf.supports_merge_revisions = True
264
182
log.show_log(b, lf, verbose=True)
267
self.assertEqual(3, len(revs))
184
self.assertEqual(3, len(lf.logs))
186
logentry = lf.logs[0]
270
187
self.assertEqual('2', logentry.revno)
271
188
self.assertEqual('merge child branch', logentry.rev.message)
272
189
self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
191
logentry = lf.logs[1]
275
192
self.assertEqual('1.1.1', logentry.revno)
276
193
self.assertEqual('remove file1 and modify file2', logentry.rev.message)
277
194
self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
196
logentry = lf.logs[2]
280
197
self.assertEqual('1', logentry.revno)
281
198
self.assertEqual('add file1 and file2', logentry.rev.message)
282
199
self.checkDelta(logentry.delta, added=['file1', 'file2'])
285
class TestShortLogFormatter(TestCaseForLogFormatter):
202
def make_commits_with_trailing_newlines(wt):
203
"""Helper method for LogFormatter tests"""
206
open('a', 'wb').write('hello moto\n')
208
wt.commit('simple log message', rev_id='a1',
209
timestamp=1132586655.459960938, timezone=-6*3600,
210
committer='Joe Foo <joe@foo.com>')
211
open('b', 'wb').write('goodbye\n')
213
wt.commit('multiline\nlog\nmessage\n', rev_id='a2',
214
timestamp=1132586842.411175966, timezone=-6*3600,
215
committer='Joe Foo <joe@foo.com>',
216
authors=['Joe Bar <joe@bar.com>'])
218
open('c', 'wb').write('just another manic monday\n')
220
wt.commit('single line with trailing newline\n', rev_id='a3',
221
timestamp=1132587176.835228920, timezone=-6*3600,
222
committer = 'Joe Foo <joe@foo.com>')
226
def normalize_log(log):
227
"""Replaces the variable lines of logs with fixed lines"""
228
author = 'author: Dolor Sit <test@example.com>'
229
committer = 'committer: Lorem Ipsum <test@example.com>'
230
lines = log.splitlines(True)
231
for idx,line in enumerate(lines):
232
stripped_line = line.lstrip()
233
indent = ' ' * (len(line) - len(stripped_line))
234
if stripped_line.startswith('author:'):
235
lines[idx] = indent + author + '\n'
236
elif stripped_line.startswith('committer:'):
237
lines[idx] = indent + committer + '\n'
238
elif stripped_line.startswith('timestamp:'):
239
lines[idx] = indent + 'timestamp: Just now\n'
240
return ''.join(lines)
243
class TestShortLogFormatter(tests.TestCaseWithTransport):
287
245
def test_trailing_newlines(self):
288
246
wt = self.make_branch_and_tree('.')
289
b = self.make_commits_with_trailing_newlines(wt)
290
self.assertFormatterResult("""\
291
3 Joe Foo\t2005-11-22
247
b = make_commits_with_trailing_newlines(wt)
248
sio = self.make_utf8_encoded_stringio()
249
lf = log.ShortLogFormatter(to_file=sio)
251
self.assertEqualDiff("""\
252
3 Joe Foo\t2005-11-21
292
253
single line with trailing newline
294
2 Joe Foo\t2005-11-22
255
2 Joe Bar\t2005-11-21
299
1 Joe Foo\t2005-11-22
260
1 Joe Foo\t2005-11-21
300
261
simple log message
303
b, log.ShortLogFormatter)
266
def _prepare_tree_with_merges(self, with_tags=False):
267
wt = self.make_branch_and_memory_tree('.')
269
self.addCleanup(wt.unlock)
271
wt.commit('rev-1', rev_id='rev-1',
272
timestamp=1132586655, timezone=36000,
273
committer='Joe Foo <joe@foo.com>')
274
wt.commit('rev-merged', rev_id='rev-2a',
275
timestamp=1132586700, timezone=36000,
276
committer='Joe Foo <joe@foo.com>')
277
wt.set_parent_ids(['rev-1', 'rev-2a'])
278
wt.branch.set_last_revision_info(1, 'rev-1')
279
wt.commit('rev-2', rev_id='rev-2b',
280
timestamp=1132586800, timezone=36000,
281
committer='Joe Foo <joe@foo.com>')
284
branch.tags.set_tag('v0.2', 'rev-2b')
285
wt.commit('rev-3', rev_id='rev-3',
286
timestamp=1132586900, timezone=36000,
287
committer='Jane Foo <jane@foo.com>')
288
branch.tags.set_tag('v1.0rc1', 'rev-3')
289
branch.tags.set_tag('v1.0', 'rev-3')
305
292
def test_short_log_with_merges(self):
306
293
wt = self._prepare_tree_with_merges()
307
self.assertFormatterResult("""\
294
logfile = self.make_utf8_encoded_stringio()
295
formatter = log.ShortLogFormatter(to_file=logfile)
296
log.show_log(wt.branch, formatter)
297
self.assertEqualDiff("""\
308
298
2 Joe Foo\t2005-11-22 [merge]
326
320
Use --include-merges or -n0 to see merged revisions.
328
wt.branch, log.ShortLogFormatter,
329
formatter_kwargs=dict(show_advice=True))
331
324
def test_short_log_with_merges_and_range(self):
332
wt = self._prepare_tree_with_merges()
333
self.wt_commit(wt, 'rev-3a', rev_id='rev-3a')
325
wt = self.make_branch_and_memory_tree('.')
327
self.addCleanup(wt.unlock)
329
wt.commit('rev-1', rev_id='rev-1',
330
timestamp=1132586655, timezone=36000,
331
committer='Joe Foo <joe@foo.com>')
332
wt.commit('rev-merged', rev_id='rev-2a',
333
timestamp=1132586700, timezone=36000,
334
committer='Joe Foo <joe@foo.com>')
335
wt.branch.set_last_revision_info(1, 'rev-1')
336
wt.set_parent_ids(['rev-1', 'rev-2a'])
337
wt.commit('rev-2b', rev_id='rev-2b',
338
timestamp=1132586800, timezone=36000,
339
committer='Joe Foo <joe@foo.com>')
340
wt.commit('rev-3a', rev_id='rev-3a',
341
timestamp=1132586800, timezone=36000,
342
committer='Joe Foo <joe@foo.com>')
334
343
wt.branch.set_last_revision_info(2, 'rev-2b')
335
344
wt.set_parent_ids(['rev-2b', 'rev-3a'])
336
self.wt_commit(wt, 'rev-3b', rev_id='rev-3b')
337
self.assertFormatterResult("""\
345
wt.commit('rev-3b', rev_id='rev-3b',
346
timestamp=1132586800, timezone=36000,
347
committer='Joe Foo <joe@foo.com>')
348
logfile = self.make_utf8_encoded_stringio()
349
formatter = log.ShortLogFormatter(to_file=logfile)
350
log.show_log(wt.branch, formatter,
351
start_revision=2, end_revision=3)
352
self.assertEqualDiff("""\
338
353
3 Joe Foo\t2005-11-22 [merge]
341
356
2 Joe Foo\t2005-11-22 [merge]
345
wt.branch, log.ShortLogFormatter,
346
show_log_kwargs=dict(start_revision=2, end_revision=3))
348
362
def test_short_log_with_tags(self):
349
363
wt = self._prepare_tree_with_merges(with_tags=True)
350
self.assertFormatterResult("""\
351
3 Joe Foo\t2005-11-22 {v1.0, v1.0rc1}
364
logfile = self.make_utf8_encoded_stringio()
365
formatter = log.ShortLogFormatter(to_file=logfile)
366
log.show_log(wt.branch, formatter)
367
self.assertEqualDiff("""\
368
3 Jane Foo\t2005-11-22 {v1.0, v1.0rc1}
354
371
2 Joe Foo\t2005-11-22 {v0.2} [merge]
361
wt.branch, log.ShortLogFormatter)
363
380
def test_short_log_single_merge_revision(self):
364
wt = self._prepare_tree_with_merges()
381
wt = self.make_branch_and_memory_tree('.')
383
self.addCleanup(wt.unlock)
385
wt.commit('rev-1', rev_id='rev-1',
386
timestamp=1132586655, timezone=36000,
387
committer='Joe Foo <joe@foo.com>')
388
wt.commit('rev-merged', rev_id='rev-2a',
389
timestamp=1132586700, timezone=36000,
390
committer='Joe Foo <joe@foo.com>')
391
wt.set_parent_ids(['rev-1', 'rev-2a'])
392
wt.branch.set_last_revision_info(1, 'rev-1')
393
wt.commit('rev-2', rev_id='rev-2b',
394
timestamp=1132586800, timezone=36000,
395
committer='Joe Foo <joe@foo.com>')
396
logfile = self.make_utf8_encoded_stringio()
397
formatter = log.ShortLogFormatter(to_file=logfile)
365
398
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
366
rev = revspec.in_history(wt.branch)
367
self.assertFormatterResult("""\
400
rev = revspec.in_history(wtb)
401
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
402
self.assertEqualDiff("""\
368
403
1.1.1 Joe Foo\t2005-11-22
372
wt.branch, log.ShortLogFormatter,
373
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
375
def test_show_ids(self):
376
wt = self.make_branch_and_tree('parent')
377
self.build_tree(['parent/f1', 'parent/f2'])
379
self.wt_commit(wt, 'first post', rev_id='a')
380
child_wt = wt.bzrdir.sprout('child').open_workingtree()
381
self.wt_commit(child_wt, 'branch 1 changes', rev_id='b')
382
wt.merge_from_branch(child_wt.branch)
383
self.wt_commit(wt, 'merge branch 1', rev_id='c')
384
self.assertFormatterResult("""\
385
2 Joe Foo\t2005-11-22 [merge]
389
1.1.1 Joe Foo\t2005-11-22
393
1 Joe Foo\t2005-11-22
398
wt.branch, log.ShortLogFormatter,
399
formatter_kwargs=dict(levels=0,show_ids=True))
402
class TestShortLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
410
class TestShortLogFormatterWithMergeRevisions(tests.TestCaseWithTransport):
404
412
def test_short_merge_revs_log_with_merges(self):
405
wt = self._prepare_tree_with_merges()
413
wt = self.make_branch_and_memory_tree('.')
415
self.addCleanup(wt.unlock)
417
wt.commit('rev-1', rev_id='rev-1',
418
timestamp=1132586655, timezone=36000,
419
committer='Joe Foo <joe@foo.com>')
420
wt.commit('rev-merged', rev_id='rev-2a',
421
timestamp=1132586700, timezone=36000,
422
committer='Joe Foo <joe@foo.com>')
423
wt.set_parent_ids(['rev-1', 'rev-2a'])
424
wt.branch.set_last_revision_info(1, 'rev-1')
425
wt.commit('rev-2', rev_id='rev-2b',
426
timestamp=1132586800, timezone=36000,
427
committer='Joe Foo <joe@foo.com>')
428
logfile = self.make_utf8_encoded_stringio()
429
formatter = log.ShortLogFormatter(to_file=logfile, levels=0)
430
log.show_log(wt.branch, formatter)
406
431
# Note that the 1.1.1 indenting is in fact correct given that
407
432
# the revision numbers are right justified within 5 characters
408
433
# for mainline revnos and 9 characters for dotted revnos.
409
self.assertFormatterResult("""\
434
self.assertEqualDiff("""\
410
435
2 Joe Foo\t2005-11-22 [merge]
420
wt.branch, log.ShortLogFormatter,
421
formatter_kwargs=dict(levels=0))
423
447
def test_short_merge_revs_log_single_merge_revision(self):
424
wt = self._prepare_tree_with_merges()
448
wt = self.make_branch_and_memory_tree('.')
450
self.addCleanup(wt.unlock)
452
wt.commit('rev-1', rev_id='rev-1',
453
timestamp=1132586655, timezone=36000,
454
committer='Joe Foo <joe@foo.com>')
455
wt.commit('rev-merged', rev_id='rev-2a',
456
timestamp=1132586700, timezone=36000,
457
committer='Joe Foo <joe@foo.com>')
458
wt.set_parent_ids(['rev-1', 'rev-2a'])
459
wt.branch.set_last_revision_info(1, 'rev-1')
460
wt.commit('rev-2', rev_id='rev-2b',
461
timestamp=1132586800, timezone=36000,
462
committer='Joe Foo <joe@foo.com>')
463
logfile = self.make_utf8_encoded_stringio()
464
formatter = log.ShortLogFormatter(to_file=logfile, levels=0)
425
465
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
426
rev = revspec.in_history(wt.branch)
427
self.assertFormatterResult("""\
467
rev = revspec.in_history(wtb)
468
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
469
self.assertEqualDiff("""\
428
470
1.1.1 Joe Foo\t2005-11-22
432
wt.branch, log.ShortLogFormatter,
433
formatter_kwargs=dict(levels=0),
434
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
437
class TestLongLogFormatter(TestCaseForLogFormatter):
477
class TestLongLogFormatter(TestCaseWithoutPropsHandler):
439
479
def test_verbose_log(self):
440
480
"""Verbose log includes changed files
444
wt = self.make_standard_commit('test_verbose_log', authors=[])
445
self.assertFormatterResult('''\
484
wt = self.make_branch_and_tree('.')
486
self.build_tree(['a'])
488
# XXX: why does a longer nick show up?
489
b.nick = 'test_verbose_log'
490
wt.commit(message='add a',
491
timestamp=1132711707,
493
committer='Lorem Ipsum <test@example.com>')
494
logfile = file('out.tmp', 'w+')
495
formatter = log.LongLogFormatter(to_file=logfile)
496
log.show_log(b, formatter, verbose=True)
499
log_contents = logfile.read()
500
self.assertEqualDiff('''\
446
501
------------------------------------------------------------
448
503
committer: Lorem Ipsum <test@example.com>
449
504
branch nick: test_verbose_log
450
timestamp: Tue 2005-11-22 00:00:00 +0000
505
timestamp: Wed 2005-11-23 12:08:27 +1000
456
wt.branch, log.LongLogFormatter,
457
show_log_kwargs=dict(verbose=True))
459
513
def test_merges_are_indented_by_level(self):
460
514
wt = self.make_branch_and_tree('parent')
461
self.wt_commit(wt, 'first post')
462
child_wt = wt.bzrdir.sprout('child').open_workingtree()
463
self.wt_commit(child_wt, 'branch 1')
464
smallerchild_wt = wt.bzrdir.sprout('smallerchild').open_workingtree()
465
self.wt_commit(smallerchild_wt, 'branch 2')
466
child_wt.merge_from_branch(smallerchild_wt.branch)
467
self.wt_commit(child_wt, 'merge branch 2')
468
wt.merge_from_branch(child_wt.branch)
469
self.wt_commit(wt, 'merge branch 1')
470
self.assertFormatterResult("""\
515
wt.commit('first post')
516
self.run_bzr('branch parent child')
517
self.run_bzr(['commit', '-m', 'branch 1', '--unchanged', 'child'])
518
self.run_bzr('branch child smallerchild')
519
self.run_bzr(['commit', '-m', 'branch 2', '--unchanged',
522
self.run_bzr('merge ../smallerchild')
523
self.run_bzr(['commit', '-m', 'merge branch 2'])
524
os.chdir('../parent')
525
self.run_bzr('merge ../child')
526
wt.commit('merge branch 1')
528
sio = self.make_utf8_encoded_stringio()
529
lf = log.LongLogFormatter(to_file=sio, levels=0)
530
log.show_log(b, lf, verbose=True)
531
the_log = normalize_log(sio.getvalue())
532
self.assertEqualDiff("""\
471
533
------------------------------------------------------------
473
committer: Joe Foo <joe@foo.com>
535
committer: Lorem Ipsum <test@example.com>
474
536
branch nick: parent
475
timestamp: Tue 2005-11-22 00:00:04 +0000
478
540
------------------------------------------------------------
479
541
revno: 1.1.2 [merge]
480
committer: Joe Foo <joe@foo.com>
542
committer: Lorem Ipsum <test@example.com>
481
543
branch nick: child
482
timestamp: Tue 2005-11-22 00:00:03 +0000
485
547
------------------------------------------------------------
487
committer: Joe Foo <joe@foo.com>
549
committer: Lorem Ipsum <test@example.com>
488
550
branch nick: smallerchild
489
timestamp: Tue 2005-11-22 00:00:02 +0000
492
554
------------------------------------------------------------
494
committer: Joe Foo <joe@foo.com>
556
committer: Lorem Ipsum <test@example.com>
495
557
branch nick: child
496
timestamp: Tue 2005-11-22 00:00:01 +0000
499
561
------------------------------------------------------------
501
committer: Joe Foo <joe@foo.com>
563
committer: Lorem Ipsum <test@example.com>
502
564
branch nick: parent
503
timestamp: Tue 2005-11-22 00:00:00 +0000
507
wt.branch, log.LongLogFormatter,
508
formatter_kwargs=dict(levels=0),
509
show_log_kwargs=dict(verbose=True))
511
571
def test_verbose_merge_revisions_contain_deltas(self):
512
572
wt = self.make_branch_and_tree('parent')
513
573
self.build_tree(['parent/f1', 'parent/f2'])
514
574
wt.add(['f1','f2'])
515
self.wt_commit(wt, 'first post')
516
child_wt = wt.bzrdir.sprout('child').open_workingtree()
575
wt.commit('first post')
576
self.run_bzr('branch parent child')
517
577
os.unlink('child/f1')
518
self.build_tree_contents([('child/f2', 'hello\n')])
519
self.wt_commit(child_wt, 'removed f1 and modified f2')
520
wt.merge_from_branch(child_wt.branch)
521
self.wt_commit(wt, 'merge branch 1')
522
self.assertFormatterResult("""\
578
file('child/f2', 'wb').write('hello\n')
579
self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
582
self.run_bzr('merge ../child')
583
wt.commit('merge branch 1')
585
sio = self.make_utf8_encoded_stringio()
586
lf = log.LongLogFormatter(to_file=sio, levels=0)
587
log.show_log(b, lf, verbose=True)
588
the_log = normalize_log(sio.getvalue())
589
self.assertEqualDiff("""\
523
590
------------------------------------------------------------
525
committer: Joe Foo <joe@foo.com>
592
committer: Lorem Ipsum <test@example.com>
526
593
branch nick: parent
527
timestamp: Tue 2005-11-22 00:00:02 +0000
582
651
committer: Joe Foo <joe@foo.com>
583
652
branch nick: test
584
timestamp: Tue 2005-11-22 00:00:00 +0000
653
timestamp: Mon 2005-11-21 09:24:15 -0600
586
655
simple log message
588
b, log.LongLogFormatter)
590
659
def test_author_in_log(self):
591
660
"""Log includes the author name if it's set in
592
661
the revision properties
594
wt = self.make_standard_commit('test_author_log',
595
authors=['John Doe <jdoe@example.com>',
596
'Jane Rey <jrey@example.com>'])
597
self.assertFormatterResult("""\
663
wt = self.make_branch_and_tree('.')
665
self.build_tree(['a'])
667
b.nick = 'test_author_log'
668
wt.commit(message='add a',
669
timestamp=1132711707,
671
committer='Lorem Ipsum <test@example.com>',
672
authors=['John Doe <jdoe@example.com>',
673
'Jane Rey <jrey@example.com>'])
675
formatter = log.LongLogFormatter(to_file=sio)
676
log.show_log(b, formatter)
677
self.assertEqualDiff('''\
598
678
------------------------------------------------------------
600
680
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
601
681
committer: Lorem Ipsum <test@example.com>
602
682
branch nick: test_author_log
603
timestamp: Tue 2005-11-22 00:00:00 +0000
683
timestamp: Wed 2005-11-23 12:08:27 +1000
607
wt.branch, log.LongLogFormatter)
609
689
def test_properties_in_log(self):
610
690
"""Log includes the custom properties returned by the registered
613
wt = self.make_standard_commit('test_properties_in_log')
614
def trivial_custom_prop_handler(revision):
615
return {'test_prop':'test_value'}
693
wt = self.make_branch_and_tree('.')
695
self.build_tree(['a'])
697
b.nick = 'test_properties_in_log'
698
wt.commit(message='add a',
699
timestamp=1132711707,
701
committer='Lorem Ipsum <test@example.com>',
702
authors=['John Doe <jdoe@example.com>'])
704
formatter = log.LongLogFormatter(to_file=sio)
706
def trivial_custom_prop_handler(revision):
707
return {'test_prop':'test_value'}
617
# Cleaned up in setUp()
618
log.properties_handler_registry.register(
619
'trivial_custom_prop_handler',
620
trivial_custom_prop_handler)
621
self.assertFormatterResult("""\
709
log.properties_handler_registry.register(
710
'trivial_custom_prop_handler',
711
trivial_custom_prop_handler)
712
log.show_log(b, formatter)
714
log.properties_handler_registry.remove(
715
'trivial_custom_prop_handler')
716
self.assertEqualDiff('''\
622
717
------------------------------------------------------------
624
719
test_prop: test_value
625
720
author: John Doe <jdoe@example.com>
626
721
committer: Lorem Ipsum <test@example.com>
627
722
branch nick: test_properties_in_log
628
timestamp: Tue 2005-11-22 00:00:00 +0000
723
timestamp: Wed 2005-11-23 12:08:27 +1000
632
wt.branch, log.LongLogFormatter)
634
729
def test_properties_in_short_log(self):
635
730
"""Log includes the custom properties returned by the registered
638
wt = self.make_standard_commit('test_properties_in_short_log')
639
def trivial_custom_prop_handler(revision):
640
return {'test_prop':'test_value'}
733
wt = self.make_branch_and_tree('.')
735
self.build_tree(['a'])
737
b.nick = 'test_properties_in_short_log'
738
wt.commit(message='add a',
739
timestamp=1132711707,
741
committer='Lorem Ipsum <test@example.com>',
742
authors=['John Doe <jdoe@example.com>'])
744
formatter = log.ShortLogFormatter(to_file=sio)
746
def trivial_custom_prop_handler(revision):
747
return {'test_prop':'test_value'}
642
log.properties_handler_registry.register(
643
'trivial_custom_prop_handler',
644
trivial_custom_prop_handler)
645
self.assertFormatterResult("""\
646
1 John Doe\t2005-11-22
749
log.properties_handler_registry.register(
750
'trivial_custom_prop_handler',
751
trivial_custom_prop_handler)
752
log.show_log(b, formatter)
754
log.properties_handler_registry.remove(
755
'trivial_custom_prop_handler')
756
self.assertEqualDiff('''\
757
1 John Doe\t2005-11-23
647
758
test_prop: test_value
651
wt.branch, log.ShortLogFormatter)
653
764
def test_error_in_properties_handler(self):
654
765
"""Log includes the custom properties returned by the registered
657
wt = self.make_standard_commit('error_in_properties_handler',
658
revprops={'first_prop':'first_value'})
659
sio = self.make_utf8_encoded_stringio()
768
wt = self.make_branch_and_tree('.')
770
self.build_tree(['a'])
772
b.nick = 'test_author_log'
773
wt.commit(message='add a',
774
timestamp=1132711707,
776
committer='Lorem Ipsum <test@example.com>',
777
authors=['John Doe <jdoe@example.com>'],
778
revprops={'first_prop':'first_value'})
660
780
formatter = log.LongLogFormatter(to_file=sio)
661
def trivial_custom_prop_handler(revision):
662
raise StandardError("a test error")
782
def trivial_custom_prop_handler(revision):
783
raise StandardError("a test error")
664
log.properties_handler_registry.register(
665
'trivial_custom_prop_handler',
666
trivial_custom_prop_handler)
667
self.assertRaises(StandardError, log.show_log, wt.branch, formatter,)
785
log.properties_handler_registry.register(
786
'trivial_custom_prop_handler',
787
trivial_custom_prop_handler)
788
self.assertRaises(StandardError, log.show_log, b, formatter,)
790
log.properties_handler_registry.remove(
791
'trivial_custom_prop_handler')
669
793
def test_properties_handler_bad_argument(self):
670
wt = self.make_standard_commit('bad_argument',
671
revprops={'a_prop':'test_value'})
672
sio = self.make_utf8_encoded_stringio()
794
wt = self.make_branch_and_tree('.')
796
self.build_tree(['a'])
798
b.nick = 'test_author_log'
799
wt.commit(message='add a',
800
timestamp=1132711707,
802
committer='Lorem Ipsum <test@example.com>',
803
authors=['John Doe <jdoe@example.com>'],
804
revprops={'a_prop':'test_value'})
673
806
formatter = log.LongLogFormatter(to_file=sio)
674
def bad_argument_prop_handler(revision):
675
return {'custom_prop_name':revision.properties['a_prop']}
677
log.properties_handler_registry.register(
678
'bad_argument_prop_handler',
679
bad_argument_prop_handler)
681
self.assertRaises(AttributeError, formatter.show_properties,
684
revision = wt.branch.repository.get_revision(wt.branch.last_revision())
685
formatter.show_properties(revision, '')
686
self.assertEqualDiff('''custom_prop_name: test_value\n''',
689
def test_show_ids(self):
690
wt = self.make_branch_and_tree('parent')
691
self.build_tree(['parent/f1', 'parent/f2'])
693
self.wt_commit(wt, 'first post', rev_id='a')
694
child_wt = wt.bzrdir.sprout('child').open_workingtree()
695
self.wt_commit(child_wt, 'branch 1 changes', rev_id='b')
696
wt.merge_from_branch(child_wt.branch)
697
self.wt_commit(wt, 'merge branch 1', rev_id='c')
698
self.assertFormatterResult("""\
699
------------------------------------------------------------
704
committer: Joe Foo <joe@foo.com>
706
timestamp: Tue 2005-11-22 00:00:02 +0000
709
------------------------------------------------------------
713
committer: Joe Foo <joe@foo.com>
715
timestamp: Tue 2005-11-22 00:00:01 +0000
718
------------------------------------------------------------
721
committer: Joe Foo <joe@foo.com>
723
timestamp: Tue 2005-11-22 00:00:00 +0000
727
wt.branch, log.LongLogFormatter,
728
formatter_kwargs=dict(levels=0,show_ids=True))
731
class TestLongLogFormatterWithoutMergeRevisions(TestCaseForLogFormatter):
808
def bad_argument_prop_handler(revision):
809
return {'custom_prop_name':revision.properties['a_prop']}
811
log.properties_handler_registry.register(
812
'bad_argument_prop_handler',
813
bad_argument_prop_handler)
815
self.assertRaises(AttributeError, formatter.show_properties,
818
revision = b.repository.get_revision(b.last_revision())
819
formatter.show_properties(revision, '')
820
self.assertEqualDiff('''custom_prop_name: test_value\n''',
823
log.properties_handler_registry.remove(
824
'bad_argument_prop_handler')
827
class TestLongLogFormatterWithoutMergeRevisions(TestCaseWithoutPropsHandler):
733
829
def test_long_verbose_log(self):
734
830
"""Verbose log includes changed files
738
wt = self.make_standard_commit('test_long_verbose_log', authors=[])
739
self.assertFormatterResult("""\
834
wt = self.make_branch_and_tree('.')
836
self.build_tree(['a'])
838
# XXX: why does a longer nick show up?
839
b.nick = 'test_verbose_log'
840
wt.commit(message='add a',
841
timestamp=1132711707,
843
committer='Lorem Ipsum <test@example.com>')
844
logfile = file('out.tmp', 'w+')
845
formatter = log.LongLogFormatter(to_file=logfile, levels=1)
846
log.show_log(b, formatter, verbose=True)
849
log_contents = logfile.read()
850
self.assertEqualDiff('''\
740
851
------------------------------------------------------------
742
853
committer: Lorem Ipsum <test@example.com>
743
branch nick: test_long_verbose_log
744
timestamp: Tue 2005-11-22 00:00:00 +0000
854
branch nick: test_verbose_log
855
timestamp: Wed 2005-11-23 12:08:27 +1000
750
wt.branch, log.LongLogFormatter,
751
formatter_kwargs=dict(levels=1),
752
show_log_kwargs=dict(verbose=True))
754
863
def test_long_verbose_contain_deltas(self):
755
864
wt = self.make_branch_and_tree('parent')
756
865
self.build_tree(['parent/f1', 'parent/f2'])
757
866
wt.add(['f1','f2'])
758
self.wt_commit(wt, 'first post')
759
child_wt = wt.bzrdir.sprout('child').open_workingtree()
867
wt.commit('first post')
868
self.run_bzr('branch parent child')
760
869
os.unlink('child/f1')
761
self.build_tree_contents([('child/f2', 'hello\n')])
762
self.wt_commit(child_wt, 'removed f1 and modified f2')
763
wt.merge_from_branch(child_wt.branch)
764
self.wt_commit(wt, 'merge branch 1')
765
self.assertFormatterResult("""\
870
file('child/f2', 'wb').write('hello\n')
871
self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
874
self.run_bzr('merge ../child')
875
wt.commit('merge branch 1')
877
sio = self.make_utf8_encoded_stringio()
878
lf = log.LongLogFormatter(to_file=sio, levels=1)
879
log.show_log(b, lf, verbose=True)
880
the_log = normalize_log(sio.getvalue())
881
self.assertEqualDiff("""\
766
882
------------------------------------------------------------
768
committer: Joe Foo <joe@foo.com>
884
committer: Lorem Ipsum <test@example.com>
769
885
branch nick: parent
770
timestamp: Tue 2005-11-22 00:00:02 +0000
814
932
committer: Joe Foo <joe@foo.com>
815
933
branch nick: test
816
timestamp: Tue 2005-11-22 00:00:00 +0000
934
timestamp: Mon 2005-11-21 09:24:15 -0600
818
936
simple log message
820
b, log.LongLogFormatter,
821
formatter_kwargs=dict(levels=1))
823
940
def test_long_author_in_log(self):
824
941
"""Log includes the author name if it's set in
825
942
the revision properties
827
wt = self.make_standard_commit('test_author_log')
828
self.assertFormatterResult("""\
944
wt = self.make_branch_and_tree('.')
946
self.build_tree(['a'])
948
b.nick = 'test_author_log'
949
wt.commit(message='add a',
950
timestamp=1132711707,
952
committer='Lorem Ipsum <test@example.com>',
953
authors=['John Doe <jdoe@example.com>'])
955
formatter = log.LongLogFormatter(to_file=sio, levels=1)
956
log.show_log(b, formatter)
957
self.assertEqualDiff('''\
829
958
------------------------------------------------------------
831
960
author: John Doe <jdoe@example.com>
832
961
committer: Lorem Ipsum <test@example.com>
833
962
branch nick: test_author_log
834
timestamp: Tue 2005-11-22 00:00:00 +0000
963
timestamp: Wed 2005-11-23 12:08:27 +1000
838
wt.branch, log.LongLogFormatter,
839
formatter_kwargs=dict(levels=1))
841
969
def test_long_properties_in_log(self):
842
970
"""Log includes the custom properties returned by the registered
845
wt = self.make_standard_commit('test_properties_in_log')
846
def trivial_custom_prop_handler(revision):
847
return {'test_prop':'test_value'}
973
wt = self.make_branch_and_tree('.')
975
self.build_tree(['a'])
977
b.nick = 'test_properties_in_log'
978
wt.commit(message='add a',
979
timestamp=1132711707,
981
committer='Lorem Ipsum <test@example.com>',
982
authors=['John Doe <jdoe@example.com>'])
984
formatter = log.LongLogFormatter(to_file=sio, levels=1)
986
def trivial_custom_prop_handler(revision):
987
return {'test_prop':'test_value'}
849
log.properties_handler_registry.register(
850
'trivial_custom_prop_handler',
851
trivial_custom_prop_handler)
852
self.assertFormatterResult("""\
989
log.properties_handler_registry.register(
990
'trivial_custom_prop_handler',
991
trivial_custom_prop_handler)
992
log.show_log(b, formatter)
994
log.properties_handler_registry.remove(
995
'trivial_custom_prop_handler')
996
self.assertEqualDiff('''\
853
997
------------------------------------------------------------
855
999
test_prop: test_value
856
1000
author: John Doe <jdoe@example.com>
857
1001
committer: Lorem Ipsum <test@example.com>
858
1002
branch nick: test_properties_in_log
859
timestamp: Tue 2005-11-22 00:00:00 +0000
1003
timestamp: Wed 2005-11-23 12:08:27 +1000
863
wt.branch, log.LongLogFormatter,
864
formatter_kwargs=dict(levels=1))
867
class TestLineLogFormatter(TestCaseForLogFormatter):
1010
class TestLineLogFormatter(tests.TestCaseWithTransport):
869
1012
def test_line_log(self):
870
1013
"""Line log should show revno
874
wt = self.make_standard_commit('test-line-log',
875
committer='Line-Log-Formatter Tester <test@line.log>',
877
self.assertFormatterResult("""\
878
1: Line-Log-Formatte... 2005-11-22 add a
880
wt.branch, log.LineLogFormatter)
1017
wt = self.make_branch_and_tree('.')
1019
self.build_tree(['a'])
1021
b.nick = 'test-line-log'
1022
wt.commit(message='add a',
1023
timestamp=1132711707,
1025
committer='Line-Log-Formatter Tester <test@line.log>')
1026
logfile = file('out.tmp', 'w+')
1027
formatter = log.LineLogFormatter(to_file=logfile)
1028
log.show_log(b, formatter)
1031
log_contents = logfile.read()
1032
self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
882
1035
def test_trailing_newlines(self):
883
1036
wt = self.make_branch_and_tree('.')
884
b = self.make_commits_with_trailing_newlines(wt)
885
self.assertFormatterResult("""\
886
3: Joe Foo 2005-11-22 single line with trailing newline
887
2: Joe Foo 2005-11-22 multiline
888
1: Joe Foo 2005-11-22 simple log message
1037
b = make_commits_with_trailing_newlines(wt)
1038
sio = self.make_utf8_encoded_stringio()
1039
lf = log.LineLogFormatter(to_file=sio)
1041
self.assertEqualDiff("""\
1042
3: Joe Foo 2005-11-21 single line with trailing newline
1043
2: Joe Bar 2005-11-21 multiline
1044
1: Joe Foo 2005-11-21 simple log message
890
b, log.LineLogFormatter)
1048
def _prepare_tree_with_merges(self, with_tags=False):
1049
wt = self.make_branch_and_memory_tree('.')
1051
self.addCleanup(wt.unlock)
1053
wt.commit('rev-1', rev_id='rev-1',
1054
timestamp=1132586655, timezone=36000,
1055
committer='Joe Foo <joe@foo.com>')
1056
wt.commit('rev-merged', rev_id='rev-2a',
1057
timestamp=1132586700, timezone=36000,
1058
committer='Joe Foo <joe@foo.com>')
1059
wt.set_parent_ids(['rev-1', 'rev-2a'])
1060
wt.branch.set_last_revision_info(1, 'rev-1')
1061
wt.commit('rev-2', rev_id='rev-2b',
1062
timestamp=1132586800, timezone=36000,
1063
committer='Joe Foo <joe@foo.com>')
1066
branch.tags.set_tag('v0.2', 'rev-2b')
1067
wt.commit('rev-3', rev_id='rev-3',
1068
timestamp=1132586900, timezone=36000,
1069
committer='Jane Foo <jane@foo.com>')
1070
branch.tags.set_tag('v1.0rc1', 'rev-3')
1071
branch.tags.set_tag('v1.0', 'rev-3')
892
1074
def test_line_log_single_merge_revision(self):
893
1075
wt = self._prepare_tree_with_merges()
1076
logfile = self.make_utf8_encoded_stringio()
1077
formatter = log.LineLogFormatter(to_file=logfile)
894
1078
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
895
rev = revspec.in_history(wt.branch)
896
self.assertFormatterResult("""\
1080
rev = revspec.in_history(wtb)
1081
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1082
self.assertEqualDiff("""\
897
1083
1.1.1: Joe Foo 2005-11-22 rev-merged
899
wt.branch, log.LineLogFormatter,
900
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
902
1087
def test_line_log_with_tags(self):
903
1088
wt = self._prepare_tree_with_merges(with_tags=True)
904
self.assertFormatterResult("""\
905
3: Joe Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
1089
logfile = self.make_utf8_encoded_stringio()
1090
formatter = log.LineLogFormatter(to_file=logfile)
1091
log.show_log(wt.branch, formatter)
1092
self.assertEqualDiff("""\
1093
3: Jane Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
906
1094
2: Joe Foo 2005-11-22 [merge] {v0.2} rev-2
907
1095
1: Joe Foo 2005-11-22 rev-1
909
wt.branch, log.LineLogFormatter)
912
class TestLineLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
1099
class TestLineLogFormatterWithMergeRevisions(tests.TestCaseWithTransport):
914
1101
def test_line_merge_revs_log(self):
915
1102
"""Line log should show revno
919
wt = self.make_standard_commit('test-line-log',
920
committer='Line-Log-Formatter Tester <test@line.log>',
922
self.assertFormatterResult("""\
923
1: Line-Log-Formatte... 2005-11-22 add a
925
wt.branch, log.LineLogFormatter)
1106
wt = self.make_branch_and_tree('.')
1108
self.build_tree(['a'])
1110
b.nick = 'test-line-log'
1111
wt.commit(message='add a',
1112
timestamp=1132711707,
1114
committer='Line-Log-Formatter Tester <test@line.log>')
1115
logfile = file('out.tmp', 'w+')
1116
formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1117
log.show_log(b, formatter)
1120
log_contents = logfile.read()
1121
self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
927
1124
def test_line_merge_revs_log_single_merge_revision(self):
928
wt = self._prepare_tree_with_merges()
1125
wt = self.make_branch_and_memory_tree('.')
1127
self.addCleanup(wt.unlock)
1129
wt.commit('rev-1', rev_id='rev-1',
1130
timestamp=1132586655, timezone=36000,
1131
committer='Joe Foo <joe@foo.com>')
1132
wt.commit('rev-merged', rev_id='rev-2a',
1133
timestamp=1132586700, timezone=36000,
1134
committer='Joe Foo <joe@foo.com>')
1135
wt.set_parent_ids(['rev-1', 'rev-2a'])
1136
wt.branch.set_last_revision_info(1, 'rev-1')
1137
wt.commit('rev-2', rev_id='rev-2b',
1138
timestamp=1132586800, timezone=36000,
1139
committer='Joe Foo <joe@foo.com>')
1140
logfile = self.make_utf8_encoded_stringio()
1141
formatter = log.LineLogFormatter(to_file=logfile, levels=0)
929
1142
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
930
rev = revspec.in_history(wt.branch)
931
self.assertFormatterResult("""\
1144
rev = revspec.in_history(wtb)
1145
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1146
self.assertEqualDiff("""\
932
1147
1.1.1: Joe Foo 2005-11-22 rev-merged
934
wt.branch, log.LineLogFormatter,
935
formatter_kwargs=dict(levels=0),
936
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
938
1151
def test_line_merge_revs_log_with_merges(self):
939
wt = self._prepare_tree_with_merges()
940
self.assertFormatterResult("""\
1152
wt = self.make_branch_and_memory_tree('.')
1154
self.addCleanup(wt.unlock)
1156
wt.commit('rev-1', rev_id='rev-1',
1157
timestamp=1132586655, timezone=36000,
1158
committer='Joe Foo <joe@foo.com>')
1159
wt.commit('rev-merged', rev_id='rev-2a',
1160
timestamp=1132586700, timezone=36000,
1161
committer='Joe Foo <joe@foo.com>')
1162
wt.set_parent_ids(['rev-1', 'rev-2a'])
1163
wt.branch.set_last_revision_info(1, 'rev-1')
1164
wt.commit('rev-2', rev_id='rev-2b',
1165
timestamp=1132586800, timezone=36000,
1166
committer='Joe Foo <joe@foo.com>')
1167
logfile = self.make_utf8_encoded_stringio()
1168
formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1169
log.show_log(wt.branch, formatter)
1170
self.assertEqualDiff("""\
941
1171
2: Joe Foo 2005-11-22 [merge] rev-2
942
1172
1.1.1: Joe Foo 2005-11-22 rev-merged
943
1173
1: Joe Foo 2005-11-22 rev-1
945
wt.branch, log.LineLogFormatter,
946
formatter_kwargs=dict(levels=0))
949
class TestGnuChangelogFormatter(TestCaseForLogFormatter):
951
def test_gnu_changelog(self):
952
wt = self.make_standard_commit('nicky', authors=[])
953
self.assertFormatterResult('''\
954
2005-11-22 Lorem Ipsum <test@example.com>
959
wt.branch, log.GnuChangelogLogFormatter)
961
def test_with_authors(self):
962
wt = self.make_standard_commit('nicky',
963
authors=['Fooa Fooz <foo@example.com>',
964
'Bari Baro <bar@example.com>'])
965
self.assertFormatterResult('''\
966
2005-11-22 Fooa Fooz <foo@example.com>
971
wt.branch, log.GnuChangelogLogFormatter)
973
def test_verbose(self):
974
wt = self.make_standard_commit('nicky')
975
self.assertFormatterResult('''\
976
2005-11-22 John Doe <jdoe@example.com>
983
wt.branch, log.GnuChangelogLogFormatter,
984
show_log_kwargs=dict(verbose=True))
986
class TestGetViewRevisions(tests.TestCaseWithTransport, TestLogMixin):
988
def _get_view_revisions(self, *args, **kwargs):
989
return self.applyDeprecated(symbol_versioning.deprecated_in((2, 2, 0)),
990
log.get_view_revisions, *args, **kwargs)
1177
class TestGetViewRevisions(tests.TestCaseWithTransport):
992
1179
def make_tree_with_commits(self):
993
1180
"""Create a tree with well-known revision ids"""
994
1181
wt = self.make_branch_and_tree('tree1')
995
self.wt_commit(wt, 'commit one', rev_id='1')
996
self.wt_commit(wt, 'commit two', rev_id='2')
997
self.wt_commit(wt, 'commit three', rev_id='3')
1182
wt.commit('commit one', rev_id='1')
1183
wt.commit('commit two', rev_id='2')
1184
wt.commit('commit three', rev_id='3')
998
1185
mainline_revs = [None, '1', '2', '3']
999
1186
rev_nos = {'1': 1, '2': 2, '3': 3}
1000
1187
return mainline_revs, rev_nos, wt
1003
1190
"""Create a tree with well-known revision ids and a merge"""
1004
1191
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1005
1192
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1006
self.wt_commit(tree2, 'four-a', rev_id='4a')
1193
tree2.commit('four-a', rev_id='4a')
1007
1194
wt.merge_from_branch(tree2.branch)
1008
self.wt_commit(wt, 'four-b', rev_id='4b')
1195
wt.commit('four-b', rev_id='4b')
1009
1196
mainline_revs.append('4b')
1010
1197
rev_nos['4b'] = 4
1012
1199
return mainline_revs, rev_nos, wt
1014
def make_branch_with_many_merges(self):
1201
def make_tree_with_many_merges(self):
1015
1202
"""Create a tree with well-known revision ids"""
1016
builder = self.make_branch_builder('tree1')
1017
builder.start_series()
1018
builder.build_snapshot('1', None, [
1019
('add', ('', 'TREE_ROOT', 'directory', '')),
1020
('add', ('f', 'f-id', 'file', '1\n'))])
1021
builder.build_snapshot('2', ['1'], [])
1022
builder.build_snapshot('3a', ['2'], [
1023
('modify', ('f-id', '1\n2\n3a\n'))])
1024
builder.build_snapshot('3b', ['2', '3a'], [
1025
('modify', ('f-id', '1\n2\n3a\n'))])
1026
builder.build_snapshot('3c', ['2', '3b'], [
1027
('modify', ('f-id', '1\n2\n3a\n'))])
1028
builder.build_snapshot('4a', ['3b'], [])
1029
builder.build_snapshot('4b', ['3c', '4a'], [])
1030
builder.finish_series()
1203
wt = self.make_branch_and_tree('tree1')
1204
self.build_tree_contents([('tree1/f', '1\n')])
1205
wt.add(['f'], ['f-id'])
1206
wt.commit('commit one', rev_id='1')
1207
wt.commit('commit two', rev_id='2')
1209
tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
1210
self.build_tree_contents([('tree3/f', '1\n2\n3a\n')])
1211
tree3.commit('commit three a', rev_id='3a')
1213
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1214
tree2.merge_from_branch(tree3.branch)
1215
tree2.commit('commit three b', rev_id='3b')
1217
wt.merge_from_branch(tree2.branch)
1218
wt.commit('commit three c', rev_id='3c')
1219
tree2.commit('four-a', rev_id='4a')
1221
wt.merge_from_branch(tree2.branch)
1222
wt.commit('four-b', rev_id='4b')
1044
1224
mainline_revs = [None, '1', '2', '3c', '4b']
1045
1225
rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
1119
1299
def test_get_view_revisions_merge2(self):
1120
1300
"""Test get_view_revisions when there are merges"""
1121
mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1123
self.addCleanup(b.unlock)
1124
revisions = list(self._get_view_revisions(
1125
mainline_revs, rev_nos, b, 'forward'))
1301
mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
1303
self.addCleanup(wt.unlock)
1304
revisions = list(log.get_view_revisions(
1305
mainline_revs, rev_nos, wt.branch, 'forward'))
1126
1306
expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1127
('3b', '2.2.1', 1), ('3a', '2.1.1', 2), ('4b', '4', 0),
1307
('3a', '2.1.1', 1), ('3b', '2.2.1', 1), ('4b', '4', 0),
1128
1308
('4a', '2.2.2', 1)]
1129
1309
self.assertEqual(expected, revisions)
1130
revisions = list(self._get_view_revisions(
1131
mainline_revs, rev_nos, b, 'forward',
1310
revisions = list(log.get_view_revisions(
1311
mainline_revs, rev_nos, wt.branch, 'forward',
1132
1312
include_merges=False))
1133
1313
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1134
1314
('4b', '4', 0)],
1137
1318
def test_file_id_for_range(self):
1138
mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1140
self.addCleanup(b.unlock)
1319
mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
1321
self.addCleanup(wt.unlock)
1142
1323
def rev_from_rev_id(revid, branch):
1143
1324
revspec = revisionspec.RevisionSpec.from_string('revid:%s' % revid)
1144
1325
return revspec.in_history(branch)
1146
1327
def view_revs(start_rev, end_rev, file_id, direction):
1147
revs = self.applyDeprecated(
1148
symbol_versioning.deprecated_in((2, 2, 0)),
1149
log.calculate_view_revisions,
1328
revs = log.calculate_view_revisions(
1151
1330
start_rev, # start_revision
1152
1331
end_rev, # end_revision
1153
1332
direction, # direction
1343
1513
class TestLogFormatter(tests.TestCase):
1346
super(TestLogFormatter, self).setUp()
1347
self.rev = revision.Revision('a-id')
1348
self.lf = log.LogFormatter(None)
1350
1515
def test_short_committer(self):
1351
def assertCommitter(expected, committer):
1352
self.rev.committer = committer
1353
self.assertEqual(expected, self.lf.short_committer(self.rev))
1355
assertCommitter('John Doe', 'John Doe <jdoe@example.com>')
1356
assertCommitter('John Smith', 'John Smith <jsmith@example.com>')
1357
assertCommitter('John Smith', 'John Smith')
1358
assertCommitter('jsmith@example.com', 'jsmith@example.com')
1359
assertCommitter('jsmith@example.com', '<jsmith@example.com>')
1360
assertCommitter('John Smith', 'John Smith jsmith@example.com')
1516
rev = revision.Revision('a-id')
1517
rev.committer = 'John Doe <jdoe@example.com>'
1518
lf = log.LogFormatter(None)
1519
self.assertEqual('John Doe', lf.short_committer(rev))
1520
rev.committer = 'John Smith <jsmith@example.com>'
1521
self.assertEqual('John Smith', lf.short_committer(rev))
1522
rev.committer = 'John Smith'
1523
self.assertEqual('John Smith', lf.short_committer(rev))
1524
rev.committer = 'jsmith@example.com'
1525
self.assertEqual('jsmith@example.com', lf.short_committer(rev))
1526
rev.committer = '<jsmith@example.com>'
1527
self.assertEqual('jsmith@example.com', lf.short_committer(rev))
1528
rev.committer = 'John Smith jsmith@example.com'
1529
self.assertEqual('John Smith', lf.short_committer(rev))
1362
1531
def test_short_author(self):
1363
def assertAuthor(expected, author):
1364
self.rev.properties['author'] = author
1365
self.assertEqual(expected, self.lf.short_author(self.rev))
1367
assertAuthor('John Smith', 'John Smith <jsmith@example.com>')
1368
assertAuthor('John Smith', 'John Smith')
1369
assertAuthor('jsmith@example.com', 'jsmith@example.com')
1370
assertAuthor('jsmith@example.com', '<jsmith@example.com>')
1371
assertAuthor('John Smith', 'John Smith jsmith@example.com')
1373
def test_short_author_from_committer(self):
1374
self.rev.committer = 'John Doe <jdoe@example.com>'
1375
self.assertEqual('John Doe', self.lf.short_author(self.rev))
1377
def test_short_author_from_authors(self):
1378
self.rev.properties['authors'] = ('John Smith <jsmith@example.com>\n'
1379
'Jane Rey <jrey@example.com>')
1380
self.assertEqual('John Smith', self.lf.short_author(self.rev))
1532
rev = revision.Revision('a-id')
1533
rev.committer = 'John Doe <jdoe@example.com>'
1534
lf = log.LogFormatter(None)
1535
self.assertEqual('John Doe', lf.short_author(rev))
1536
rev.properties['author'] = 'John Smith <jsmith@example.com>'
1537
self.assertEqual('John Smith', lf.short_author(rev))
1538
rev.properties['author'] = 'John Smith'
1539
self.assertEqual('John Smith', lf.short_author(rev))
1540
rev.properties['author'] = 'jsmith@example.com'
1541
self.assertEqual('jsmith@example.com', lf.short_author(rev))
1542
rev.properties['author'] = '<jsmith@example.com>'
1543
self.assertEqual('jsmith@example.com', lf.short_author(rev))
1544
rev.properties['author'] = 'John Smith jsmith@example.com'
1545
self.assertEqual('John Smith', lf.short_author(rev))
1546
del rev.properties['author']
1547
rev.properties['authors'] = ('John Smith <jsmith@example.com>\n'
1548
'Jane Rey <jrey@example.com>')
1549
self.assertEqual('John Smith', lf.short_author(rev))
1383
1552
class TestReverseByDepth(tests.TestCase):
1529
1698
log.show_branch_change(tree.branch, s, 3, '3b')
1530
1699
self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1531
1700
self.assertNotContainsRe(s.getvalue(), 'Added Revisions:')
1534
class TestRevisionNotInBranch(TestCaseForLogFormatter):
1536
def setup_a_tree(self):
1537
tree = self.make_branch_and_tree('tree')
1539
self.addCleanup(tree.unlock)
1541
'committer': 'Joe Foo <joe@foo.com>',
1542
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1543
'timezone': 0, # UTC
1545
tree.commit('commit 1a', rev_id='1a', **kwargs)
1546
tree.commit('commit 2a', rev_id='2a', **kwargs)
1547
tree.commit('commit 3a', rev_id='3a', **kwargs)
1550
def setup_ab_tree(self):
1551
tree = self.setup_a_tree()
1552
tree.set_last_revision('1a')
1553
tree.branch.set_last_revision_info(1, '1a')
1555
'committer': 'Joe Foo <joe@foo.com>',
1556
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1557
'timezone': 0, # UTC
1559
tree.commit('commit 2b', rev_id='2b', **kwargs)
1560
tree.commit('commit 3b', rev_id='3b', **kwargs)
1563
def test_one_revision(self):
1564
tree = self.setup_ab_tree()
1566
rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1567
log.show_log(tree.branch, lf, verbose=True, start_revision=rev,
1569
self.assertEqual(1, len(lf.revisions))
1570
self.assertEqual(None, lf.revisions[0].revno) # Out-of-branch
1571
self.assertEqual('3a', lf.revisions[0].rev.revision_id)
1573
def test_many_revisions(self):
1574
tree = self.setup_ab_tree()
1576
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1577
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1578
log.show_log(tree.branch, lf, verbose=True, start_revision=start_rev,
1579
end_revision=end_rev)
1580
self.assertEqual(3, len(lf.revisions))
1581
self.assertEqual(None, lf.revisions[0].revno) # Out-of-branch
1582
self.assertEqual('3a', lf.revisions[0].rev.revision_id)
1583
self.assertEqual(None, lf.revisions[1].revno) # Out-of-branch
1584
self.assertEqual('2a', lf.revisions[1].rev.revision_id)
1585
self.assertEqual('1', lf.revisions[2].revno) # In-branch
1587
def test_long_format(self):
1588
tree = self.setup_ab_tree()
1589
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1590
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1591
self.assertFormatterResult("""\
1592
------------------------------------------------------------
1594
committer: Joe Foo <joe@foo.com>
1596
timestamp: Tue 2005-11-22 00:00:00 +0000
1599
------------------------------------------------------------
1601
committer: Joe Foo <joe@foo.com>
1603
timestamp: Tue 2005-11-22 00:00:00 +0000
1606
------------------------------------------------------------
1608
committer: Joe Foo <joe@foo.com>
1610
timestamp: Tue 2005-11-22 00:00:00 +0000
1614
tree.branch, log.LongLogFormatter, show_log_kwargs={
1615
'start_revision': start_rev, 'end_revision': end_rev
1618
def test_short_format(self):
1619
tree = self.setup_ab_tree()
1620
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1621
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1622
self.assertFormatterResult("""\
1631
1 Joe Foo\t2005-11-22
1635
tree.branch, log.ShortLogFormatter, show_log_kwargs={
1636
'start_revision': start_rev, 'end_revision': end_rev
1639
def test_line_format(self):
1640
tree = self.setup_ab_tree()
1641
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1642
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1643
self.assertFormatterResult("""\
1644
Joe Foo 2005-11-22 commit 3a
1645
Joe Foo 2005-11-22 commit 2a
1646
1: Joe Foo 2005-11-22 commit 1a
1648
tree.branch, log.LineLogFormatter, show_log_kwargs={
1649
'start_revision': start_rev, 'end_revision': end_rev
1653
class TestLogWithBugs(TestCaseForLogFormatter, TestLogMixin):
1656
TestCaseForLogFormatter.setUp(self)
1657
log.properties_handler_registry.register(
1658
'bugs_properties_handler',
1659
log._bugs_properties_handler)
1661
def make_commits_with_bugs(self):
1662
"""Helper method for LogFormatter tests"""
1663
tree = self.make_branch_and_tree(u'.')
1664
self.build_tree(['a', 'b'])
1666
self.wt_commit(tree, 'simple log message', rev_id='a1',
1667
revprops={'bugs': 'test://bug/id fixed'})
1669
self.wt_commit(tree, 'multiline\nlog\nmessage\n', rev_id='a2',
1670
authors=['Joe Bar <joe@bar.com>'],
1671
revprops={'bugs': 'test://bug/id fixed\n'
1672
'test://bug/2 fixed'})
1676
def test_long_bugs(self):
1677
tree = self.make_commits_with_bugs()
1678
self.assertFormatterResult("""\
1679
------------------------------------------------------------
1681
fixes bug(s): test://bug/id test://bug/2
1682
author: Joe Bar <joe@bar.com>
1683
committer: Joe Foo <joe@foo.com>
1685
timestamp: Tue 2005-11-22 00:00:01 +0000
1690
------------------------------------------------------------
1692
fixes bug(s): test://bug/id
1693
committer: Joe Foo <joe@foo.com>
1695
timestamp: Tue 2005-11-22 00:00:00 +0000
1699
tree.branch, log.LongLogFormatter)
1701
def test_short_bugs(self):
1702
tree = self.make_commits_with_bugs()
1703
self.assertFormatterResult("""\
1704
2 Joe Bar\t2005-11-22
1705
fixes bug(s): test://bug/id test://bug/2
1710
1 Joe Foo\t2005-11-22
1711
fixes bug(s): test://bug/id
1715
tree.branch, log.ShortLogFormatter)
1717
def test_wrong_bugs_property(self):
1718
tree = self.make_branch_and_tree(u'.')
1719
self.build_tree(['foo'])
1720
self.wt_commit(tree, 'simple log message', rev_id='a1',
1721
revprops={'bugs': 'test://bug/id invalid_value'})
1722
self.assertFormatterResult("""\
1723
1 Joe Foo\t2005-11-22
1727
tree.branch, log.ShortLogFormatter)
1729
def test_bugs_handler_present(self):
1730
self.properties_handler_registry.get('bugs_properties_handler')
1733
class TestLogForAuthors(TestCaseForLogFormatter):
1736
TestCaseForLogFormatter.setUp(self)
1737
self.wt = self.make_standard_commit('nicky',
1738
authors=['John Doe <jdoe@example.com>',
1739
'Jane Rey <jrey@example.com>'])
1741
def assertFormatterResult(self, formatter, who, result):
1742
formatter_kwargs = dict()
1744
author_list_handler = log.author_list_registry.get(who)
1745
formatter_kwargs['author_list_handler'] = author_list_handler
1746
TestCaseForLogFormatter.assertFormatterResult(self, result,
1747
self.wt.branch, formatter, formatter_kwargs=formatter_kwargs)
1749
def test_line_default(self):
1750
self.assertFormatterResult(log.LineLogFormatter, None, """\
1751
1: John Doe 2005-11-22 add a
1754
def test_line_committer(self):
1755
self.assertFormatterResult(log.LineLogFormatter, 'committer', """\
1756
1: Lorem Ipsum 2005-11-22 add a
1759
def test_line_first(self):
1760
self.assertFormatterResult(log.LineLogFormatter, 'first', """\
1761
1: John Doe 2005-11-22 add a
1764
def test_line_all(self):
1765
self.assertFormatterResult(log.LineLogFormatter, 'all', """\
1766
1: John Doe, Jane Rey 2005-11-22 add a
1770
def test_short_default(self):
1771
self.assertFormatterResult(log.ShortLogFormatter, None, """\
1772
1 John Doe\t2005-11-22
1777
def test_short_committer(self):
1778
self.assertFormatterResult(log.ShortLogFormatter, 'committer', """\
1779
1 Lorem Ipsum\t2005-11-22
1784
def test_short_first(self):
1785
self.assertFormatterResult(log.ShortLogFormatter, 'first', """\
1786
1 John Doe\t2005-11-22
1791
def test_short_all(self):
1792
self.assertFormatterResult(log.ShortLogFormatter, 'all', """\
1793
1 John Doe, Jane Rey\t2005-11-22
1798
def test_long_default(self):
1799
self.assertFormatterResult(log.LongLogFormatter, None, """\
1800
------------------------------------------------------------
1802
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1803
committer: Lorem Ipsum <test@example.com>
1805
timestamp: Tue 2005-11-22 00:00:00 +0000
1810
def test_long_committer(self):
1811
self.assertFormatterResult(log.LongLogFormatter, 'committer', """\
1812
------------------------------------------------------------
1814
committer: Lorem Ipsum <test@example.com>
1816
timestamp: Tue 2005-11-22 00:00:00 +0000
1821
def test_long_first(self):
1822
self.assertFormatterResult(log.LongLogFormatter, 'first', """\
1823
------------------------------------------------------------
1825
author: John Doe <jdoe@example.com>
1826
committer: Lorem Ipsum <test@example.com>
1828
timestamp: Tue 2005-11-22 00:00:00 +0000
1833
def test_long_all(self):
1834
self.assertFormatterResult(log.LongLogFormatter, 'all', """\
1835
------------------------------------------------------------
1837
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1838
committer: Lorem Ipsum <test@example.com>
1840
timestamp: Tue 2005-11-22 00:00:00 +0000
1845
def test_gnu_changelog_default(self):
1846
self.assertFormatterResult(log.GnuChangelogLogFormatter, None, """\
1847
2005-11-22 John Doe <jdoe@example.com>
1853
def test_gnu_changelog_committer(self):
1854
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'committer', """\
1855
2005-11-22 Lorem Ipsum <test@example.com>
1861
def test_gnu_changelog_first(self):
1862
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'first', """\
1863
2005-11-22 John Doe <jdoe@example.com>
1869
def test_gnu_changelog_all(self):
1870
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'all', """\
1871
2005-11-22 John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1878
class TestLogExcludeAncestry(tests.TestCaseWithTransport):
1880
def make_branch_with_alternate_ancestries(self, relpath='.'):
1881
# See test_merge_sorted_exclude_ancestry below for the difference with
1882
# bt.per_branch.test_iter_merge_sorted_revision.
1883
# TestIterMergeSortedRevisionsBushyGraph.
1884
# make_branch_with_alternate_ancestries
1885
# and test_merge_sorted_exclude_ancestry
1886
# See the FIXME in assertLogRevnos too.
1887
builder = branchbuilder.BranchBuilder(self.get_transport(relpath))
1899
builder.start_series()
1900
builder.build_snapshot('1', None, [
1901
('add', ('', 'TREE_ROOT', 'directory', '')),])
1902
builder.build_snapshot('1.1.1', ['1'], [])
1903
builder.build_snapshot('2', ['1'], [])
1904
builder.build_snapshot('1.2.1', ['1.1.1'], [])
1905
builder.build_snapshot('1.1.2', ['1.1.1', '1.2.1'], [])
1906
builder.build_snapshot('3', ['2', '1.1.2'], [])
1907
builder.finish_series()
1908
br = builder.get_branch()
1910
self.addCleanup(br.unlock)
1913
def assertLogRevnos(self, expected_revnos, b, start, end,
1914
exclude_common_ancestry, generate_merge_revisions=True):
1915
# FIXME: the layering in log makes it hard to test intermediate levels,
1916
# I wish adding filters with their parameters were easier...
1918
iter_revs = log._calc_view_revisions(
1919
b, start, end, direction='reverse',
1920
generate_merge_revisions=generate_merge_revisions,
1921
exclude_common_ancestry=exclude_common_ancestry)
1922
self.assertEqual(expected_revnos,
1923
[revid for revid, revno, depth in iter_revs])
1925
def test_merge_sorted_exclude_ancestry(self):
1926
b = self.make_branch_with_alternate_ancestries()
1927
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2', '1'],
1928
b, '1', '3', exclude_common_ancestry=False)
1929
# '2' is part of the '3' ancestry but not part of '1.1.1' ancestry so
1930
# it should be mentioned even if merge_sort order will make it appear
1932
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '2'],
1933
b, '1.1.1', '3', exclude_common_ancestry=True)
1935
def test_merge_sorted_simple_revnos_exclude_ancestry(self):
1936
b = self.make_branch_with_alternate_ancestries()
1937
self.assertLogRevnos(['3', '2'],
1938
b, '1', '3', exclude_common_ancestry=True,
1939
generate_merge_revisions=False)
1940
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2'],
1941
b, '1', '3', exclude_common_ancestry=True,
1942
generate_merge_revisions=True)