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