5"""Top-level presubmit script for Dart.
7See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
8for more details about the presubmit API built into gcl.
13import importlib.machinery
16from typing
import Callable
26 return path.endswith(
'.cc')
or path.endswith(
'.h')
30 return path.endswith(
'.dart')
34 local_root = input_api.change.RepositoryRoot()
35 upstream = input_api.change._upstream
36 return scm.GIT.Capture([
'show', upstream +
':' + path],
44 "pkg/front_end/testcases/",
"pkg/front_end/parser_testcases/"
46 for git_file
in input_api.AffectedTextFiles():
47 local_path = git_file.LocalPath()
48 if not local_path.endswith(extension):
50 if any([local_path.startswith(f)
for f
in exclude_folders]):
52 files.append(git_file)
56def _CheckFormat(input_api, identification, extension, windows,
57 hasFormatErrors: Callable[[str, list, str],
58 bool], exclude_folders):
65 if not hasFormatErrors(filenames=[f.AbsoluteLocalPath()
for f
in files]):
68 print(
"Formatting errors found, comparing against old versions.")
69 unformatted_files = []
70 for git_file
in files:
71 filename = git_file.AbsoluteLocalPath()
72 if hasFormatErrors(filename=filename):
73 old_version_has_errors =
False
75 path = git_file.LocalPath()
78 path = path.replace(os.sep,
'/')
80 old_version_has_errors =
True
81 except subprocess.CalledProcessError
as e:
82 old_version_has_errors =
False
84 if old_version_has_errors:
85 print(
"WARNING: %s has existing and possibly new %s issues" %
86 (git_file.LocalPath(), identification))
88 unformatted_files.append(filename)
90 return unformatted_files
94 loader = importlib.machinery.SourceFileLoader(modname, filename)
95 spec = importlib.util.spec_from_file_location(modname,
98 module = importlib.util.module_from_spec(spec)
102 loader.exec_module(module)
106def _CheckDartFormat(input_api, output_api):
107 local_root = input_api.change.RepositoryRoot()
108 utils =
load_source(
'utils', os.path.join(local_root,
'tools',
'utils.py'))
116 if not os.path.isfile(dart):
117 print(
'WARNING: dart not found: %s' % (dart))
121 '--fix-named-default-separator',
124 def HasFormatErrors(filename: str =
None,
125 filenames: list =
None,
126 contents: str =
None):
131 if path.endswith(
'_test.dart'):
132 with open(path, encoding=
'utf-8')
as f:
134 if '//#' in contents:
138 if filename
and skip_file(filename):
145 '--set-exit-if-changed',
151 if windows
and contents:
152 f = tempfile.NamedTemporaryFile(
162 process = subprocess.run(args)
166 process = subprocess.run(args, input=contents, text=
True)
168 args += [f
for f
in filenames
if not skip_file(f)]
169 process = subprocess.run(args)
171 args.append(filename)
172 process = subprocess.run(args)
178 return process.returncode == 1
180 unformatted_files = _CheckFormat(input_api,
"dart format",
".dart", windows,
183 if unformatted_files:
188 output_api.PresubmitError(
189 'File output does not match dart format.\n'
190 'Fix these issues with:\n'
191 '%s format %s%s%s' % (dart,
' '.
join(dartFixes), lineSep,
192 lineSep.join(unformatted_files)))
198def _CheckStatusFiles(input_api, output_api):
199 local_root = input_api.change.RepositoryRoot()
200 utils =
load_source(
'utils', os.path.join(local_root,
'tools',
'utils.py'))
203 lint = os.path.join(local_root,
'pkg',
'status_file',
'bin',
'lint.dart')
209 if not os.path.isfile(dart):
210 print(
'WARNING: dart not found: %s' % dart)
213 if not os.path.isfile(lint):
214 print(
'WARNING: Status file linter not found: %s' % lint)
217 def HasFormatErrors(filename=None, filenames=None, contents=None):
223 args = [dart, lint] + ([
'-t']
if contents
else [filename])
224 process = subprocess.run(args, input=contents, text=
True)
225 return process.returncode != 0
228 "pkg/status_file/test/data/",
231 unformatted_files = _CheckFormat(input_api,
"status file",
".status",
232 windows, HasFormatErrors, exclude_folders)
234 if unformatted_files:
235 normalize = os.path.join(local_root,
'pkg',
'status_file',
'bin',
241 output_api.PresubmitError(
242 'Status files are not normalized.\n'
243 'Fix these issues with:\n'
244 '%s %s -w%s%s' % (dart, normalize, lineSep,
245 lineSep.join(unformatted_files)))
251def _CheckValidHostsInDEPS(input_api, output_api):
252 """Checks that DEPS file deps are from allowed_hosts."""
254 if all(f.LocalPath() !=
'DEPS' for f
in input_api.AffectedFiles()):
258 input_api.subprocess.check_output([
'gclient',
'verify'])
260 except input_api.subprocess.CalledProcessError
as error:
262 output_api.PresubmitError(
263 'DEPS file must have only dependencies from allowed hosts.',
264 long_text=error.output)
268def _CheckLayering(input_api, output_api):
269 """Run VM layering check.
271 This check validates that sources from one layer do
not reference sources
272 from another layer accidentally.
276 if all(
not is_cpp_file(f.LocalPath())
for f
in input_api.AffectedFiles()):
279 local_root = input_api.change.RepositoryRoot()
281 'compiler_layering_check',
282 os.path.join(local_root,
'runtime',
'tools',
283 'compiler_layering_check.py'))
286 'embedder_layering_check',
287 os.path.join(local_root,
'runtime',
'tools',
288 'embedder_layering_check.py'))
292 output_api.PresubmitError(
293 'Layering check violation for C++ sources.',
294 long_text=
'\n'.
join(errors))
300def _CheckClangTidy(input_api, output_api):
301 """Run clang-tidy on VM changes."""
304 if platform.system() !=
'Linux' or platform.machine() !=
'x86_64':
309 for f
in input_api.AffectedFiles():
311 if is_cpp_file(path)
and os.path.isfile(path): files.append(path)
317 'tools/sdks/dart-sdk/bin/dart',
318 'runtime/tools/run_clang_tidy.dart',
321 stdout = input_api.subprocess.check_output(args).strip()
326 output_api.PresubmitError(
327 'The `clang-tidy` linter revealed issues:',
332def _CheckClangFormat(input_api, output_api):
333 """Run clang-format on VM changes."""
336 if platform.system() !=
'Linux' or platform.machine() !=
'x86_64':
342 for f
in input_api.AffectedFiles():
344 if path ==
'DEPS' and any(
345 map(
lambda content:
'clang' in content[1],
346 f.ChangedContents())):
362 files = subprocess.check_output(find_args, text=
True).split()
368 'buildtools/linux-x64/clang/bin/clang-format',
373 stdout = input_api.subprocess.check_output(args).strip()
378 output_api.PresubmitError(
'The `clang-format` revealed issues:',
383def _CheckAnalyzerFiles(input_api, output_api):
384 """Run analyzer checks on source files."""
388 "pkg/analyzer/lib/src/error/error_code_values.g.dart",
389 "pkg/linter/lib/src/rules.dart",
392 if any(f.LocalPath()
in code_files
for f
in input_api.AffectedFiles()):
394 "tools/sdks/dart-sdk/bin/dart",
395 "pkg/analysis_server/tool/presubmit/verify_error_fix_status.dart",
397 stdout = input_api.subprocess.check_output(args).strip()
402 output_api.PresubmitError(
403 "The verify_error_fix_status Analyzer tool revealed issues:",
408 if any(f.LocalPath().startswith(
'pkg/linter/lib/src/rules')
409 for f
in input_api.AffectedFiles()):
411 "tools/sdks/dart-sdk/bin/dart",
412 "pkg/linter/tool/checks/check_all_yaml.dart",
414 stdout = input_api.subprocess.check_output(args).strip()
419 output_api.PresubmitError(
420 "The check_all_yaml linter tool revealed issues:",
442def _CheckTestMatrixValid(input_api, output_api):
443 """Run script to check that the test matrix has no errors."""
445 def test_matrix_filter(affected_file):
446 """Only run test if either the test matrix or the code that
447 validates it was modified."""
448 path = affected_file.LocalPath()
449 return (path ==
'tools/bots/test_matrix.json' or
450 path ==
'tools/validate_test_matrix.dart' or
451 path.startswith(
'pkg/smith/'))
454 input_api.AffectedFiles(
455 include_deletes=
False, file_filter=test_matrix_filter)) == 0:
459 'tools/sdks/dart-sdk/bin/dart',
460 'tools/validate_test_matrix.dart',
462 stdout = input_api.subprocess.check_output(command).strip()
467 output_api.PresubmitError(
468 'The test matrix is not valid:', long_text=stdout)
472def _CheckCopyrightYear(input_api, output_api):
473 """Check copyright year in new files."""
476 year = str(datetime.datetime.now().year)
477 for f
in input_api.AffectedFiles(include_deletes=
False):
480 )
and f.Action() ==
'A' and os.path.isfile(path):
481 with open(path, encoding=
'utf-8')
as f:
482 first_line = f.readline()
483 if 'Copyright' in first_line
and year
not in first_line:
490 output_api.PresubmitPromptWarning(
491 'Copyright year for new files should be ' + year +
':\n' +
496def _CheckNoNewObservatoryServiceTests(input_api, output_api):
497 """Ensures that no new tests are added to the Observatory test suite."""
500 for f
in input_api.AffectedFiles(include_deletes=
False):
503 "runtime/observatory/tests/service/")
and f.Action(
504 ) ==
'A' and os.path.isfile(path):
511 output_api.PresubmitError(
512 'New VM service tests should be added to pkg/vm_service/test, ' +
513 'not runtime/observatory/tests/service:\n' +
'\n'.
join(files))
516def _CommonChecks(input_api, output_api):
518 results.extend(_CheckValidHostsInDEPS(input_api, output_api))
519 results.extend(_CheckDartFormat(input_api, output_api))
520 results.extend(_CheckStatusFiles(input_api, output_api))
521 results.extend(_CheckLayering(input_api, output_api))
522 results.extend(_CheckClangTidy(input_api, output_api))
523 results.extend(_CheckClangFormat(input_api, output_api))
524 results.extend(_CheckTestMatrixValid(input_api, output_api))
526 input_api.canned_checks.CheckPatchFormatted(input_api, output_api))
527 results.extend(_CheckCopyrightYear(input_api, output_api))
528 results.extend(_CheckAnalyzerFiles(input_api, output_api))
529 results.extend(_CheckNoNewObservatoryServiceTests(input_api, output_api))
534 return _CommonChecks(input_api, output_api)
538 return _CommonChecks(input_api, output_api)
def CheckChangeOnCommit(input_api, output_api)
def CheckChangeOnUpload(input_api, output_api)
def files_to_check_for_format(input_api, extension, exclude_folders)
def load_source(modname, filename)
def get_old_contents(input_api, path)
def print(*args, **kwargs)
SIT bool all(const Vec< 1, T > &x)
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>
SIT bool any(const Vec< 1, T > &x)
static SkString join(const CommandLineFlags::StringArray &)