Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/python2
      2 
      3 # Copyright 2014 Google Inc.
      4 #
      5 # Use of this source code is governed by a BSD-style license that can be
      6 # found in the LICENSE file.
      7 
      8 """Add message to codereview issue.
      9 
     10 This script takes a codereview URL or a codereview issue number as its
     11 argument and a (possibly multi-line) message on stdin.  It then calls
     12 `git cl upload` to append the message to the given codereview issue.
     13 
     14 Usage:
     15   echo MESSAGE | %prog -c CHECKOUT_PATH CODEREVIEW_ISSUE
     16 or:
     17   cd /path/to/git/checkout
     18   %prog CODEREVIEW_ISSUE <<EOF
     19   MESSAGE
     20   EOF
     21 or:
     22   %prog --help
     23 """
     24 
     25 import optparse
     26 import os
     27 import sys
     28 
     29 import git_utils
     30 import misc_utils
     31 
     32 
     33 DEFAULT_REVIEWERS = ','.join([
     34     'rmistry (at] google.com',
     35     'reed (at] google.com',
     36     'bsalomon (at] google.com',
     37     'robertphillips (at] google.com',
     38     ])
     39 
     40 
     41 DEFAULT_CC_LIST = ','.join([
     42     'skia-team (at] google.com',
     43     ])
     44 
     45 
     46 def add_codereview_message(codereview_url, message, checkout_path,
     47                            skip_cl_upload, verbose, reviewers, cclist):
     48     """Add a message to a given codereview.
     49 
     50     Args:
     51         codereview_url: (string) we will extract the issue number from
     52             this url, or this could simply be the issue number.
     53         message: (string) will be passed to `git cl upload -m $MESSAGE`
     54         checkout_path: (string) location of the git
     55             repository checkout to be used.
     56         skip_cl_upload: (boolean) if true, don't actually
     57             add the message and keep the temporary branch around.
     58         verbose: (boolean) print out details useful for debugging.
     59         reviewers: (string) comma-separated list of reviewers
     60         cclist: (string) comma-separated list of addresses to be
     61             carbon-copied
     62     """
     63     # pylint: disable=I0011,R0913
     64     git = git_utils.git_executable()
     65     issue = codereview_url.strip('/').split('/')[-1]
     66     vsp = misc_utils.VerboseSubprocess(verbose)
     67     if skip_cl_upload:
     68         branch_name = 'issue_%s' % issue
     69     else:
     70         branch_name = None
     71     upstream = 'origin/master'
     72 
     73     with misc_utils.ChangeDir(checkout_path, verbose):
     74         vsp.check_call([git, 'fetch', '-q', 'origin'])
     75 
     76         with git_utils.ChangeGitBranch(branch_name, upstream, verbose):
     77             vsp.check_call([git, 'cl', 'patch', issue])
     78 
     79             git_upload = [
     80                 git, 'cl', 'upload', '-t', 'bot report', '-m', message]
     81             if cclist:
     82                 git_upload.append('--cc=' + cclist)
     83             if reviewers:
     84                 git_upload.append('--reviewers=' + reviewers)
     85 
     86             if skip_cl_upload:
     87                 branch_name = git_utils.git_branch_name(verbose)
     88                 space = '    '
     89                 print 'You should call:'
     90                 misc_utils.print_subprocess_args(space, ['cd', os.getcwd()])
     91                 misc_utils.print_subprocess_args(
     92                     space, [git, 'checkout', branch_name])
     93                 misc_utils.print_subprocess_args(space, git_upload)
     94             else:
     95                 vsp.check_call(git_upload)
     96                 print vsp.check_output([git, 'cl', 'issue'])
     97 
     98 
     99 def main(argv):
    100     """main function; see module-level docstring and GetOptionParser help.
    101 
    102     Args:
    103         argv: sys.argv[1:]-type argument list.
    104     """
    105     option_parser = optparse.OptionParser(usage=__doc__)
    106     option_parser.add_option(
    107         '-c', '--checkout_path',
    108         default=os.curdir,
    109         help='Path to the Git repository checkout,'
    110         ' defaults to current working directory.')
    111     option_parser.add_option(
    112         '', '--skip_cl_upload', action='store_true', default=False,
    113         help='Skip the cl upload step; useful for testing.')
    114     option_parser.add_option(
    115         '', '--verbose', action='store_true', dest='verbose', default=False,
    116         help='Do not suppress the output from `git cl`.',)
    117     option_parser.add_option(
    118         '', '--git_path', default='git',
    119         help='Git executable, defaults to "git".',)
    120     option_parser.add_option(
    121         '', '--reviewers', default=DEFAULT_REVIEWERS,
    122         help=('Comma-separated list of reviewers.  Default is "%s".'
    123               % DEFAULT_REVIEWERS))
    124     option_parser.add_option(
    125         '', '--cc', default=DEFAULT_CC_LIST,
    126         help=('Comma-separated list of addresses to be carbon-copied.'
    127               '  Default is "%s".' %  DEFAULT_CC_LIST))
    128 
    129     options, arguments = option_parser.parse_args(argv)
    130 
    131     if not options.checkout_path:
    132         option_parser.error('Must specify checkout_path.')
    133     if not git_utils.git_executable():
    134         option_parser.error('Invalid git executable.')
    135     if len(arguments) > 1:
    136         option_parser.error('Extra arguments.')
    137     if len(arguments) != 1:
    138         option_parser.error('Missing Codereview URL.')
    139 
    140     message = sys.stdin.read()
    141     add_codereview_message(arguments[0], message, options.checkout_path,
    142                            options.skip_cl_upload, options.verbose,
    143                            options.reviewers, options.cc)
    144 
    145 
    146 if __name__ == '__main__':
    147     main(sys.argv[1:])
    148 
    149