 Chromium Code Reviews
 Chromium Code Reviews Issue 6674014:
  Make git-cl work with OWNERS files in a non .git/hooks/pre-cl-* world  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
    
  
    Issue 6674014:
  Make git-cl work with OWNERS files in a non .git/hooks/pre-cl-* world  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools| Index: git_cl/git_cl.py | 
| diff --git a/git_cl/git_cl.py b/git_cl/git_cl.py | 
| index b0071adc0ed7ab651852ec3ed583cfc364d26960..8c0e66b3281368fe63dc62a511d84cd90a5bea0f 100644 | 
| --- a/git_cl/git_cl.py | 
| +++ b/git_cl/git_cl.py | 
| @@ -7,6 +7,7 @@ import logging | 
| import optparse | 
| import os | 
| import re | 
| +import StringIO | 
| import subprocess | 
| import sys | 
| import tempfile | 
| @@ -66,6 +67,7 @@ def RunCommand(cmd, error_ok=False, error_message=None, | 
| stderr = None | 
| proc = Popen(cmd, stdout=stdout, stderr=stderr, **kwargs) | 
| output = proc.communicate()[0] | 
| + | 
| if not error_ok and proc.returncode != 0: | 
| DieWithError('Command "%s" failed.\n' % (' '.join(cmd)) + | 
| (error_message or output or '')) | 
| @@ -480,6 +482,76 @@ def GetCodereviewSettingsInteractively(): | 
| # svn-based hackery. | 
| +class HookResults(object): | 
| + """Contains the parsed output of the presubmit hooks.""" | 
| + def __init__(self, output_from_hooks=None): | 
| + self.reviewers = [] | 
| + self.output = None | 
| + self._ParseOutputFromHooks(output_from_hooks) | 
| + | 
| + def _ParseOutputFromHooks(self, output_from_hooks): | 
| + if not output_from_hooks: | 
| + return | 
| + lines = [] | 
| + reviewers = [] | 
| + reviewer_regexp = re.compile('ADD: R=(.+)') | 
| + for l in output_from_hooks.splitlines(): | 
| + m = reviewer_regexp.match(l) | 
| + if m: | 
| + reviewers.extend(m.group(1).split(',')) | 
| + else: | 
| + lines.append(l) | 
| + self.output = '\n'.join(lines) | 
| + self.reviewers = ','.join(reviewers) | 
| + | 
| + | 
| +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 += '\nR=' + self.reviewers | 
| + if 'BUG=' not in self.description: | 
| + initial_text += '\nBUG=' | 
| + if 'TEST=' not in self.description: | 
| + initial_text += '\nTEST=' | 
| + 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'): | 
| """Finds the given file starting in the cwd and going up. | 
| @@ -671,7 +743,8 @@ def ConvertToInteger(inputval): | 
| return None | 
| -def RunHook(committing, upstream_branch): | 
| +def RunHook(committing, upstream_branch, rietveld_server, tbr=False): | 
| + """Calls sys.exit() if the hook fails; returns a HookResults otherwise.""" | 
| import presubmit_support | 
| import scm | 
| import watchlists | 
| @@ -709,9 +782,19 @@ def RunHook(committing, upstream_branch): | 
| RunCommand(['git', 'config', '--replace-all', | 
| 'rietveld.extracc', ','.join(watchers)]) | 
| - return presubmit_support.DoPresubmitChecks(change, committing, | 
| - verbose=None, output_stream=sys.stdout, input_stream=sys.stdin, | 
| - default_presubmit=None, may_prompt=None) | 
| + output = StringIO.StringIO() | 
| + res = presubmit_support.DoPresubmitChecks(change, committing, | 
| + verbose=None, output_stream=output, input_stream=sys.stdin, | 
| + default_presubmit=None, may_prompt=None, tbr=tbr, | 
| 
M-A Ruel
2011/03/11 23:11:14
You disable may_prompt so that converts all warnin
 | 
| + host_url=cl.GetRietveldServer()) | 
| + hook_results = HookResults(output.getvalue()) | 
| + if hook_results.output: | 
| + print hook_results.output | 
| + | 
| + # TODO(dpranke): We should propagate the error out instead of calling exit(). | 
| + if not res: | 
| + sys.exit(1) | 
| + return hook_results | 
| def CMDpresubmit(parser, args): | 
| @@ -727,18 +810,23 @@ def CMDpresubmit(parser, args): | 
| print 'Cannot presubmit with a dirty tree. You must commit locally first.' | 
| return 1 | 
| + cl = Changelist() | 
| if args: | 
| base_branch = args[0] | 
| else: | 
| # Default to diffing against the "upstream" branch. | 
| - base_branch = Changelist().GetUpstreamBranch() | 
| + base_branch = cl.GetUpstreamBranch() | 
| if options.upload: | 
| print '*** Presubmit checks for UPLOAD would report: ***' | 
| - return RunHook(committing=False, upstream_branch=base_branch) | 
| + RunHook(committing=False, upstream_branch=base_branch, | 
| + rietveld_server=cl.GetRietveldServer(), tbr=False) | 
| + return 0 | 
| else: | 
| print '*** Presubmit checks for DCOMMIT would report: ***' | 
| - return RunHook(committing=True, upstream_branch=base_branch) | 
| + RunHook(committing=True, upstream_branch=base_branch, | 
| + rietveld_server=cl.GetRietveldServer, tbr=False) | 
| + return 0 | 
| @usage('[args to "git diff"]') | 
| @@ -777,7 +865,13 @@ def CMDupload(parser, args): | 
| args = [base_branch + "..."] | 
| if not options.bypass_hooks: | 
| - RunHook(committing=False, upstream_branch=base_branch) | 
| + hook_results = RunHook(committing=False, upstream_branch=base_branch, | 
| + rietveld_server=cl.GetRietveldServer(), tbr=False) | 
| + else: | 
| + hook_results = HookResults() | 
| + | 
| + if not options.reviewers and hook_results.reviewers: | 
| + options.reviewers = hook_results.reviewers | 
| # --no-ext-diff is broken in some versions of Git, so try to work around | 
| # this by overriding the environment (but there is still a problem if the | 
| @@ -790,8 +884,6 @@ def CMDupload(parser, args): | 
| upload_args = ['--assume_yes'] # Don't ask about untracked files. | 
| upload_args.extend(['--server', cl.GetRietveldServer()]) | 
| - if options.reviewers: | 
| - upload_args.extend(['--reviewers', options.reviewers]) | 
| if options.emulate_svn_auto_props: | 
| upload_args.append('--emulate_svn_auto_props') | 
| if options.send_mail: | 
| @@ -812,28 +904,19 @@ def CMDupload(parser, args): | 
| "Adding patch to that issue." % cl.GetIssue()) | 
| else: | 
| log_desc = CreateDescriptionFromLog(args) | 
| - if options.from_logs: | 
| - # Uses logs as description and message as subject. | 
| - subject = options.message | 
| - change_desc = subject + '\n\n' + log_desc | 
| - else: | 
| - 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. | 
| -""" | 
| - if 'BUG=' not in log_desc: | 
| - log_desc += '\nBUG=' | 
| - if 'TEST=' not in log_desc: | 
| - log_desc += '\nTEST=' | 
| - change_desc = UserEditedLog(initial_text + log_desc) | 
| - subject = '' | 
| - if change_desc: | 
| - subject = change_desc.splitlines()[0] | 
| - if not change_desc: | 
| + change_desc = ChangeDescription(options.message, log_desc, | 
| + options.reviewers) | 
| + if not options.from_logs: | 
| + change_desc.Update() | 
| + | 
| + if change_desc.IsEmpty(): | 
| print "Description is empty; aborting." | 
| return 1 | 
| - upload_args.extend(['--message', subject]) | 
| - upload_args.extend(['--description', change_desc]) | 
| + | 
| + upload_args.extend(['--message', change_desc.subject]) | 
| + upload_args.extend(['--description', change_desc.description]) | 
| + if change_desc.reviewers: | 
| + upload_args.extend(['--reviewers', change_desc.reviewers]) | 
| cc = ','.join(filter(None, (settings.GetCCList(), options.cc))) | 
| if cc: | 
| upload_args.extend(['--cc', cc]) | 
| @@ -865,7 +948,7 @@ def CMDupload(parser, args): | 
| print '\nGot exception while uploading -- saving description to %s\n' \ | 
| % backup_path | 
| backup_file = open(backup_path, 'w') | 
| - backup_file.write(change_desc) | 
| + backup_file.write(change_desc.description) | 
| backup_file.close() | 
| raise | 
| @@ -933,8 +1016,9 @@ def SendUpstream(parser, args, cmd): | 
| 'before attempting to %s.' % (base_branch, cmd)) | 
| return 1 | 
| - if not options.force and not options.bypass_hooks: | 
| - RunHook(committing=False, upstream_branch=base_branch) | 
| + if not options.bypass_hooks: | 
| + hook_results = RunHook(committing=True, upstream_branch=base_branch, | 
| + rietveld_server=cl.GetRietveldServer(), tbr=options.tbr) | 
| if cmd == 'dcommit': | 
| # Check the tree status if the tree status URL is set. | 
| @@ -974,6 +1058,7 @@ def SendUpstream(parser, args, cmd): | 
| if cl.GetIssue(): | 
| description = cl.GetDescription() | 
| + # TODO(dpranke): Update to use ChangeDescription object. | 
| if not description: | 
| description = """# Enter a description of the change. | 
| # This will be used as the change log for the commit. |