Make git-cl work with OWNERS file hooks properly.

This version calls into presubmit_support directly to support the OWNERS hooks. We do not need both this patch and http://codereview.chromium.org/6646009/

This patch depends on http://codereview.chromium.org/6665018/ .

Review URL: http://codereview.chromium.org/6674014

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@77898 0039d316-1c4b-4281-b951-d872f2087c98
experimental/szager/collated-output
dpranke@chromium.org
parent 627ea67f26
commit 970c522f0f

@ -7,6 +7,7 @@ import logging
import optparse import optparse
import os import os
import re import re
import StringIO
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
@ -37,7 +38,7 @@ POSTUPSTREAM_HOOK_PATTERN = '.git/hooks/post-cl-%s'
DESCRIPTION_BACKUP_FILE = '~/.git_cl_description_backup' DESCRIPTION_BACKUP_FILE = '~/.git_cl_description_backup'
def DieWithError(message): def DieWithError(message):
print >>sys.stderr, message print >> sys.stderr, message
sys.exit(1) sys.exit(1)
@ -481,6 +482,76 @@ def GetCodereviewSettingsInteractively():
# svn-based hackery. # 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'): 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.
@ -503,15 +574,6 @@ def FindCodereviewSettingsFile(filename='codereview.settings'):
def LoadCodereviewSettingsFromFile(fileobj): def LoadCodereviewSettingsFromFile(fileobj):
"""Parse a codereview.settings file and updates hooks.""" """Parse a codereview.settings file and updates hooks."""
def DownloadToFile(url, filename):
filename = os.path.join(settings.GetRoot(), filename)
contents = urllib2.urlopen(url).read()
fileobj = open(filename, 'w')
fileobj.write(contents)
fileobj.close()
os.chmod(filename, 0755)
return 0
keyvals = {} keyvals = {}
for line in fileobj.read().splitlines(): for line in fileobj.read().splitlines():
if not line or line.startswith("#"): if not line or line.startswith("#"):
@ -519,9 +581,6 @@ def LoadCodereviewSettingsFromFile(fileobj):
k, v = line.split(": ", 1) k, v = line.split(": ", 1)
keyvals[k] = v keyvals[k] = v
def GetProperty(name):
return keyvals.get(name)
def SetProperty(name, setting, unset_error_ok=False): def SetProperty(name, setting, unset_error_ok=False):
fullname = 'rietveld.' + name fullname = 'rietveld.' + name
if setting in keyvals: if setting in keyvals:
@ -672,7 +731,8 @@ def ConvertToInteger(inputval):
return None return None
def RunHook(committing, upstream_branch): def RunHook(committing, upstream_branch, rietveld_server, tbr, may_prompt):
"""Calls sys.exit() if the hook fails; returns a HookResults otherwise."""
import presubmit_support import presubmit_support
import scm import scm
import watchlists import watchlists
@ -710,9 +770,19 @@ def RunHook(committing, upstream_branch):
RunCommand(['git', 'config', '--replace-all', RunCommand(['git', 'config', '--replace-all',
'rietveld.extracc', ','.join(watchers)]) 'rietveld.extracc', ','.join(watchers)])
return presubmit_support.DoPresubmitChecks(change, committing, output = StringIO.StringIO()
verbose=None, output_stream=sys.stdout, input_stream=sys.stdin, res = presubmit_support.DoPresubmitChecks(change, committing,
default_presubmit=None, may_prompt=None) verbose=None, output_stream=output, input_stream=sys.stdin,
default_presubmit=None, may_prompt=may_prompt, tbr=tbr,
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): def CMDpresubmit(parser, args):
@ -728,18 +798,25 @@ def CMDpresubmit(parser, args):
print 'Cannot presubmit with a dirty tree. You must commit locally first.' print 'Cannot presubmit with a dirty tree. You must commit locally first.'
return 1 return 1
cl = Changelist()
if args: if args:
base_branch = args[0] base_branch = args[0]
else: else:
# Default to diffing against the "upstream" branch. # Default to diffing against the "upstream" branch.
base_branch = Changelist().GetUpstreamBranch() base_branch = cl.GetUpstreamBranch()
if options.upload: if options.upload:
print '*** Presubmit checks for UPLOAD would report: ***' 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,
may_prompt=False)
return 0
else: else:
print '*** Presubmit checks for DCOMMIT would report: ***' 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,
may_prompt=False)
return 0
@usage('[args to "git diff"]') @usage('[args to "git diff"]')
@ -747,6 +824,8 @@ def CMDupload(parser, args):
"""upload the current changelist to codereview""" """upload the current changelist to codereview"""
parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks', parser.add_option('--bypass-hooks', action='store_true', dest='bypass_hooks',
help='bypass upload presubmit hook') help='bypass upload presubmit hook')
parser.add_option('-f', action='store_true', dest='force',
help="force yes to questions (don't prompt)")
parser.add_option('-m', dest='message', help='message for patch') parser.add_option('-m', dest='message', help='message for patch')
parser.add_option('-r', '--reviewers', parser.add_option('-r', '--reviewers',
help='reviewer email addresses') help='reviewer email addresses')
@ -778,7 +857,14 @@ def CMDupload(parser, args):
args = [base_branch + "..."] args = [base_branch + "..."]
if not options.bypass_hooks: 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,
may_prompt=(not options.force))
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 # --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 # this by overriding the environment (but there is still a problem if the
@ -791,8 +877,6 @@ def CMDupload(parser, args):
upload_args = ['--assume_yes'] # Don't ask about untracked files. upload_args = ['--assume_yes'] # Don't ask about untracked files.
upload_args.extend(['--server', cl.GetRietveldServer()]) upload_args.extend(['--server', cl.GetRietveldServer()])
if options.reviewers:
upload_args.extend(['--reviewers', options.reviewers])
if options.emulate_svn_auto_props: if options.emulate_svn_auto_props:
upload_args.append('--emulate_svn_auto_props') upload_args.append('--emulate_svn_auto_props')
if options.send_mail: if options.send_mail:
@ -813,28 +897,19 @@ 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)
if options.from_logs: change_desc = ChangeDescription(options.message, log_desc,
# Uses logs as description and message as subject. options.reviewers)
subject = options.message if not options.from_logs:
change_desc = subject + '\n\n' + log_desc change_desc.Update()
else:
initial_text = """# Enter a description of the change. if change_desc.IsEmpty():
# 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:
print "Description is empty; aborting." print "Description is empty; aborting."
return 1 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))) cc = ','.join(filter(None, (settings.GetCCList(), options.cc)))
if cc: if cc:
upload_args.extend(['--cc', cc]) upload_args.extend(['--cc', cc])
@ -866,7 +941,7 @@ def CMDupload(parser, args):
print '\nGot exception while uploading -- saving description to %s\n' \ print '\nGot exception while uploading -- saving description to %s\n' \
% backup_path % backup_path
backup_file = open(backup_path, 'w') backup_file = open(backup_path, 'w')
backup_file.write(change_desc) backup_file.write(change_desc.description)
backup_file.close() backup_file.close()
raise raise
@ -934,9 +1009,12 @@ def SendUpstream(parser, args, cmd):
'before attempting to %s.' % (base_branch, cmd)) 'before attempting to %s.' % (base_branch, cmd))
return 1 return 1
if not options.force and not options.bypass_hooks: if not options.bypass_hooks:
RunHook(committing=False, upstream_branch=base_branch) RunHook(committing=True, upstream_branch=base_branch,
rietveld_server=cl.GetRietveldServer(), tbr=options.tbr,
may_prompt=(not options.force))
if not options.force and not options.bypass_hooks:
if cmd == 'dcommit': if cmd == 'dcommit':
# Check the tree status if the tree status URL is set. # Check the tree status if the tree status URL is set.
status = GetTreeStatus() status = GetTreeStatus()
@ -975,6 +1053,7 @@ def SendUpstream(parser, args, cmd):
if cl.GetIssue(): if cl.GetIssue():
description = cl.GetDescription() description = cl.GetDescription()
# TODO(dpranke): Update to use ChangeDescription object.
if not description: if not description:
description = """# Enter a description of the change. description = """# Enter a description of the change.
# This will be used as the change log for the commit. # This will be used as the change log for the commit.
@ -1066,7 +1145,7 @@ def SendUpstream(parser, args, cmd):
if retcode == 0: if retcode == 0:
hook = POSTUPSTREAM_HOOK_PATTERN % cmd hook = POSTUPSTREAM_HOOK_PATTERN % cmd
if os.path.isfile(hook): if os.path.isfile(hook):
RunHook(hook, upstream_branch=base_branch, error_ok=True) RunCommand([hook, base_branch], error_ok=True)
return 0 return 0
@ -1202,9 +1281,9 @@ def GetTreeStatus():
elif status.find('open') != -1 or status == '1': elif status.find('open') != -1 or status == '1':
return 'open' return 'open'
return 'unknown' return 'unknown'
return 'unset' return 'unset'
def GetTreeStatusReason(): def GetTreeStatusReason():
"""Fetches the tree status from a json url and returns the message """Fetches the tree status from a json url and returns the message
with the reason for the tree to be opened or closed.""" with the reason for the tree to be opened or closed."""
@ -1230,6 +1309,7 @@ def GetTreeStatusReason():
connection.close() connection.close()
return status['message'] return status['message']
def CMDtree(parser, args): def CMDtree(parser, args):
"""show the status of the tree""" """show the status of the tree"""
(options, args) = parser.parse_args(args) (options, args) = parser.parse_args(args)

@ -0,0 +1,46 @@
#!/bin/bash
set -e
. ./test-lib.sh
setup_initsvn
setup_gitsvn
(
set -e
cd git-svn
git config rietveld.server localhost:8080
export EDITOR=$(which true)
git checkout -q -b work
echo "ben@chromium.org" > OWNERS
cat <<END > PRESUBMIT.py
def CheckChangeOnCommit(input_api, output_api):
return input_api.canned_checks.CheckOwners(input_api, output_api)
CheckChangeOnUpload = CheckChangeOnCommit
END
git add OWNERS PRESUBMIT.py ; git commit -q -m "add OWNERS"
test_expect_success "upload succeeds (needs a server running on localhost)" \
"$GIT_CL upload -m test master | grep -q 'Issue created'"
test_expect_success "git-cl status has a suggested reviewer" \
"$GIT_CL status | grep -q 'R=ben@chromium.org'"
test_expect_failure "git-cl dcommit fails w/ missing LGTM" \
"$GIT_CL dcommit"
test_expect_success "git-cl dcommit --tbr succeeds" \
"$GIT_CL dcommit --tbr -f | grep -q -- '--tbr was specified'"
)
SUCCESS=$?
cleanup
if [ $SUCCESS == 0 ]; then
echo PASS
fi

@ -1,37 +0,0 @@
#!/bin/bash
set -e
. ./test-lib.sh
setup_initsvn
setup_gitsvn
(
set -e
cd git-svn
cat > .git/hooks/post-cl-dcommit << _EOF
#!/bin/bash
git branch -m COMMITTED
_EOF
chmod +x .git/hooks/post-cl-dcommit
git config rietveld.server localhost:1
git checkout -q --track -b work
echo "some work done" >> test
git add test; git commit -q -m "work"
test_expect_success "dcommitted code" \
"$GIT_CL dcommit -f --tbr --bypass-hooks -m 'dcommit'"
test_expect_success "post-cl-dcommit hook executed" \
"git symbolic-ref HEAD | grep -q COMMITTED"
)
SUCCESS=$?
cleanup
if [ $SUCCESS == 0 ]; then
echo PASS
fi

@ -626,10 +626,13 @@ def CheckBuildbotPendingBuilds(input_api, output_api, url, max_pendings,
return [] return []
def CheckOwners(input_api, output_api, source_file_filter=None): def CheckOwners(input_api, output_api, email_regexp=None,
source_file_filter=None):
affected_files = set([f.LocalPath() for f in affected_files = set([f.LocalPath() for f in
input_api.change.AffectedFiles(source_file_filter)]) input_api.change.AffectedFiles(source_file_filter)])
owners_db = input_api.owners_db owners_db = input_api.owners_db
if email_regexp:
owners_db.email_regexp = input_api.re.compile(email_regexp)
if input_api.is_committing and input_api.tbr: if input_api.is_committing and input_api.tbr:
return [output_api.PresubmitNotifyResult( return [output_api.PresubmitNotifyResult(

@ -154,19 +154,12 @@ class OutputApi(object):
"""Whether this presubmit result should result in a prompt warning.""" """Whether this presubmit result should result in a prompt warning."""
return False return False
def IsMessage(self):
"""Whether this result contains anything needing to be displayed."""
return True
class PresubmitAddText(PresubmitResult): class PresubmitAddText(PresubmitResult):
"""Propagates a line of text back to the caller.""" """Propagates a line of text back to the caller."""
def __init__(self, message, items=None, long_text=''): def __init__(self, message, items=None, long_text=''):
super(OutputApi.PresubmitAddText, self).__init__("ADD: " + message, super(OutputApi.PresubmitAddText, self).__init__("ADD: " + message,
items, long_text) items, long_text)
def IsMessage(self):
return False
class PresubmitError(PresubmitResult): class PresubmitError(PresubmitResult):
"""A hard presubmit error.""" """A hard presubmit error."""
def IsFatal(self): def IsFatal(self):
@ -229,14 +222,15 @@ class InputApi(object):
# TODO(dpranke): Update callers to pass in tbr, host_url, remove # TODO(dpranke): Update callers to pass in tbr, host_url, remove
# default arguments. # default arguments.
def __init__(self, change, presubmit_path, is_committing, tbr=False, def __init__(self, change, presubmit_path, is_committing, tbr, host_url=None):
host_url='http://codereview.chromium.org'):
"""Builds an InputApi object. """Builds an InputApi object.
Args: Args:
change: A presubmit.Change object. change: A presubmit.Change object.
presubmit_path: The path to the presubmit script being processed. presubmit_path: The path to the presubmit script being processed.
is_committing: True if the change is about to be committed. is_committing: True if the change is about to be committed.
tbr: True if '--tbr' was passed to skip any reviewer/owner checks
host_url: scheme, host, and path of rietveld instance
""" """
# Version number of the presubmit_support script. # Version number of the presubmit_support script.
self.version = [int(x) for x in __version__.split('.')] self.version = [int(x) for x in __version__.split('.')]
@ -244,6 +238,7 @@ class InputApi(object):
self.host_url = host_url self.host_url = host_url
self.is_committing = is_committing self.is_committing = is_committing
self.tbr = tbr self.tbr = tbr
self.host_url = host_url or 'http://codereview.chromium.org'
# We expose various modules and functions as attributes of the input_api # We expose various modules and functions as attributes of the input_api
# so that presubmit scripts don't have to import them. # so that presubmit scripts don't have to import them.
@ -935,14 +930,19 @@ def DoGetTrySlaves(changed_files,
class PresubmitExecuter(object): class PresubmitExecuter(object):
def __init__(self, change, committing): def __init__(self, change, committing, tbr, host_url):
""" """
Args: Args:
change: The Change object. change: The Change object.
committing: True if 'gcl commit' is running, False if 'gcl upload' is. committing: True if 'gcl commit' is running, False if 'gcl upload' is.
tbr: True if '--tbr' was passed to skip any reviewer/owner checks
host_url: scheme, host, and path of rietveld instance
(or None for default)
""" """
self.change = change self.change = change
self.committing = committing self.committing = committing
self.tbr = tbr
self.host_url = host_url
def ExecPresubmitScript(self, script_text, presubmit_path): def ExecPresubmitScript(self, script_text, presubmit_path):
"""Executes a single presubmit script. """Executes a single presubmit script.
@ -961,7 +961,8 @@ class PresubmitExecuter(object):
os.chdir(os.path.dirname(presubmit_path)) os.chdir(os.path.dirname(presubmit_path))
# Load the presubmit script into context. # Load the presubmit script into context.
input_api = InputApi(self.change, presubmit_path, self.committing) input_api = InputApi(self.change, presubmit_path, self.committing,
self.tbr, self.host_url)
context = {} context = {}
exec script_text in context exec script_text in context
@ -992,14 +993,16 @@ class PresubmitExecuter(object):
os.chdir(main_path) os.chdir(main_path)
return result return result
# TODO(dpranke): make all callers pass in tbr, host_url?
def DoPresubmitChecks(change, def DoPresubmitChecks(change,
committing, committing,
verbose, verbose,
output_stream, output_stream,
input_stream, input_stream,
default_presubmit, default_presubmit,
may_prompt): may_prompt,
tbr=False,
host_url=None):
"""Runs all presubmit checks that apply to the files in the change. """Runs all presubmit checks that apply to the files in the change.
This finds all PRESUBMIT.py files in directories enclosing the files in the This finds all PRESUBMIT.py files in directories enclosing the files in the
@ -1017,6 +1020,9 @@ def DoPresubmitChecks(change,
input_stream: A stream to read input from the user. input_stream: A stream to read input from the user.
default_presubmit: A default presubmit script to execute in any case. default_presubmit: A default presubmit script to execute in any case.
may_prompt: Enable (y/n) questions on warning or error. may_prompt: Enable (y/n) questions on warning or error.
tbr: was --tbr specified to skip any reviewer/owner checks?
host_url: scheme, host, and port of host to use for rietveld-related
checks
Warning: Warning:
If may_prompt is true, output_stream SHOULD be sys.stdout and input_stream If may_prompt is true, output_stream SHOULD be sys.stdout and input_stream
@ -1032,7 +1038,7 @@ def DoPresubmitChecks(change,
if not presubmit_files and verbose: if not presubmit_files and verbose:
output_stream.write("Warning, no presubmit.py found.\n") output_stream.write("Warning, no presubmit.py found.\n")
results = [] results = []
executer = PresubmitExecuter(change, committing) executer = PresubmitExecuter(change, committing, tbr, host_url)
if default_presubmit: if default_presubmit:
if verbose: if verbose:
output_stream.write("Running default presubmit script.\n") output_stream.write("Running default presubmit script.\n")
@ -1064,9 +1070,6 @@ def DoPresubmitChecks(change,
if items: if items:
output_stream.write('** Presubmit %s **\n' % name) output_stream.write('** Presubmit %s **\n' % name)
for item in items: for item in items:
if not item.IsMessage():
continue
# Access to a protected member XXX of a client class # Access to a protected member XXX of a client class
# pylint: disable=W0212 # pylint: disable=W0212
if not item._Handle(output_stream, input_stream, if not item._Handle(output_stream, input_stream,

@ -342,7 +342,7 @@ class PresubmitUnittest(PresubmitTestsBase):
change = presubmit.Change('mychange', '\n'.join(description_lines), change = presubmit.Change('mychange', '\n'.join(description_lines),
self.fake_root_dir, files, 0, 0) self.fake_root_dir, files, 0, 0)
executer = presubmit.PresubmitExecuter(change, False) executer = presubmit.PresubmitExecuter(change, False, False, None)
self.failIf(executer.ExecPresubmitScript('', fake_presubmit)) self.failIf(executer.ExecPresubmitScript('', fake_presubmit))
# No error if no on-upload entry point # No error if no on-upload entry point
self.failIf(executer.ExecPresubmitScript( self.failIf(executer.ExecPresubmitScript(
@ -351,7 +351,7 @@ class PresubmitUnittest(PresubmitTestsBase):
fake_presubmit fake_presubmit
)) ))
executer = presubmit.PresubmitExecuter(change, True) executer = presubmit.PresubmitExecuter(change, True, False, None)
# No error if no on-commit entry point # No error if no on-commit entry point
self.failIf(executer.ExecPresubmitScript( self.failIf(executer.ExecPresubmitScript(
('def CheckChangeOnUpload(input_api, output_api):\n' ('def CheckChangeOnUpload(input_api, output_api):\n'
@ -706,7 +706,8 @@ class InputApiUnittest(PresubmitTestsBase):
'version', 'version',
] ]
# If this test fails, you should add the relevant test. # If this test fails, you should add the relevant test.
self.compareMembers(presubmit.InputApi(self.fake_change, './.', False), self.compareMembers(presubmit.InputApi(self.fake_change, './.', False,
False, None),
members) members)
def testDepotToLocalPath(self): def testDepotToLocalPath(self):
@ -715,31 +716,32 @@ class InputApiUnittest(PresubmitTestsBase):
presubmit.scm.SVN.CaptureInfo('svn:/foo/notfound/burp').AndReturn({}) presubmit.scm.SVN.CaptureInfo('svn:/foo/notfound/burp').AndReturn({})
self.mox.ReplayAll() self.mox.ReplayAll()
path = presubmit.InputApi(self.fake_change, './p', False).DepotToLocalPath( path = presubmit.InputApi(self.fake_change, './p', False, False,
'svn://foo/smurf') None).DepotToLocalPath('svn://foo/smurf')
self.failUnless(path == 'prout') self.failUnless(path == 'prout')
path = presubmit.InputApi(self.fake_change, './p', False).DepotToLocalPath( path = presubmit.InputApi(self.fake_change, './p', False, False,
'svn:/foo/notfound/burp') None).DepotToLocalPath('svn:/foo/notfound/burp')
self.failUnless(path == None) self.failUnless(path == None)
def testLocalToDepotPath(self): def testLocalToDepotPath(self):
presubmit.scm.SVN.CaptureInfo('smurf').AndReturn({'URL': 'svn://foo'}) presubmit.scm.SVN.CaptureInfo('smurf').AndReturn({'URL': 'svn://foo'})
presubmit.scm.SVN.CaptureInfo('notfound-food').AndReturn({}) presubmit.scm.SVN.CaptureInfo('notfound-food').AndReturn({})
self.mox.ReplayAll() self.mox.ReplayAll()
path = presubmit.InputApi(self.fake_change, './p', False).LocalToDepotPath( path = presubmit.InputApi(self.fake_change, './p', False, False,
'smurf') None).LocalToDepotPath('smurf')
self.assertEqual(path, 'svn://foo') self.assertEqual(path, 'svn://foo')
path = presubmit.InputApi(self.fake_change, './p', False).LocalToDepotPath( path = presubmit.InputApi(self.fake_change, './p', False, False,
'notfound-food') None).LocalToDepotPath('notfound-food')
self.failUnless(path == None) self.failUnless(path == None)
def testInputApiConstruction(self): def testInputApiConstruction(self):
self.mox.ReplayAll() self.mox.ReplayAll()
api = presubmit.InputApi(self.fake_change, api = presubmit.InputApi(self.fake_change,
presubmit_path='foo/path/PRESUBMIT.py', presubmit_path='foo/path/PRESUBMIT.py',
is_committing=False) is_committing=False, tbr=False, host_url=None)
self.assertEquals(api.PresubmitLocalPath(), 'foo/path') self.assertEquals(api.PresubmitLocalPath(), 'foo/path')
self.assertEquals(api.change, self.fake_change) self.assertEquals(api.change, self.fake_change)
self.assertEquals(api.host_url, 'http://codereview.chromium.org')
def testInputApiPresubmitScriptFiltering(self): def testInputApiPresubmitScriptFiltering(self):
join = presubmit.os.path.join join = presubmit.os.path.join
@ -795,7 +797,7 @@ class InputApiUnittest(PresubmitTestsBase):
input_api = presubmit.InputApi(change, input_api = presubmit.InputApi(change,
join(self.fake_root_dir, 'foo', join(self.fake_root_dir, 'foo',
'PRESUBMIT.py'), 'PRESUBMIT.py'),
False) False, False, None)
# Doesn't filter much # Doesn't filter much
got_files = input_api.AffectedFiles() got_files = input_api.AffectedFiles()
self.assertEquals(len(got_files), 7) self.assertEquals(len(got_files), 7)
@ -880,7 +882,8 @@ class InputApiUnittest(PresubmitTestsBase):
], ],
), ),
] ]
input_api = presubmit.InputApi(self.fake_change, './PRESUBMIT.py', False) input_api = presubmit.InputApi(self.fake_change, './PRESUBMIT.py', False,
False, None)
self.mox.ReplayAll() self.mox.ReplayAll()
self.assertEqual(len(input_api.DEFAULT_WHITE_LIST), 22) self.assertEqual(len(input_api.DEFAULT_WHITE_LIST), 22)
@ -911,7 +914,7 @@ class InputApiUnittest(PresubmitTestsBase):
input_api = presubmit.InputApi(change, input_api = presubmit.InputApi(change,
presubmit.os.path.join(self.fake_root_dir, presubmit.os.path.join(self.fake_root_dir,
'PRESUBMIT.py'), 'PRESUBMIT.py'),
False) False, False, None)
got_files = input_api.AffectedSourceFiles(FilterSourceFile) got_files = input_api.AffectedSourceFiles(FilterSourceFile)
self.assertEquals(len(got_files), 2) self.assertEquals(len(got_files), 2)
self.assertEquals(got_files[0].LocalPath(), 'eeaee') self.assertEquals(got_files[0].LocalPath(), 'eeaee')
@ -930,7 +933,8 @@ class InputApiUnittest(PresubmitTestsBase):
change = presubmit.SvnChange('mychange', '', self.fake_root_dir, files, 0, change = presubmit.SvnChange('mychange', '', self.fake_root_dir, files, 0,
0) 0)
input_api = presubmit.InputApi(change, './PRESUBMIT.py', False) input_api = presubmit.InputApi(change, './PRESUBMIT.py', False,
False, None)
# Sample usage of overiding the default white and black lists. # Sample usage of overiding the default white and black lists.
got_files = input_api.AffectedSourceFiles( got_files = input_api.AffectedSourceFiles(
lambda x: input_api.FilterSourceFile(x, white_list, black_list)) lambda x: input_api.FilterSourceFile(x, white_list, black_list))
@ -970,7 +974,7 @@ class InputApiUnittest(PresubmitTestsBase):
presubmit_path = join(self.fake_root_dir, 'isdir', 'PRESUBMIT.py') presubmit_path = join(self.fake_root_dir, 'isdir', 'PRESUBMIT.py')
api = presubmit.InputApi(change=change, api = presubmit.InputApi(change=change,
presubmit_path=presubmit_path, presubmit_path=presubmit_path,
is_committing=True) is_committing=True, tbr=False, host_url=None)
paths_from_api = api.AbsoluteLocalPaths(include_dirs=True) paths_from_api = api.AbsoluteLocalPaths(include_dirs=True)
self.assertEqual(len(paths_from_api), 2) self.assertEqual(len(paths_from_api), 2)
for absolute_paths in [paths_from_change, paths_from_api]: for absolute_paths in [paths_from_change, paths_from_api]:
@ -986,7 +990,8 @@ class InputApiUnittest(PresubmitTestsBase):
change = presubmit.Change('mychange', '', self.fake_root_dir, [], 0, 0) change = presubmit.Change('mychange', '', self.fake_root_dir, [], 0, 0)
api = presubmit.InputApi( api = presubmit.InputApi(
change, change,
presubmit.os.path.join(self.fake_root_dir, 'foo', 'PRESUBMIT.py'), True) presubmit.os.path.join(self.fake_root_dir, 'foo', 'PRESUBMIT.py'), True,
False, None)
api.AffectedTextFiles(include_deletes=False) api.AffectedTextFiles(include_deletes=False)
def testReadFileStringDenied(self): def testReadFileStringDenied(self):
@ -995,7 +1000,8 @@ class InputApiUnittest(PresubmitTestsBase):
change = presubmit.Change('foo', 'foo', self.fake_root_dir, [('M', 'AA')], change = presubmit.Change('foo', 'foo', self.fake_root_dir, [('M', 'AA')],
0, 0) 0, 0)
input_api = presubmit.InputApi( input_api = presubmit.InputApi(
change, presubmit.os.path.join(self.fake_root_dir, '/p'), False) change, presubmit.os.path.join(self.fake_root_dir, '/p'), False,
False, None)
self.assertRaises(IOError, input_api.ReadFile, 'boo', 'x') self.assertRaises(IOError, input_api.ReadFile, 'boo', 'x')
def testReadFileStringAccepted(self): def testReadFileStringAccepted(self):
@ -1006,7 +1012,8 @@ class InputApiUnittest(PresubmitTestsBase):
change = presubmit.Change('foo', 'foo', self.fake_root_dir, [('M', 'AA')], change = presubmit.Change('foo', 'foo', self.fake_root_dir, [('M', 'AA')],
0, 0) 0, 0)
input_api = presubmit.InputApi( input_api = presubmit.InputApi(
change, presubmit.os.path.join(self.fake_root_dir, '/p'), False) change, presubmit.os.path.join(self.fake_root_dir, '/p'), False,
False, None)
input_api.ReadFile(path, 'x') input_api.ReadFile(path, 'x')
def testReadFileAffectedFileDenied(self): def testReadFileAffectedFileDenied(self):
@ -1016,7 +1023,8 @@ class InputApiUnittest(PresubmitTestsBase):
change = presubmit.Change('foo', 'foo', self.fake_root_dir, [('M', 'AA')], change = presubmit.Change('foo', 'foo', self.fake_root_dir, [('M', 'AA')],
0, 0) 0, 0)
input_api = presubmit.InputApi( input_api = presubmit.InputApi(
change, presubmit.os.path.join(self.fake_root_dir, '/p'), False) change, presubmit.os.path.join(self.fake_root_dir, '/p'), False,
False, None)
self.assertRaises(IOError, input_api.ReadFile, fileobj, 'x') self.assertRaises(IOError, input_api.ReadFile, fileobj, 'x')
def testReadFileAffectedFileAccepted(self): def testReadFileAffectedFileAccepted(self):
@ -1028,7 +1036,8 @@ class InputApiUnittest(PresubmitTestsBase):
change = presubmit.Change('foo', 'foo', self.fake_root_dir, [('M', 'AA')], change = presubmit.Change('foo', 'foo', self.fake_root_dir, [('M', 'AA')],
0, 0) 0, 0)
input_api = presubmit.InputApi( input_api = presubmit.InputApi(
change, presubmit.os.path.join(self.fake_root_dir, '/p'), False) change, presubmit.os.path.join(self.fake_root_dir, '/p'), False,
False, None)
input_api.ReadFile(fileobj, 'x') input_api.ReadFile(fileobj, 'x')
@ -1046,23 +1055,17 @@ class OuputApiUnittest(PresubmitTestsBase):
def testOutputApiBasics(self): def testOutputApiBasics(self):
self.mox.ReplayAll() self.mox.ReplayAll()
self.failUnless(presubmit.OutputApi.PresubmitError('').IsFatal()) self.failUnless(presubmit.OutputApi.PresubmitError('').IsFatal())
self.failUnless(presubmit.OutputApi.PresubmitError('').IsMessage())
self.failIf(presubmit.OutputApi.PresubmitError('').ShouldPrompt()) self.failIf(presubmit.OutputApi.PresubmitError('').ShouldPrompt())
self.failIf(presubmit.OutputApi.PresubmitPromptWarning('').IsFatal()) self.failIf(presubmit.OutputApi.PresubmitPromptWarning('').IsFatal())
self.failUnless( self.failUnless(
presubmit.OutputApi.PresubmitPromptWarning('').ShouldPrompt()) presubmit.OutputApi.PresubmitPromptWarning('').ShouldPrompt())
self.failUnless(
presubmit.OutputApi.PresubmitPromptWarning('').IsMessage())
self.failIf(presubmit.OutputApi.PresubmitNotifyResult('').IsFatal()) self.failIf(presubmit.OutputApi.PresubmitNotifyResult('').IsFatal())
self.failIf(presubmit.OutputApi.PresubmitNotifyResult('').ShouldPrompt()) self.failIf(presubmit.OutputApi.PresubmitNotifyResult('').ShouldPrompt())
self.failUnless(
presubmit.OutputApi.PresubmitNotifyResult('foo').IsMessage())
self.failIf(presubmit.OutputApi.PresubmitAddText('foo').IsFatal()) self.failIf(presubmit.OutputApi.PresubmitAddText('foo').IsFatal())
self.failIf(presubmit.OutputApi.PresubmitAddText('foo').ShouldPrompt()) self.failIf(presubmit.OutputApi.PresubmitAddText('foo').ShouldPrompt())
self.failIf(presubmit.OutputApi.PresubmitAddText('foo').IsMessage())
# TODO(joi) Test MailTextResult once implemented. # TODO(joi) Test MailTextResult once implemented.
@ -1880,7 +1883,7 @@ mac|success|blew
messages = list('{"sender": "' + a + '","text": "lgtm"}' for messages = list('{"sender": "' + a + '","text": "lgtm"}' for
a in approvers) a in approvers)
rietveld_response = ('{"owner": "john@example.com",' rietveld_response = ('{"owner": "john@example.com",'
'"messages": [' + ','.join(messages) + ']}') '"messages": [' + ','.join(messages) + ']}')
input_api.urllib2.urlopen( input_api.urllib2.urlopen(
input_api.host_url + '/api/1?messages=true').AndReturn( input_api.host_url + '/api/1?messages=true').AndReturn(
StringIO.StringIO(rietveld_response)) StringIO.StringIO(rietveld_response))

Loading…
Cancel
Save