PRESUBMIT.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. # Copyright 2012 The Chromium Authors. All rights reserved.
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. """Presubmit script for changes affecting tools/perf/.
  5. See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
  6. for more details about the presubmit API built into depot_tools.
  7. """
  8. import os
  9. USE_PYTHON3 = True
  10. def _CommonChecks(input_api, output_api, block_on_failure=False):
  11. """Performs common checks, which includes running pylint.
  12. block_on_failure: For some failures, we would like to warn the
  13. user but still allow them to upload the change. However, we
  14. don't want them to commit code with those failures, so we
  15. need to block the change on commit.
  16. """
  17. results = []
  18. results.extend(_CheckExpectations(input_api, output_api))
  19. results.extend(_CheckJson(input_api, output_api))
  20. results.extend(
  21. _CheckPerfDataCurrentness(input_api, output_api, block_on_failure))
  22. results.extend(
  23. _CheckPerfJsonConfigs(input_api, output_api, block_on_failure))
  24. results.extend(_CheckWprShaFiles(input_api, output_api))
  25. results.extend(_CheckShardMaps(input_api, output_api, block_on_failure))
  26. results.extend(_CheckVersionsInSmokeTests(input_api, output_api))
  27. results.extend(
  28. input_api.RunTests(
  29. input_api.canned_checks.GetPylint(
  30. input_api,
  31. output_api,
  32. extra_paths_list=_GetPathsToPrepend(input_api),
  33. pylintrc='pylintrc',
  34. version='2.7')))
  35. return results
  36. def _GetPathsToPrepend(input_api):
  37. perf_dir = input_api.PresubmitLocalPath()
  38. chromium_src_dir = input_api.os_path.join(perf_dir, '..', '..')
  39. telemetry_dir = input_api.os_path.join(
  40. chromium_src_dir, 'third_party', 'catapult', 'telemetry')
  41. typ_dir = input_api.os_path.join(
  42. chromium_src_dir, 'third_party', 'catapult', 'third_party', 'typ')
  43. experimental_dir = input_api.os_path.join(
  44. chromium_src_dir, 'third_party', 'catapult', 'experimental')
  45. tracing_dir = input_api.os_path.join(
  46. chromium_src_dir, 'third_party', 'catapult', 'tracing')
  47. py_utils_dir = input_api.os_path.join(
  48. chromium_src_dir, 'third_party', 'catapult', 'common', 'py_utils')
  49. android_pylib_dir = input_api.os_path.join(
  50. chromium_src_dir, 'build', 'android')
  51. testing_dir = input_api.os_path.join(chromium_src_dir, 'testing')
  52. return [
  53. telemetry_dir,
  54. typ_dir,
  55. input_api.os_path.join(telemetry_dir, 'third_party', 'mock'),
  56. experimental_dir,
  57. tracing_dir,
  58. py_utils_dir,
  59. android_pylib_dir,
  60. testing_dir,
  61. ]
  62. def _RunArgs(args, input_api):
  63. p = input_api.subprocess.Popen(args, stdout=input_api.subprocess.PIPE,
  64. stderr=input_api.subprocess.STDOUT)
  65. out, _ = p.communicate()
  66. return (out, p.returncode)
  67. def _RunValidationScript(
  68. input_api,
  69. output_api,
  70. script_path,
  71. extra_args = None,
  72. block_on_failure = None):
  73. results = []
  74. vpython = 'vpython3.bat' if input_api.is_windows else 'vpython3'
  75. perf_dir = input_api.PresubmitLocalPath()
  76. script_abs_path = input_api.os_path.join(perf_dir, script_path)
  77. extra_args = extra_args if extra_args else []
  78. # When running git cl presubmit --all this presubmit may be asked to check
  79. # ~500 files, leading to a command line that is over 43,000 characters.
  80. # This goes past the Windows 8191 character cmd.exe limit and causes cryptic
  81. # failures. To avoid these we break the command up into smaller pieces. The
  82. # non-Windows limit is chosen so that the code that splits up commands will
  83. # get some exercise on other platforms.
  84. # Depending on how long the command is on Windows the error may be:
  85. # The command line is too long.
  86. # Or it may be:
  87. # OSError: Execution failed with error: [WinError 206] The filename or
  88. # extension is too long.
  89. # I suspect that the latter error comes from CreateProcess hitting its 32768
  90. # character limit.
  91. files_per_command = 50 if input_api.is_windows else 1000
  92. # Handle the case where extra_args is empty.
  93. for i in range(0, len(extra_args) if extra_args else 1, files_per_command):
  94. args = [vpython, script_abs_path] + extra_args[i:i + files_per_command]
  95. out, return_code = _RunArgs(args, input_api)
  96. if return_code:
  97. error_msg = 'Script ' + script_path + ' failed.'
  98. if block_on_failure is None or block_on_failure:
  99. results.append(output_api.PresubmitError(error_msg, long_text=out))
  100. else:
  101. results.append(
  102. output_api.PresubmitPromptWarning(error_msg, long_text=out))
  103. return results
  104. def _CheckExpectations(input_api, output_api):
  105. return _RunValidationScript(
  106. input_api,
  107. output_api,
  108. 'validate_story_expectation_data',
  109. )
  110. def _CheckPerfDataCurrentness(input_api, output_api, block_on_failure):
  111. return _RunValidationScript(
  112. input_api,
  113. output_api,
  114. 'generate_perf_data',
  115. ['--validate-only'],
  116. block_on_failure
  117. )
  118. def _CheckPerfJsonConfigs(input_api, output_api, block_on_failure):
  119. return _RunValidationScript(
  120. input_api,
  121. output_api,
  122. 'validate_perf_json_config',
  123. ['--validate-only'],
  124. block_on_failure
  125. )
  126. def _CheckWprShaFiles(input_api, output_api):
  127. """Check whether the wpr sha files have matching URLs."""
  128. wpr_archive_shas = []
  129. for affected_file in input_api.AffectedFiles(include_deletes=False):
  130. filename = affected_file.AbsoluteLocalPath()
  131. if not filename.endswith('.sha1'):
  132. continue
  133. wpr_archive_shas.append(filename)
  134. return _RunValidationScript(
  135. input_api,
  136. output_api,
  137. 'validate_wpr_archives',
  138. wpr_archive_shas
  139. )
  140. def _CheckShardMaps(input_api, output_api, block_on_failure):
  141. return _RunValidationScript(
  142. input_api,
  143. output_api,
  144. 'generate_perf_sharding.py',
  145. ['validate'],
  146. block_on_failure
  147. )
  148. def _CheckJson(input_api, output_api):
  149. """Checks whether JSON files in this change can be parsed."""
  150. for affected_file in input_api.AffectedFiles(include_deletes=False):
  151. filename = affected_file.AbsoluteLocalPath()
  152. if os.path.splitext(filename)[1] != '.json':
  153. continue
  154. if (os.path.basename(filename) == 'perf_results.json' and
  155. os.path.basename(os.path.dirname(filename)) == 'speedometer2-future'):
  156. # Intentionally invalid JSON file.
  157. continue
  158. try:
  159. input_api.json.load(open(filename))
  160. except ValueError:
  161. return [output_api.PresubmitError('Error parsing JSON in %s!' % filename)]
  162. return []
  163. def _CheckVersionsInSmokeTests(input_api, output_api):
  164. return _RunValidationScript(
  165. input_api,
  166. output_api,
  167. input_api.os_path.join(
  168. 'benchmarks', 'system_health_load_tests_smoke_test.py'),
  169. )
  170. def CheckChangeOnUpload(input_api, output_api):
  171. report = []
  172. report.extend(_CommonChecks(input_api, output_api))
  173. return report
  174. def CheckChangeOnCommit(input_api, output_api):
  175. report = []
  176. report.extend(_CommonChecks(input_api, output_api, block_on_failure=True))
  177. return report