# HG changeset patch # User Steve Losh # Date 1254786345 14400 # Node ID 7e437c5261bb9791a9254204456329428b0a0089 # Parent 60a287538a94b18cfd8ee9a2e9d0d4a51f1b41e6 Output diffs (with line numbers) and review-level comments for review. Parsing and formatting unified diffs is hard, let's ride bikes^H^H^H^H^H^H^H^H^H^H^H drink beer! diff -r 60a287538a94 -r 7e437c5261bb review/api.py --- a/review/api.py Sun Oct 04 22:25:33 2009 -0400 +++ b/review/api.py Mon Oct 05 19:45:45 2009 -0400 @@ -6,7 +6,7 @@ import os import messages, templates from datetime import datetime -from mercurial import cmdutil, hg +from mercurial import cmdutil, hg, patch from mercurial.node import hex from mercurial.util import sha1 @@ -90,13 +90,14 @@ def __getitem__(self, rev): '''Return a ReviewChangeset for the given revision.''' node = hex(self.target[rev].node()) - return ReviewChangeset(self.ui, self.repo, node) + return ReviewChangeset(self.ui, self.repo, self.target, node) class ReviewChangeset(object): '''The review data about one changeset in the target repository.''' - def __init__(self, ui, repo, node): + def __init__(self, ui, repo, target, node): self.repo = repo + self.target = target self.ui = ui self.node = node @@ -146,6 +147,34 @@ self.node, filename, lines, message) comment.commit(self.ui, self.repo) + def full_diffs(self, filenames=None, opts={}): + '''Return diffs of the given files.''' + + target_files = self.target[self.node].files() + if not filenames: + filenames = target_files + else: + filenames = filter(lambda f: f in target_files, filenames) + + opts['unified'] = '100000' + node2 = self.node + node1 = self.target[node2].parents()[0].node() + + diffs = {} + for filename in filenames: + m = cmdutil.matchfiles(self.target, [filename]) + d = patch.diff(self.target, node1, node2, match=m, + opts=patch.diffopts(self.ui, opts)) + + # patch.diff will give us back a generator with two items + # the first is the diff header, which we don't care about + d.next() + + # the second is the diff's contents, which is what we want + diffs[filename] = d.next() + + return diffs + class _ReviewObject(object): '''Some kind of object.''' diff -r 60a287538a94 -r 7e437c5261bb review/extension_ui.py --- a/review/extension_ui.py Sun Oct 04 22:25:33 2009 -0400 +++ b/review/extension_ui.py Mon Oct 05 19:45:45 2009 -0400 @@ -51,7 +51,7 @@ return -def _review_command(ui, repo, **opts): +def _review_command(ui, repo, *fnames, **opts): rev = opts.pop('rev') rd = ReviewDatastore(ui, repo) cset = repo[rev] @@ -66,6 +66,26 @@ ui.write(messages.REVIEW_LOG_SIGNOFFS % len(rcset.signoffs)) ui.write(messages.REVIEW_LOG_COMMENTS % (comment_count, author_count)) + + review_level_comments = filter(lambda c: not c.filename, rcset.comments) + if review_level_comments: + ui.write('\n') + for comment in review_level_comments: + ui.write('\n' + messages.REVIEW_LOG_COMMENT_AUTHOR % comment.author) + for line in comment.message.splitlines(): + ui.write(messages.REVIEW_LOG_COMMENT_LINE % line) + + diffs = rcset.full_diffs(fnames, opts) + + for filename in diffs: + header = messages.REVIEW_LOG_FILE_HEADER % filename + print '\n\n%s %s' % (header, '-'*(80-(len(header)+1))) + + content = diffs[filename].splitlines()[2:] + + prefix = '%%%dd: ' % len(str(len(content)-1)) + for n, line in enumerate(content): + ui.write('%s %s\n' % (prefix % n, line)) def review(ui, repo, *fnames, **opts): @@ -78,7 +98,7 @@ elif opts.pop('signoff'): return _signoff_command(ui, repo, **opts) else: - return _review_command(ui, repo, **opts) + return _review_command(ui, repo, *fnames, **opts) cmdtable = { diff -r 60a287538a94 -r 7e437c5261bb review/messages.py --- a/review/messages.py Sun Oct 04 22:25:33 2009 -0400 +++ b/review/messages.py Mon Oct 05 19:45:45 2009 -0400 @@ -53,9 +53,17 @@ REVIEW_LOG_COMMENTS = '''\ comments: %d comments from %d authors - ''' +REVIEW_LOG_FILE_HEADER = '''changes in %s''' + +REVIEW_LOG_COMMENT_AUTHOR = '''\ +# %s said: +''' + +REVIEW_LOG_COMMENT_LINE = '''\ +# %s +''' COMMIT_COMMENT = '''Add a comment on changeset %s''' COMMIT_SIGNOFF = '''Sign off on changeset %s''' diff -r 60a287538a94 -r 7e437c5261bb review/tests/test_comment.py --- a/review/tests/test_comment.py Sun Oct 04 22:25:33 2009 -0400 +++ b/review/tests/test_comment.py Mon Oct 05 19:45:45 2009 -0400 @@ -36,10 +36,19 @@ output = review() assert messages.REVIEW_LOG_COMMENTS % (1, 1) in output + author_line = messages.REVIEW_LOG_COMMENT_AUTHOR % '|' + a1, _, a2 = author_line.partition('|') + assert a1 in output + assert a2 in output + + assert messages.REVIEW_LOG_COMMENT_LINE % 'Test comment one.' in output + review(comment=True, message='Test comment two.') output = review() assert messages.REVIEW_LOG_COMMENTS % (2, 1) in output + assert messages.REVIEW_LOG_COMMENT_LINE % 'Test comment one.' in output + assert messages.REVIEW_LOG_COMMENT_LINE % 'Test comment two.' in output @with_setup(setup_reviewed_sandbox, teardown_sandbox) @@ -51,11 +60,21 @@ output = review(rev='0') assert messages.REVIEW_LOG_COMMENTS % (1, 1) in output + author_line = messages.REVIEW_LOG_COMMENT_AUTHOR % '|' + a1, _, a2 = author_line.partition('|') + assert a1 in output + assert a2 in output + + assert messages.REVIEW_LOG_COMMENT_LINE % 'Test comment one.' in output + output = review() assert messages.REVIEW_LOG_COMMENTS % (0, 0) in output + assert messages.REVIEW_LOG_COMMENT_LINE % 'Test comment one.' not in output review(comment=True, message='Test comment two.', rev='0') output = review(rev='0') assert messages.REVIEW_LOG_COMMENTS % (2, 1) in output + assert messages.REVIEW_LOG_COMMENT_LINE % 'Test comment one.' in output + assert messages.REVIEW_LOG_COMMENT_LINE % 'Test comment two.' in output