@ -9,7 +9,6 @@ import os
import re
import re
import subprocess
import subprocess
import sys
import sys
import tempfile
import textwrap
import textwrap
import urlparse
import urlparse
import urllib2
import urllib2
@ -21,17 +20,17 @@ except ImportError:
# TODO(dpranke): don't use relative import.
# TODO(dpranke): don't use relative import.
import upload # pylint: disable=W0403
import upload # pylint: disable=W0403
try :
# TODO(dpranke): We wrap this in a try block for a limited form of
# TODO(dpranke): move this file up a directory so we don't need this.
# backwards-compatibility with older versions of git-cl that weren't
depot_tools_path = os . path . dirname ( os . path . dirname ( os . path . abspath ( __file__ ) ) )
# dependent on depot_tools. This version should still work outside of
sys . path . append ( depot_tools_path )
# depot_tools as long as --bypass-hooks is used. We should remove this
# once this has baked for a while and things seem safe.
import breakpad # pylint: disable=W0611
depot_tools_path = os . path . dirname ( os . path . dirname ( os . path . abspath ( __file__ ) ) )
sys . path . append ( depot_tools_path )
import presubmit_support
import breakpad # pylint: disable=W0611
import scm
except ImportError :
import watchlists
pass
DEFAULT_SERVER = ' http://codereview.appspot.com '
DEFAULT_SERVER = ' http://codereview.appspot.com '
POSTUPSTREAM_HOOK_PATTERN = ' .git/hooks/post-cl- %s '
POSTUPSTREAM_HOOK_PATTERN = ' .git/hooks/post-cl- %s '
@ -333,6 +332,7 @@ class Changelist(object):
self . description = None
self . description = None
self . has_patchset = False
self . has_patchset = False
self . patchset = None
self . patchset = None
self . tbr = False
def GetBranch ( self ) :
def GetBranch ( self ) :
""" Returns the short branch name, e.g. ' master ' . """
""" Returns the short branch name, e.g. ' master ' . """
@ -535,53 +535,6 @@ def GetCodereviewSettingsInteractively():
# svn-based hackery.
# svn-based hackery.
class ChangeDescription ( object ) :
""" Contains a parsed form of the change description. """
def __init__ ( self , subject , log_desc , reviewers ) :
self . subject = subject
self . log_desc = log_desc
self . reviewers = reviewers
self . description = self . log_desc
def Update ( self ) :
initial_text = """ # Enter a description of the change.
# This will displayed on the codereview site.
# The first line will also be used as the subject of the review.
"""
initial_text + = self . description
if ' R= ' not in self . description and self . reviewers :
initial_text + = ' \n R= ' + self . reviewers
if ' BUG= ' not in self . description :
initial_text + = ' \n BUG= '
if ' TEST= ' not in self . description :
initial_text + = ' \n TEST= '
self . _ParseDescription ( UserEditedLog ( initial_text ) )
def _ParseDescription ( self , description ) :
if not description :
self . description = description
return
parsed_lines = [ ]
reviewers_regexp = re . compile ( ' \ s*R=(.+) ' )
reviewers = ' '
subject = ' '
for l in description . splitlines ( ) :
if not subject :
subject = l
matched_reviewers = reviewers_regexp . match ( l )
if matched_reviewers :
reviewers = matched_reviewers . group ( 1 )
parsed_lines . append ( l )
self . description = ' \n ' . join ( parsed_lines ) + ' \n '
self . subject = subject
self . reviewers = reviewers
def IsEmpty ( self ) :
return not self . description
def FindCodereviewSettingsFile ( filename = ' codereview.settings ' ) :
def FindCodereviewSettingsFile ( filename = ' codereview.settings ' ) :
""" Finds the given file starting in the cwd and going up.
""" Finds the given file starting in the cwd and going up.
@ -731,36 +684,6 @@ def CreateDescriptionFromLog(args):
return RunGit ( [ ' log ' , ' --pretty=format: %s \n \n % b ' ] + log_args )
return RunGit ( [ ' log ' , ' --pretty=format: %s \n \n % b ' ] + log_args )
def UserEditedLog ( starting_text ) :
""" Given some starting text, let the user edit it and return the result. """
editor = os . getenv ( ' EDITOR ' , ' vi ' )
( file_handle , filename ) = tempfile . mkstemp ( )
fileobj = os . fdopen ( file_handle , ' w ' )
fileobj . write ( starting_text )
fileobj . close ( )
# Open up the default editor in the system to get the CL description.
try :
cmd = ' %s %s ' % ( editor , filename )
if sys . platform == ' win32 ' and os . environ . get ( ' TERM ' ) == ' msys ' :
# Msysgit requires the usage of 'env' to be present.
cmd = ' env ' + cmd
# shell=True to allow the shell to handle all forms of quotes in $EDITOR.
subprocess . check_call ( cmd , shell = True )
fileobj = open ( filename )
text = fileobj . read ( )
fileobj . close ( )
finally :
os . remove ( filename )
if not text :
return
stripcomment_re = re . compile ( r ' ^#.*$ ' , re . MULTILINE )
return stripcomment_re . sub ( ' ' , text ) . strip ( )
def ConvertToInteger ( inputval ) :
def ConvertToInteger ( inputval ) :
""" Convert a string to integer, but returns either an int or None. """
""" Convert a string to integer, but returns either an int or None. """
try :
try :
@ -769,12 +692,20 @@ def ConvertToInteger(inputval):
return None
return None
class GitChangeDescription ( presubmit_support . ChangeDescription ) :
def UserEdit ( self ) :
header = (
" # Enter a description of the change. \n "
" # This will displayed on the codereview site. \n "
" # The first line will also be used as the subject of the review. \n "
" \n " )
edited_text = self . editor ( header + self . EditableDescription ( ) )
stripcomment_re = re . compile ( r ' ^#.*$ ' , re . MULTILINE )
self . Parse ( stripcomment_re . sub ( ' ' , edited_text ) . strip ( ) )
def RunHook ( committing , upstream_branch , rietveld_server , tbr , may_prompt ) :
def RunHook ( committing , upstream_branch , rietveld_server , tbr , may_prompt ) :
""" Calls sys.exit() if the hook fails; returns a HookResults otherwise. """
""" Calls sys.exit() if the hook fails; returns a HookResults otherwise. """
import presubmit_support
import scm
import watchlists
root = RunCommand ( [ ' git ' , ' rev-parse ' , ' --show-cdup ' ] ) . strip ( )
root = RunCommand ( [ ' git ' , ' rev-parse ' , ' --show-cdup ' ] ) . strip ( )
if not root :
if not root :
root = ' . '
root = ' . '
@ -843,13 +774,13 @@ def CMDpresubmit(parser, args):
if options . upload :
if options . upload :
print ' *** Presubmit checks for UPLOAD would report: *** '
print ' *** Presubmit checks for UPLOAD would report: *** '
RunHook ( committing = False , upstream_branch = base_branch ,
RunHook ( committing = False , upstream_branch = base_branch ,
rietveld_server = cl . GetRietveldServer ( ) , tbr = False ,
rietveld_server = cl . GetRietveldServer ( ) , tbr = cl . tbr ,
may_prompt = False )
may_prompt = False )
return 0
return 0
else :
else :
print ' *** Presubmit checks for DCOMMIT would report: *** '
print ' *** Presubmit checks for DCOMMIT would report: *** '
RunHook ( committing = True , upstream_branch = base_branch ,
RunHook ( committing = True , upstream_branch = base_branch ,
rietveld_server = cl . GetRietveldServer , tbr = False ,
rietveld_server = cl . GetRietveldServer , tbr = cl . tbr ,
may_prompt = False )
may_prompt = False )
return 0
return 0
@ -893,10 +824,10 @@ def CMDupload(parser, args):
if not options . bypass_hooks and not options . force :
if not options . bypass_hooks and not options . force :
hook_results = RunHook ( committing = False , upstream_branch = base_branch ,
hook_results = RunHook ( committing = False , upstream_branch = base_branch ,
rietveld_server = cl . GetRietveldServer ( ) , tbr = False ,
rietveld_server = cl . GetRietveldServer ( ) , tbr = cl . tbr ,
may_prompt = True )
may_prompt = True )
if not options . reviewers and hook_results . reviewers :
if not options . reviewers and hook_results . reviewers :
options . reviewers = hook_results . reviewers
options . reviewers = ' , ' . join ( hook_results . reviewers )
# --no-ext-diff is broken in some versions of Git, so try to work around
# --no-ext-diff is broken in some versions of Git, so try to work around
@ -930,10 +861,10 @@ def CMDupload(parser, args):
" Adding patch to that issue. " % cl . GetIssue ( ) )
" Adding patch to that issue. " % cl . GetIssue ( ) )
else :
else :
log_desc = CreateDescriptionFromLog ( args )
log_desc = CreateDescriptionFromLog ( args )
change_desc = ChangeDescription( options . message , log_desc ,
change_desc = Git ChangeDescription( subject = options . message ,
options . reviewers )
description = log_desc , reviewers = options . reviewers , tbr = cl . tbr )
if not options . from_logs :
if not options . from_logs and ( not options . force ) :
change_desc . U pdate ( )
change_desc . U serEdit ( )
if change_desc . IsEmpty ( ) :
if change_desc . IsEmpty ( ) :
print " Description is empty; aborting. "
print " Description is empty; aborting. "
@ -1044,7 +975,7 @@ def SendUpstream(parser, args, cmd):
if not options . bypass_hooks and not options . force :
if not options . bypass_hooks and not options . force :
RunHook ( committing = True , upstream_branch = base_branch ,
RunHook ( committing = True , upstream_branch = base_branch ,
rietveld_server = cl . GetRietveldServer ( ) , tbr = options . tbr ,
rietveld_server = cl . GetRietveldServer ( ) , tbr = ( cl . tbr or options . tbr ) ,
may_prompt = True )
may_prompt = True )
if cmd == ' dcommit ' :
if cmd == ' dcommit ' :
@ -1083,17 +1014,15 @@ def SendUpstream(parser, args, cmd):
# create a template description. Eitherway, give the user a chance to edit
# create a template description. Eitherway, give the user a chance to edit
# it to fill in the TBR= field.
# it to fill in the TBR= field.
if cl . GetIssue ( ) :
if cl . GetIssue ( ) :
description = cl . GetDescription ( )
change_desc = GitChangeDescription ( description = cl . GetDescription ( ) )
# TODO(dpranke): Update to use ChangeDescription object.
if not description :
if not description :
description = """ # Enter a description of the change.
log_desc = CreateDescriptionFromLog ( args )
# This will be used as the change log for the commit.
change_desc = GitChangeDescription ( description = log_desc , tbr = True )
"""
description + = CreateDescriptionFromLog ( args )
description = UserEditedLog ( description + ' \n TBR= ' )
if not options . force :
change_desc . UserEdit ( )
description = change_desc . description
if not description :
if not description :
print " Description empty; aborting. "
print " Description empty; aborting. "