1ef154bb1a4f

Add file-level commenting.
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Mon, 05 Oct 2009 20:50:06 -0400
parents 7e437c5261bb
children 34caeeba9ae2
branches/tags (none)
files review/extension_ui.py review/messages.py review/tests/test_comment.py review/tests/util.py

Changes

--- a/review/extension_ui.py	Mon Oct 05 19:45:45 2009 -0400
+++ b/review/extension_ui.py	Mon Oct 05 20:50:06 2009 -0400
@@ -1,5 +1,6 @@
 '''The review extension's UI.'''
 
+import os
 import messages
 from api import *
 from mercurial import util
@@ -17,18 +18,27 @@
             ui.note(messages.INIT_EXISTS_COMMITTED)
         else:
             raise util.Abort(messages.INIT_EXISTS_UNCOMMITTED)
-        return
 
-def _comment_command(ui, repo, **opts):
+def _comment_command(ui, repo, *fnames, **opts):
+    rev = opts.pop('rev')
+    filename = fnames[0] if fnames else ''
+    message = opts.pop('message')
+    
     rd = ReviewDatastore(ui, repo)
-    rcset = rd[opts.pop('rev')]
-    message = opts.pop('message')
+    rcset = rd[rev]
+    
+    if filename:
+        filename = os.path.relpath(filename, start=repo.root)
+        
+        if filename not in repo[rcset.node].files():
+            raise util.Abort(
+                messages.COMMENT_FILE_DOES_NOT_EXIST % (filename, repo[rev].rev())
+            )
     
     if not message:
         raise util.Abort(messages.COMMENT_REQUIRES_MESSAGE)
     
-    rcset.add_comment(message=message)
-    return
+    rcset.add_comment(message=message, filename=filename)
 
 def _signoff_command(ui, repo, **opts):
     rd = ReviewDatastore(ui, repo)
@@ -48,11 +58,10 @@
             force=opts.pop('force'))
     except SignoffExists:
         raise util.Abort(messages.SIGNOFF_EXISTS)
-    
-    return
 
 def _review_command(ui, repo, *fnames, **opts):
     rev = opts.pop('rev')
+    
     rd = ReviewDatastore(ui, repo)
     cset = repo[rev]
     rcset = rd[rev]
@@ -81,6 +90,13 @@
         header = messages.REVIEW_LOG_FILE_HEADER % filename
         print '\n\n%s %s' % (header, '-'*(80-(len(header)+1)))
         
+        file_level_comments = filter(lambda c: filename == c.filename, rcset.comments)
+        for comment in file_level_comments:
+            ui.write(messages.REVIEW_LOG_COMMENT_AUTHOR % comment.author)
+            for line in comment.message.splitlines():
+                ui.write(messages.REVIEW_LOG_COMMENT_LINE % line)
+            
+        
         content = diffs[filename].splitlines()[2:]
         
         prefix = '%%%dd: ' % len(str(len(content)-1))
@@ -94,7 +110,7 @@
     if opts.pop('init'):
         return _init_command(ui, repo, **opts)
     elif opts.pop('comment'):
-        return _comment_command(ui, repo, **opts)
+        return _comment_command(ui, repo, *fnames, **opts)
     elif opts.pop('signoff'):
         return _signoff_command(ui, repo, **opts)
     else:
@@ -103,16 +119,17 @@
 
 cmdtable = {
     'review': (review, [
-        ('i', 'init', False, 'start code reviewing this repository'),
-        ('', 'local-path', '', 'the local path to the code review data'),
-        ('', 'remote-path', '', 'the remote path to code review data'),
-        ('c', 'comment', False, 'add a comment'),
-        ('s', 'signoff', False, 'sign off'),
-        ('', 'yes', False, 'sign off as stating the changeset is good'),
-        ('', 'no', False, 'sign off as stating the changeset is bad'),
-        ('m', 'message', '', 'use <text> as the comment or signoff message'),
-        ('', 'force', False, 'overwrite an existing signoff'),
-        ('r', 'rev', '.', 'the revision to review'),
+        ('i', 'init',        False, 'start code reviewing this repository'),
+        ('',  'local-path',  '',    'the local path to the code review data'),
+        ('',  'remote-path', '',    'the remote path to code review data'),
+        ('c', 'comment',     False, 'add a comment'),
+        ('s', 'signoff',     False, 'sign off'),
+        ('',  'yes',         False, 'sign off as stating the changeset is good'),
+        ('',  'no',          False, 'sign off as stating the changeset is bad'),
+        ('m', 'message',     '',    'use <text> as the comment or signoff message'),
+        ('',  'force',       False, 'overwrite an existing signoff'),
+        ('f', 'file',        '',    'comment on <file>'),
+        ('r', 'rev',         '.',   'the revision to review'),
     ],
     'hg review')
 }
\ No newline at end of file
--- a/review/messages.py	Mon Oct 05 19:45:45 2009 -0400
+++ b/review/messages.py	Mon Oct 05 20:50:06 2009 -0400
@@ -22,6 +22,10 @@
 a message must be provided to add a comment!
 '''
 
+COMMENT_FILE_DOES_NOT_EXIST = '''\
+file %s was not changed in revision %s!
+'''
+
 SIGNOFF_REQUIRES_MESSAGE = '''\
 a message must be provided to sign off!
 '''
--- a/review/tests/test_comment.py	Mon Oct 05 19:45:45 2009 -0400
+++ b/review/tests/test_comment.py	Mon Oct 05 20:50:06 2009 -0400
@@ -78,3 +78,40 @@
     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)
+def test_add_comments_to_file():
+    sandbox = get_sandbox_repo()
+    
+    author_line = messages.REVIEW_LOG_COMMENT_AUTHOR % '|'
+    a1, _, a2 = author_line.partition('|')
+    
+    review(comment=True, message='Test comment one.', rev='1', files=['file_one'])
+    
+    output = review(rev='1', files=['file_one'])
+    assert a1 in output
+    assert a2 in output
+    assert messages.REVIEW_LOG_COMMENT_LINE % 'Test comment one.' in output
+    
+    output = review(rev='1', files=['file_two'])
+    assert messages.REVIEW_LOG_COMMENT_LINE % 'Test comment one.' not in output
+    
+    output = review(rev='0', files=['file_one'])
+    assert a1 not in output
+    assert a2 not in output
+    assert messages.REVIEW_LOG_COMMENT_LINE % 'Test comment one.' not in output
+
+
+@with_setup(setup_reviewed_sandbox, teardown_sandbox)
+def test_add_comments_to_bad_file():
+    sandbox = get_sandbox_repo()
+    
+    try:
+        review(comment=True, message='Test comment one.', files=['bad'])
+    except hgutil.Abort, e:
+        error = str(e)
+        assert messages.COMMENT_FILE_DOES_NOT_EXIST % ('bad', '2') in error
+    else:
+        assert False, 'The correct error message was not printed.'
+    
+
--- a/review/tests/util.py	Mon Oct 05 19:45:45 2009 -0400
+++ b/review/tests/util.py	Mon Oct 05 20:50:06 2009 -0400
@@ -6,13 +6,15 @@
 
 _ui = ui.ui()
 def review(init=False, comment=False, signoff=False, yes=False, no=False,
-    force=False, message='', rev='.', local_path='', remote_path=''):
+    force=False, message='', rev='.', local_path='', remote_path='', files=None):
+    
+    files = files if files else []
     
     _ui.pushbuffer()
-    extension_ui.review(_ui, get_sandbox_repo(),
+    extension_ui.review(_ui, get_sandbox_repo(), *files,
         init=init, comment=comment, signoff=signoff, yes=yes, no=no, 
-        force=force, message=message, rev=rev, local_path=local_path,
-        remote_path=remote_path)
+        force=force, message=message, rev=rev,
+        local_path=local_path, remote_path=remote_path )
     output = _ui.popbuffer()
     
     print output