Hi Christian,

I started out with a post-commit hook using a file:// URL, but I couldn't 
get that to work.  It's been a while since I worked on it, but I was 
working with it that way today, and if I recall correctly, I never managed 
to get past the "Unable to find a Review Board server for this source code 
tree" error. Since this is running as a hook, I can't use a reviewboardrc 
file.  I might have to look at that some more.  If there really is a better 
way of getting that to work, it would explain why no one has needed to 
modify the rbtools subversion interface.  I've attached a sanitized version 
of my hook.  My modifications to svn.py were really simplistic (in other 
words, sloppy).  I just went through and, for each svn command like this:

diff_cmd = ['svn', 'diff', '--diff-cmd=diff', '--notice-ancestry']

I added the hard-coded username and password:

diff_cmd = ['svn', 'diff', '--non-interactive','--username=MYUSERNAME', 
'--password=MYPASSWORD', '--diff-cmd=diff', '--notice-ancestry']

I can send you the whole thing if you  think it would make a difference, 
but I just did that same thing for svn info, etc.



On Wednesday, July 2, 2014 3:03:35 PM UTC-4, Christian Hammond wrote:
> Hi MIchelle,
> I can’t really say, to be honest. I want to get a better sense of your 
> setup, though.
> This hook is a script living on the SVN server, right? Given that it’s 
> local to there, is there a reason it can’t use a file:// URL to reach its 
> SVN repo?
> Can I see the hook and the modifications?
> Christian
> -- 
> Christian Hammond - chri...@beanbaginc.com <javascript:>
> Review Board - http://www.reviewboard.org
> Beanbag, Inc. - http://www.beanbaginc.com
> On July 2, 2014 at 11:50:58 AM, Michelle Avery (michell...@gmail.com 
> <javascript:>) wrote:
> Hi, 
> I set up an instance of reviewboard a few weeks ago as a quick proof of 
> concept for my company.  At the time, I ran into a problem getting my 
> subversion post-commit hook to work.  Our repository allows no anonymous 
> access, so the svn info, log, etc. calls issued by rbtools were hanging 
> waiting for a password that rbtools didn't seem to give me a way to supply. 
>  From this 
> <https://groups.google.com/d/topic/reviewboard/xDoWsUyHpBg/discussion> 
> mailing 
> list post, it seemed that this was actually a limitation.  Since I was just 
> trying out reviewboard at the time, I just modified rbtools/clients/svn.py 
> to supply the credentials with those calls.  However, now that I'm setting 
> up what will be a production instance, I'm more concerned about doing 
> things properly, and it seems odd to me that, in the two years since that 
> post, no one has modified rbtools to allow those parameters.  Can someone 
> please confirm whether this is an uncommon requirement, or I'm just totally 
> wrong and there actually is a better way of doing this?
> Thanks,
> Michelle 
>  --
> Get the Review Board Power Pack at http://www.reviewboard.org/powerpack/
> ---
> Sign up for Review Board hosting at RBCommons: https://rbcommons.com/
> ---
> Happy user? Let us know at http://www.reviewboard.org/users/
> ---
> You received this message because you are subscribed to the Google Groups 
> "reviewboard" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to reviewboard...@googlegroups.com <javascript:>.
> For more options, visit https://groups.google.com/d/optout.

Get the Review Board Power Pack at http://www.reviewboard.org/powerpack/
Sign up for Review Board hosting at RBCommons: https://rbcommons.com/
Happy user? Let us know at http://www.reviewboard.org/users/
You received this message because you are subscribed to the Google Groups 
"reviewboard" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to reviewboard+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
#!/usr/bin/env python
# svn-hook-postcommit-review
# This script should be invoked from the subversion post-commit hook like this:
# REPOS="$1"
# REV="$2"
# /usr/bin/python /some/path/svn-hook-postcommit-review "$REPOS" "$REV" || exit 
# Searches the commit message for text in the form of:
#   publish review - publishes a review request
#   draft review - creates a draft review request
# The space before 'review' may be ommitted.
# The log message is interpreted for review request parameters:
#    summary = up to first period+space, first new-line, or 250 chars
#    description = entire log message
#    existing review updated if log message includes 'update review:[0-9]+'
#    bugs added to review if log message includes commands as defined in
#      supported_ticket_cmds
# By default, the review request is created out of a diff between the current
# revision (M) and the previous revision (M-1).
# To create a diff that spans multiple revisions, include
# 'after revision:[0-9]+' in the log message.
# To limit the diff to changes in a certain path (e.g. a branch), include
# 'base path:"<path>"' in the log message.  The path must be relative to
# the root of the repository and be surrounded by single or double quotes.
# An example commit message is:
#    Changed blah and foo to do this or that.  Publish review ticket:1
#      update review:2 after revision:3 base path:'internal/trunk/style'.
# This would update the existing review 2 with a diff of changes to files under
# the style directory between this commit and revision 3.  It would place
# the entire log message in the review summary and description, and put
# bug id 1 in the bugs field.
# This script may only be run from outside a working copy.

# User configurable variables

# Path to rbt script
POSTREVIEW_PATH = "/usr/local/bin/"
# Username and password for Review Board user that will be connecting
# to create all review requests.  This user must have 'submit as'
# privileges, since it will submit requests in the name of svn committers.
USERNAME = '<my username here>'
PASSWORD = '<my password here>'

# If true, runs rbt in debug mode and outputs its diff
DEBUG = False

# end user configurable variables

import sys
import os
import subprocess
import re
import svn.fs
import svn.core
import svn.repos

# list of trac commands from trac-post-commit-hook.py.
# numbers following these commands will be added to the bugs
# field of the review request.
supported_ticket_cmds = {'review':         '_cmdReview',
                         'publishreview':  '_cmdReview',
                         'publish review': '_cmdReview',
                         'draftreview':    '_cmdReview',
                         'draft review':   '_cmdReview'}

ticket_prefix = '(?:#|(?:ticket|issue|bug)[: ]?)'
ticket_reference = ticket_prefix + '[0-9]+'
ticket_command = (r'(?P<action>[A-Za-z]*).?'
                  '(?P<ticket>%s(?:(?:[, &]*|[ ]?and[ ]?)%s)*)' %
                  (ticket_reference, ticket_reference))

def execute(command, env=None, ignore_errors=False):
    Utility function to execute a command and return the output.
    Derived from Review Board's rbt script.
    if env:
        env = os.environ

    p = subprocess.Popen(command,
                         stdin = subprocess.PIPE,
                         stdout = subprocess.PIPE,
                         stderr = subprocess.STDOUT,
                         shell = False,
                         close_fds = sys.platform.startswith('win'),
                         universal_newlines = True,
                         env = env)
    data = p.stdout.read()
    rc = p.wait()
    if rc and not ignore_errors:
        sys.stderr.write('Failed to execute command: %s\n%s\n' % (command, 

    return data

def main():
    if len(sys.argv) != 3:
        sys.stderr.write('Usage: %s <repos> <rev>\n' % sys.argv[0])

    repos = sys.argv[1]
    rev = sys.argv[2]

    # verify that rev parameter is an int
    except ValueError:
        sys.stderr.write("Parameter <rev> must be an int, was given %s\n" % rev)

    # get the svn file system object
    fs_ptr = svn.repos.svn_repos_fs(svn.repos.svn_repos_open(

    # get the log message
    log = svn.fs.svn_fs_revision_prop(fs_ptr, int(rev),

    # error if log message is blank
    if len(log.strip()) < 1:
        sys.stderr.write("Log message is empty, no review request created\n")

    # get the author
    author = svn.fs.svn_fs_revision_prop(fs_ptr, int(rev),

    # error if author is blank
    if len(author.strip()) < 1:
        sys.stderr.write("Author is blank, no review request created\n")

    # check whether to create a review, based on presence of word
    # 'review' with prefix
    review = r'(?:publish|draft)(?: )?review'
    if not re.search(review, log, re.M | re.I):
        print 'No review requested'

    # check for update to existing review
    m = re.search(r'update(?: )?review:([0-9]+)', log, re.M | re.I)
    if m:
        reviewid = '--review-request-id=' + m.group(1)
        reviewid = ''

    # check whether to publish or leave review as draft
    if re.search(r'draft(?: )?review', log, re.M | re.I):
        publish = ''
        publish = '-p'

    # get previous revision number -- either 1 prior, or
    # user-specified number
    m = re.search(r'after(?: )?revision:([0-9]+)', log, re.M | re.I)
    if m:
        prevrev = m.group(1)
        prevrev = int(rev) - 1

    # check for an explicitly-provided base path (must be contained
    # within quotes)
    m = re.search(r'base ?path:[\'"]([^\'"]+)[\'"]', log, re.M | re.I)
    if m:
        base_path = m.group(1)
        base_path = ''

    # get bug numbers referenced in this log message
    ticket_command_re = re.compile(ticket_command)
    ticket_re = re.compile(ticket_prefix + '([0-9]+)')

    ticket_ids = []
    ticket_cmd_groups = ticket_command_re.findall(log)
    for cmd, tkts in ticket_cmd_groups:
        funcname = supported_ticket_cmds.get(cmd.lower(), '')
        if funcname:
            for tkt_id in ticket_re.findall(tkts):

    if ticket_ids:
        bugs = '--bugs-closed=' + ','.join(ticket_ids)
        bugs = ''

    # summary is log up to first period+space / first new line / first 250 chars
    # (whichever comes first)
    summary = '--summary=' + log[:250].splitlines().pop(0).split('. ').pop(0)

    # other parameters for postreview
    repository_url  = '--repository-url=http://my.server.com/repo'
    password        = '--password=' + PASSWORD
    username        = '--username=' + USERNAME
    description     = "--description=(In [%s]) %s" % (rev, log)
    submitas        = '--submit-as=' + author
    revision        = '%s:%s' % (prevrev, rev)

    # common arguments
    args = [repository_url, username, password, publish,
            submitas, revision, base_path, reviewid]

    # filter out any potentially blank args, which will confuse rbt
    args = [i for i in args if len(i) > 1]

    # if not updating an existing review, add extra arguments
    if len(reviewid) == 0:
        args += [summary, description, bugs]

    if DEBUG:
        args += ['-d', '--output-diff']
        print [os.path.join(POSTREVIEW_PATH, 'rbt'), 'post'] + args

    # Run Review Board rbt script
    data = execute([os.path.join(POSTREVIEW_PATH, 'rbt'), 'post'] + args,
                   env = {'LANG': 'en_US.UTF-8'})

    if DEBUG:
        print data

if __name__ == '__main__':

Reply via email to