Index: PRESUBMIT.py |
diff --git a/PRESUBMIT.py b/PRESUBMIT.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7a5ca44611d84425d546f67d0d5e4e08aa447c12 |
--- /dev/null |
+++ b/PRESUBMIT.py |
@@ -0,0 +1,141 @@ |
+# Copyright (c) 2014 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+ |
+"""Presubmit checks for common code.""" |
+ |
+import os |
+import subprocess |
+import sys |
+ |
+ |
+SKIA_TREE_STATUS_URL = 'http://skia-tree-status.appspot.com' |
+SKIP_RUNS_KEYWORD = '(SkipBuildbotRuns)' |
+ |
+ |
+def _RunPyUnitTests(input_api, output_api): |
+ """ Run the Python unit tests and return a list of strings containing any |
+ errors. |
+ """ |
+ results = [] |
+ success = True |
+ try: |
+ proc = subprocess.Popen(['python', os.path.join('py', 'run_unittests')], |
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |
+ success = proc.wait() == 0 |
+ long_text = proc.communicate()[0] |
+ except Exception: |
+ success = False |
+ long_text = 'Failed to run the common tests!' |
+ if not success: |
+ results.append(output_api.PresubmitPromptWarning( |
+ message='One or more unit tests failed.', |
+ long_text=long_text)) |
+ return results |
+ |
+ |
+def CheckChange(input_api, output_api): |
+ """Presubmit checks for the change on upload or commit. |
+ |
+ The presubmit checks have been handpicked from the list of canned checks |
+ here: |
+ https://chromium.googlesource.com/chromium/tools/depot_tools/+/master/presubmit_canned_checks.py |
+ |
+ The following are the presubmit checks: |
+ * Pylint is run if the change contains any .py files. |
+ * Enforces max length for all lines is 80. |
+ * Checks that the user didn't add TODO(name) without an owner. |
+ * Checks that there is no stray whitespace at source lines end. |
+ * Checks that there are no tab characters in any of the text files. |
+ """ |
+ results = [] |
+ |
+ pylint_disabled_warnings = ( |
+ 'F0401', # Unable to import. |
+ 'E0611', # No name in module. |
+ 'W0232', # Class has no __init__ method. |
+ 'E1002', # Use of super on an old style class. |
+ 'W0403', # Relative import used. |
+ 'R0201', # Method could be a function. |
+ 'E1003', # Using class name in super. |
+ 'W0613', # Unused argument. |
+ ) |
+ # Run Pylint on only the modified python files. Unfortunately it still runs |
+ # Pylint on the whole file instead of just the modified lines. |
+ affected_python_files = [] |
+ for affected_file in input_api.AffectedSourceFiles(None): |
+ affected_file_path = affected_file.LocalPath() |
+ if affected_file_path.endswith('.py'): |
+ affected_python_files.append(affected_file_path) |
+ results += input_api.canned_checks.RunPylint( |
+ input_api, output_api, |
+ disabled_warnings=pylint_disabled_warnings, |
+ white_list=affected_python_files) |
+ |
+ # Use 100 for max length for files other than python. Python length is |
+ # already checked during the Pylint above. |
+ results += input_api.canned_checks.CheckLongLines(input_api, output_api, 100) |
+ results += input_api.canned_checks.CheckChangeTodoHasOwner( |
+ input_api, output_api) |
+ results += input_api.canned_checks.CheckChangeHasNoStrayWhitespace( |
+ input_api, output_api) |
+ results += input_api.canned_checks.CheckChangeHasNoTabs(input_api, output_api) |
+ |
+ results += _RunPyUnitTests(input_api, output_api) |
+ |
+ return results |
+ |
+ |
+def _CheckTreeStatus(input_api, output_api, json_url): |
+ """Check whether to allow commit. |
+ |
+ Args: |
+ input_api: input related apis. |
+ output_api: output related apis. |
+ json_url: url to download json style status. |
+ """ |
+ results = [] |
+ tree_status_results = input_api.canned_checks.CheckTreeIsOpen( |
+ input_api, output_api, json_url=json_url) |
+ display_skip_keyword_prompt = False |
+ tree_status = None |
+ if not tree_status_results: |
+ # Check for caution state only if tree is not closed. |
+ connection = input_api.urllib2.urlopen(json_url) |
+ status = input_api.json.loads(connection.read()) |
+ connection.close() |
+ tree_status = status['message'] |
+ if 'caution' in tree_status.lower(): |
+ # Display a prompt only if we are in an interactive shell. Without this |
+ # check the commit queue behaves incorrectly because it considers |
+ # prompts to be failures. |
+ display_skip_keyword_prompt = True |
+ else: |
+ # pylint: disable=W0212 |
+ tree_status = tree_status_results[0]._message |
+ display_skip_keyword_prompt = True |
+ |
+ if (display_skip_keyword_prompt |
+ and os.isatty(sys.stdout.fileno()) |
+ and not SKIP_RUNS_KEYWORD in input_api.change.DescriptionText()): |
+ long_text = ( |
+ '%s\nAre you sure the change should be submitted. If it should be ' |
+ 'submitted but not run on the buildbots you can use the %s keyword.' % ( |
+ tree_status, SKIP_RUNS_KEYWORD)) |
+ results.append(output_api.PresubmitPromptWarning( |
+ message=tree_status, long_text=long_text)) |
+ return results |
+ |
+ |
+def CheckChangeOnUpload(input_api, output_api): |
+ return CheckChange(input_api, output_api) |
+ |
+ |
+def CheckChangeOnCommit(input_api, output_api): |
+ results = CheckChange(input_api, output_api) |
+ results.extend( |
+ _CheckTreeStatus(input_api, output_api, json_url=( |
+ SKIA_TREE_STATUS_URL + '/banner-status?format=json'))) |
+ return results |
+ |