Commits

iproetel  committed e9c0f46

New command 'lpostreview' to post review requests on non-commited local changes

  • Participants
  • Parent commits 6f657c5

Comments (0)

Files changed (2)

File lpostreviews.patch

+# HG changeset patch
+# Parent 07b176e4ac4b19b93bf0f21c4b8b27a8bca27648
+
+diff -r 07b176e4ac4b mercurial_reviewboard/__init__.py
+--- a/mercurial_reviewboard/__init__.py	Tue Aug 02 18:13:00 2011 +0200
++++ b/mercurial_reviewboard/__init__.py	Tue Aug 02 18:28:29 2011 +0200
+@@ -111,6 +111,58 @@
+         repo.mq.series_dirty = True
+         repo.mq.save_dirty()
+ 
++def lpostreview(ui, repo, *files, **opts):
++    '''post an local change to a Review Board server
++
++This command creates a new review request on a Review Board server, or updates
++an existing review request, based on a not committed change in the local
++working dir.
++
++If the parent revision is not available to the Review Board server (e.g. it
++exists in your local repository but not in the one that Review Board has
++access to) you must tell postreview how to determine the base revision
++to use for a parent diff. The --outgoing, --outgoingrepo or --master options
++may be used for this purpose. The --outgoing option is the simplest of these;
++it assumes that the upstream repository specified in .hg/hgrc is the same as
++the one known to Review Board. The other two options offer more control if
++this is not the case.
++
++The --outgoing option recognizes the path entries 'reviewboard', 'default-push'
++and 'default' in this order of precedence. 'reviewboard' may be used if the
++repository accessible to Review Board is not the upstream repository.
++'''
++
++    ui.status('postreview plugin, version %s\n' % __version__)
++
++    # no branches supported
++    opts['branch']=''
++    # checks to see if the server was set
++    find_server(ui, opts)
++
++    parent  = repo['tip']
++    ui.debug('parent: %s\n' % str(parent))
++
++    opts['outgoing']='true'
++    rparent = find_rparent(ui, repo, parent, opts)
++    ui.debug('remote parent: %s\n' % rparent)
++
++    ui.debug("looking for diff in %s\n" % str(files))
++    match = cmdutil.match(repo, files, opts)
++    ui.debug("diffing %s\n" % str(match))
++    diff = getdiff(ui, repo, None, parent, match)
++    ui.debug('\n=== Diff from parent to rev ===\n')
++    ui.debug(diff + '\n')
++
++    if rparent != None and parent != rparent:
++        parentdiff = getdiff(ui, repo, parent, rparent)
++        ui.debug('\n=== Diff from rparent to parent ===\n')
++        ui.debug(parentdiff + '\n')
++    else:
++        parentdiff = ''
++
++
++    send_review(ui, repo, None, parent, diff, parentdiff, opts)
++
+ def qreviews(ui, repo, patch=None, **opts):#
+     ''' Show pending review requests for the patches.
+     '''
+@@ -248,13 +300,14 @@
+ 
+ def send_review(ui, repo, c, parentc, diff, parentdiff, opts):
+ 
+-    fields = createfields(ui, repo, c, parentc, opts)
+     reviewboard = getreviewboard(ui, opts)
+ 
+     request_id = opts['existing']
+-    if request_id and check_update(reviewboard, request_id, ui, fields, diff, parentdiff, opts):
++    if request_id and check_update(reviewboard, request_id, ui, opts):
++        fields = createfields(ui, repo, c, parentc, opts)
+         update_review(reviewboard, request_id, ui, fields, diff, parentdiff, opts)
+     else:
++        fields = createfields(ui, repo, c, parentc, opts)
+         request_id = new_review(reviewboard, ui, fields, diff, parentdiff,
+                                    opts)
+ 
+@@ -285,10 +338,16 @@
+     webbrowser.open(request_url)
+ 
+ 
+-def getdiff(ui, repo, r, parent):
++def getdiff(ui, repo, r, parent, match=None):
+     '''return diff for the specified revision'''
+     output = ""
+-    for chunk in patch.diff(repo, parent.node(), r.node()):
++    parentNode = parent.node()
++    if r:
++      revisionNode = r.node()
++    else:
++      revisionNode = None
++
++    for chunk in patch.diff(repo, parentNode, revisionNode, match):
+         output += chunk
+     return output
+ 
+@@ -346,7 +405,7 @@
+             opts['reopen'] = 'reopen'
+             return True
+ 
+-def check_update(reviewboard, request_id, ui, fields, diff, parentdiff, opts):
++def check_update(reviewboard, request_id, ui, opts):
+     ''' Test if request_id is a pending review request or if it should be reopened.
+         Returns True if an update is possible.'''
+     status = reviewboard.get_status(request_id)
+@@ -431,15 +490,18 @@
+ def createfields(ui, repo, c, parentc, opts):
+     fields = {}
+ 
+-    all_contexts = find_contexts(repo, parentc, c, opts)
++    if c:
++      all_contexts = find_contexts(repo, parentc, c, opts)
+ 
+-    if len(all_contexts) == 1 :
+-        changesets_string = '%s' % all_contexts[0].description()
++      if len(all_contexts) == 1 :
++          changesets_string = '%s' % all_contexts[0].description()
++      else:
++          changesets_string = 'changesets:\n'
++          changesets_string += \
++              ''.join(['\t%s:%s "%s"\n' % (ctx.rev(), ctx, ctx.description()) \
++                       for ctx in all_contexts])
+     else:
+-        changesets_string = 'changesets:\n'
+-        changesets_string += \
+-            ''.join(['\t%s:%s "%s"\n' % (ctx.rev(), ctx, ctx.description()) \
+-                     for ctx in all_contexts])
++      changesets_string = ''
+ 
+     if opts['branch']:
+         branch_msg = "review of branch: %s\n\n" % (c.branch())
+@@ -452,11 +514,31 @@
+     # unless specifically asked for
+     if opts['update'] or not request_id:
+ 
++        # description
++        description = ''
++        if interactive:
++            ui.status('enter description:\n')
++            description = readline().strip()
++            ui.status('append changesets to description? (Y/n):\n')
++            choice = readline().strip()
++            if choice != 'n':
++                if description:
++                    description += '\n\n'
++                description += changesets_string
++        else:
++            description = opts["description"]
++        fields['description'] = description
++
++
+         # summary
+         if opts["summary"]:
+             default_summary = opts["summary"]
+         else:
+-            default_summary = c.description().splitlines()[0]
++            lines = description.splitlines();
++            if len(lines) > 0:
++              default_summary = description.splitlines()[0]
++            else:
++              default_summary = description
+ 
+         if interactive:
+             ui.status('default summary: %s\n' % default_summary)
+@@ -469,21 +551,13 @@
+         else:
+             fields['summary'] = default_summary
+ 
+-        # description
+-        if interactive:
+-            ui.status('enter description:\n')
+-            description = readline().strip()
+-            ui.status('append changesets to description? (Y/n):\n')
+-            choice = readline().strip()
+-            if choice != 'n':
+-                if description:
+-                    description += '\n\n'
+-                description += changesets_string
++        if c:
++          fields['branch'] = c.branch()
+         else:
+-            description = changesets_string
+-        fields['description'] = description
++          fields['branch'] = 'default'
+ 
+-        fields['branch'] = c.branch()
++        if opts['tests']:
++          fields['testing_done'] = opts['tests']
+ 
+     for field in ('target_groups', 'target_people', 'bugs_closed'):
+         if opts.get(field):
+@@ -507,6 +581,10 @@
+         # python <2.6 compatibility
+         out = repo.findoutgoing(remoterepo)
+ 
++    if ctx.node():
++      ctxNode = [ctx.node()]
++    else:
++      ctxNode = None
+     for o in out:
+         orev = repo[o]
+         a, b, c = repo.changelog.nodesbetween([orev.node()], [ctx.node()])
+@@ -625,6 +703,37 @@
+ }
+ 
+ def uisetup(ui):
++    cmdtable["lpostreview"] = \
++        (lpostreview,
++         # same options as qnew, but copy them so we don't get
++         # -i/--interactive for qrecord and add white space diff options
++        [
++        ('O', 'outgoingrepo', '',
++         _('use specified repository to determine the parent diff base')),
++        ('i', 'repoid', '',
++         _('specify repository id on reviewboard server')),
++        ('s', 'summary', '', _('specify a summary for the review request')),
++        ('d', 'description', '', _('specify a description for the review request')),
++        ('', 'tests', '', _('specify used tests for the review request')),
++        ('', 'server', '', _('ReviewBoard server URL')),
++        ('e', 'existing', '', _('existing request ID to update')),
++        ('u', 'update', False, _('update the fields of an existing request')),
++        ('p', 'publish', None, _('publish request immediately')),
++        ('', 'parent', '', _('parent revision for the uploaded diff')),
++        ('I', 'interactive', False,
++            _('override the default summary and description')),
++        ('U', 'target_people', '',
++            _('comma separated list of people needed to review the code')),
++        ('G', 'target_groups', '',
++            _('comma separated list of groups needed to review the code')),
++        ('B', 'bugs_closed', '',
++            _('comma separated list of bug IDs addressed by the change')),
++        ('', 'username', '', _('username for the ReviewBoard site')),
++        ('', 'password', '', _('password for the ReviewBoard site')),
++        ('', 'apiver', '', _('ReviewBoard API version (e.g. 1.0, 2.0)')),
++        ],
++        _('hg lpostreview [OPTION]... FILES'))
++
+     try:
+         mq = extensions.find('mq')
+     except KeyError:
 short-description.patch
 check-state.patch
 qreviews.patch
-
+lpostreviews.patch