Index: presubmit_canned_checks.py |
diff --git a/presubmit_canned_checks.py b/presubmit_canned_checks.py |
index 839fe1d7f3b56e6ec18b20492cd5a409d2c32b3d..52081912b6665a23edaafe5d7c32991b6d998192 100644 |
--- a/presubmit_canned_checks.py |
+++ b/presubmit_canned_checks.py |
@@ -12,7 +12,7 @@ def CheckChangeHasTestField(input_api, output_api): |
return [] |
else: |
return [output_api.PresubmitNotifyResult( |
- "Changelist should have a TEST= field. TEST=none is allowed.")] |
+ 'Changelist should have a TEST= field. TEST=none is allowed.')] |
def CheckChangeHasBugField(input_api, output_api): |
@@ -21,7 +21,7 @@ def CheckChangeHasBugField(input_api, output_api): |
return [] |
else: |
return [output_api.PresubmitNotifyResult( |
- "Changelist should have a BUG= field. BUG=none is allowed.")] |
+ 'Changelist should have a BUG= field. BUG=none is allowed.')] |
def CheckChangeHasTestedField(input_api, output_api): |
@@ -29,7 +29,7 @@ def CheckChangeHasTestedField(input_api, output_api): |
if input_api.change.TESTED: |
return [] |
else: |
- return [output_api.PresubmitError("Changelist must have a TESTED= field.")] |
+ return [output_api.PresubmitError('Changelist must have a TESTED= field.')] |
def CheckChangeHasQaField(input_api, output_api): |
@@ -37,7 +37,7 @@ def CheckChangeHasQaField(input_api, output_api): |
if input_api.change.QA: |
return [] |
else: |
- return [output_api.PresubmitError("Changelist must have a QA= field.")] |
+ return [output_api.PresubmitError('Changelist must have a QA= field.')] |
def CheckDoNotSubmitInDescription(input_api, output_api): |
@@ -46,7 +46,7 @@ def CheckDoNotSubmitInDescription(input_api, output_api): |
keyword = 'DO NOT ' + 'SUBMIT' |
if keyword in input_api.change.DescriptionText(): |
return [output_api.PresubmitError( |
- keyword + " is present in the changelist description.")] |
+ keyword + ' is present in the changelist description.')] |
else: |
return [] |
@@ -56,9 +56,9 @@ def CheckChangeHasDescription(input_api, output_api): |
text = input_api.change.DescriptionText() |
if text.strip() == '': |
if input_api.is_committing: |
- return [output_api.PresubmitError("Add a description.")] |
+ return [output_api.PresubmitError('Add a description.')] |
else: |
- return [output_api.PresubmitNotifyResult("Add a description.")] |
+ return [output_api.PresubmitNotifyResult('Add a description.')] |
return [] |
### Content checks |
@@ -75,7 +75,7 @@ def CheckDoNotSubmitInFiles(input_api, output_api): |
def CheckChangeLintsClean(input_api, output_api, source_file_filter=None): |
- """Checks that all ".cc" and ".h" files pass cpplint.py.""" |
+ """Checks that all '.cc' and '.h' files pass cpplint.py.""" |
_RE_IS_TEST = input_api.re.compile(r'.*tests?.(cc|h)$') |
result = [] |
@@ -92,9 +92,9 @@ def CheckChangeLintsClean(input_api, output_api, source_file_filter=None): |
# - runtime/int : Can be fixed long term; volume of errors too high |
# - runtime/virtual : Broken now, but can be fixed in the future? |
# - whitespace/braces : We have a lot of explicit scoping in chrome code. |
- cpplint._SetFilters("-build/include,-build/include_order,-build/namespace," |
- "-readability/casting,-runtime/int,-runtime/virtual," |
- "-whitespace/braces") |
+ cpplint._SetFilters('-build/include,-build/include_order,-build/namespace,' |
+ '-readability/casting,-runtime/int,-runtime/virtual,' |
+ '-whitespace/braces') |
# We currently are more strict with normal code than unit tests; 4 and 5 are |
# the verbosity level that would normally be passed to cpplint.py through |
@@ -114,7 +114,7 @@ def CheckChangeLintsClean(input_api, output_api, source_file_filter=None): |
res_type = output_api.PresubmitError |
else: |
res_type = output_api.PresubmitPromptWarning |
- result = [res_type("Changelist failed cpplint.py check.")] |
+ result = [res_type('Changelist failed cpplint.py check.')] |
return result |
@@ -127,7 +127,7 @@ def CheckChangeHasNoCR(input_api, output_api, source_file_filter=None): |
cr_files.append(f.LocalPath()) |
if cr_files: |
return [output_api.PresubmitPromptWarning( |
- "Found a CR character in these files:", items=cr_files)] |
+ 'Found a CR character in these files:', items=cr_files)] |
return [] |
@@ -162,7 +162,7 @@ def CheckSvnModifiedDirectories(input_api, output_api, source_file_filter=None): |
else: |
error_type = output_api.PresubmitNotifyResult |
errors.append(error_type( |
- "Potential accidental commits in changelist %s:" % f.LocalPath(), |
+ 'Potential accidental commits in changelist %s:' % f.LocalPath(), |
items=bad_files)) |
return errors |
@@ -173,7 +173,7 @@ def CheckChangeHasOnlyOneEol(input_api, output_api, source_file_filter=None): |
for f in input_api.AffectedSourceFiles(source_file_filter): |
contents = input_api.ReadFile(f, 'rb') |
# Check that the file ends in one and only one newline character. |
- if len(contents) > 1 and (contents[-1:] != "\n" or contents[-2:-1] == "\n"): |
+ if len(contents) > 1 and (contents[-1:] != '\n' or contents[-2:-1] == '\n'): |
eof_files.append(f.LocalPath()) |
if eof_files: |
@@ -196,12 +196,12 @@ def CheckChangeHasNoCrAndHasOnlyOneEol(input_api, output_api, |
if '\r' in contents: |
cr_files.append(f.LocalPath()) |
# Check that the file ends in one and only one newline character. |
- if len(contents) > 1 and (contents[-1:] != "\n" or contents[-2:-1] == "\n"): |
+ if len(contents) > 1 and (contents[-1:] != '\n' or contents[-2:-1] == '\n'): |
eof_files.append(f.LocalPath()) |
outputs = [] |
if cr_files: |
outputs.append(output_api.PresubmitPromptWarning( |
- "Found a CR character in these files:", items=cr_files)) |
+ 'Found a CR character in these files:', items=cr_files)) |
if eof_files: |
outputs.append(output_api.PresubmitPromptWarning( |
'These files should end in one (and only one) newline character:', |
@@ -216,10 +216,10 @@ def CheckChangeHasNoTabs(input_api, output_api, source_file_filter=None): |
tabs = [] |
for f, line_num, line in input_api.RightHandSideLines(source_file_filter): |
if '\t' in line: |
- tabs.append("%s, line %s" % (f.LocalPath(), line_num)) |
+ tabs.append('%s, line %s' % (f.LocalPath(), line_num)) |
if tabs: |
- return [output_api.PresubmitPromptWarning("Found a tab character in:", |
- long_text="\n".join(tabs))] |
+ return [output_api.PresubmitPromptWarning('Found a tab character in:', |
+ long_text='\n'.join(tabs))] |
return [] |
@@ -229,11 +229,11 @@ def CheckChangeHasNoStrayWhitespace(input_api, output_api, |
errors = [] |
for f, line_num, line in input_api.RightHandSideLines(source_file_filter): |
if line.rstrip() != line: |
- errors.append("%s, line %s" % (f.LocalPath(), line_num)) |
+ errors.append('%s, line %s' % (f.LocalPath(), line_num)) |
if errors: |
return [output_api.PresubmitPromptWarning( |
- "Found line ending with white spaces in:", |
- long_text="\n".join(errors))] |
+ 'Found line ending with white spaces in:', |
+ long_text='\n'.join(errors))] |
return [] |
@@ -260,7 +260,7 @@ def CheckLongLines(input_api, output_api, maxlen=80, source_file_filter=None): |
break |
if bad: |
- msg = "Found lines longer than %s characters (first 5 shown)." % maxlen |
+ msg = 'Found lines longer than %s characters (first 5 shown).' % maxlen |
return [output_api.PresubmitPromptWarning(msg, items=bad)] |
else: |
return [] |
@@ -281,7 +281,7 @@ def CheckLicense(input_api, output_api, license, source_file_filter=None): |
else: |
res_type = output_api.PresubmitNotifyResult |
return [res_type( |
- "Found a bad license header in these files:", items=bad_files)] |
+ 'Found a bad license header in these files:', items=bad_files)] |
return [] |
@@ -327,7 +327,7 @@ def CheckSvnProperty(input_api, output_api, prop, expected, affected_files): |
res_type = output_api.PresubmitError |
else: |
res_type = output_api.PresubmitNotifyResult |
- message = "Run the command: svn pset %s %s \\" % (prop, expected) |
+ message = 'Run the command: svn pset %s %s \\' % (prop, expected) |
return [res_type(message, items=bad)] |
return [] |
@@ -344,14 +344,15 @@ def CheckDoNotSubmit(input_api, output_api): |
def CheckTreeIsOpen(input_api, output_api, url, closed): |
"""Checks that an url's content doesn't match a regexp that would mean that |
the tree is closed.""" |
- assert(input_api.is_committing) |
+ if not input_api.is_committing: |
+ return [] |
try: |
connection = input_api.urllib2.urlopen(url) |
status = connection.read() |
connection.close() |
if input_api.re.match(closed, status): |
long_text = status + '\n' + url |
- return [output_api.PresubmitPromptWarning("The tree is closed.", |
+ return [output_api.PresubmitPromptWarning('The tree is closed.', |
long_text=long_text)] |
except IOError: |
pass |
@@ -375,7 +376,7 @@ def RunPythonUnitTests(input_api, output_api, unit_tests): |
cwd = None |
env = None |
unit_test_name = unit_test |
- # "python -m test.unit_test" doesn't work. We need to change to the right |
+ # 'python -m test.unit_test' doesn't work. We need to change to the right |
# directory instead. |
if '.' in unit_test: |
# Tests imported in submodules (subdirectories) assume that the current |
@@ -394,8 +395,8 @@ def RunPythonUnitTests(input_api, output_api, unit_tests): |
subproc = input_api.subprocess.Popen( |
[ |
input_api.python_executable, |
- "-m", |
- "%s" % unit_test |
+ '-m', |
+ '%s' % unit_test |
], |
cwd=cwd, |
env=env, |
@@ -405,9 +406,92 @@ def RunPythonUnitTests(input_api, output_api, unit_tests): |
stdoutdata, stderrdata = subproc.communicate() |
# Discard the output if returncode == 0 |
if subproc.returncode: |
- outputs.append("Test '%s' failed with code %d\n%s\n%s\n" % ( |
+ outputs.append('Test \'%s\' failed with code %d\n%s\n%s\n' % ( |
unit_test_name, subproc.returncode, stdoutdata, stderrdata)) |
if outputs: |
- return [message_type("%d unit tests failed." % len(outputs), |
+ return [message_type('%d unit tests failed.' % len(outputs), |
long_text='\n'.join(outputs))] |
return [] |
+ |
+ |
+def CheckRietveldTryJobExecution(input_api, output_api, host_url, platforms, |
+ owner): |
+ if not input_api.is_committing: |
+ return [] |
+ if not input_api.change.issue or not input_api.change.patchset: |
+ return [] |
+ url = '%s/%d/get_build_results/%d' % ( |
+ host_url, input_api.change.issue, input_api.change.patchset) |
+ try: |
+ connection = input_api.urllib2.urlopen(url) |
+ # platform|status|url |
+ values = [item.split('|', 2) for item in connection.read().splitlines()] |
+ connection.close() |
+ except input_api.urllib2.HTTPError, e: |
+ if e.code == 404: |
+ # Fallback to no try job. |
+ return [output_api.PresubmitPromptWarning( |
+ 'You should try the patch first.')] |
+ else: |
+ # Another HTTP error happened, warn the user. |
+ return [output_api.PresubmitPromptWarning( |
+ 'Got %s while looking for try job status.' % str(e))] |
+ |
+ if not values: |
+ # It returned an empty list. Probably a private review. |
+ return [] |
+ # Reformat as an dict of platform: [status, url] |
+ values = dict([[v[0], [v[1], v[2]]] for v in values if len(v) == 3]) |
+ if not values: |
+ # It returned useless data. |
+ return [output_api.PresubmitNotifyResult('Failed to parse try job results')] |
+ |
+ for platform in platforms: |
+ values.setdefault(platform, ['not started', '']) |
+ message = None |
+ non_success = [k.upper() for k,v in values.iteritems() if v[0] != 'success'] |
+ if 'failure' in [v[0] for v in values.itervalues()]: |
+ message = 'Try job failures on %s!\n' % ', '.join(non_success) |
+ elif non_success: |
+ message = ('Unfinished (or not even started) try jobs on ' |
+ '%s.\n') % ', '.join(non_success) |
+ if message: |
+ message += ( |
+ 'Is try server wrong or broken? Please notify %s. ' |
+ 'Thanks.\n' % owner) |
+ return [output_api.PresubmitPromptWarning(message=message)] |
+ return [] |
+ |
+ |
+def CheckBuildbotPendingBuilds(input_api, output_api, url, max_pendings, |
+ ignored): |
+ if not input_api.json: |
+ return [output_api.PresubmitPromptWarning( |
+ 'Please install simplejson or upgrade to python 2.6+')] |
+ try: |
+ connection = input_api.urllib2.urlopen(url) |
+ raw_data = connection.read() |
+ connection.close() |
+ except IOError: |
+ return [output_api.PresubmitNotifyResult('%s is not accessible' % url)] |
+ |
+ try: |
+ data = input_api.json.loads(raw_data) |
+ except ValueError: |
+ return [output_api.PresubmitNotifyResult('Received malformed json while ' |
+ 'looking up buildbot status')] |
+ |
+ out = [] |
+ for (builder_name, builder) in data.iteritems(): |
+ if builder_name in ignored: |
+ continue |
+ pending_builds_len = len(builder.get('pending_builds', [])) |
+ if pending_builds_len > max_pendings: |
+ out.append('%s has %d build(s) pending' % |
+ (builder_name, pending_builds_len)) |
+ if out: |
+ return [output_api.PresubmitPromptWarning( |
+ 'Build(s) pending. It is suggested to wait that no more than %d ' |
+ 'builds are pending.' % max_pendings, |
+ long_text='\n'.join(out))] |
+ return [] |