| OLD | NEW |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Fetches a copy of the latest state of a W3C test repository and commits. | 5 """Fetches a copy of the latest state of a W3C test repository and commits. |
| 6 | 6 |
| 7 If this script is given the argument --auto-update, it will also attempt to | 7 If this script is given the argument --auto-update, it will also attempt to |
| 8 upload a CL, triggery try jobs, and make any changes that are required for | 8 upload a CL, triggery try jobs, and make any changes that are required for |
| 9 new failing tests before committing. | 9 new failing tests before committing. |
| 10 """ | 10 """ |
| 11 | 11 |
| 12 import argparse | 12 import argparse |
| 13 import json | 13 import json |
| 14 | 14 |
| 15 from webkitpy.common.net.git_cl import GitCL | 15 from webkitpy.common.net.git_cl import GitCL |
| 16 from webkitpy.common.webkit_finder import WebKitFinder | 16 from webkitpy.common.webkit_finder import WebKitFinder |
| 17 from webkitpy.layout_tests.models.test_expectations import TestExpectations |
| 17 | 18 |
| 18 # Import destination directories (under LayoutTests/imported/). | 19 # Import destination directories (under LayoutTests/imported/). |
| 19 WPT_DEST_NAME = 'wpt' | 20 WPT_DEST_NAME = 'wpt' |
| 20 CSS_DEST_NAME = 'csswg-test' | 21 CSS_DEST_NAME = 'csswg-test' |
| 21 | 22 |
| 22 # Our mirrors of the official w3c repos, which we pull from. | 23 # Our mirrors of the official w3c repos, which we pull from. |
| 23 WPT_REPO_URL = 'https://chromium.googlesource.com/external/w3c/web-platform-test
s.git' | 24 WPT_REPO_URL = 'https://chromium.googlesource.com/external/w3c/web-platform-test
s.git' |
| 24 CSS_REPO_URL = 'https://chromium.googlesource.com/external/w3c/csswg-test.git' | 25 CSS_REPO_URL = 'https://chromium.googlesource.com/external/w3c/csswg-test.git' |
| 25 | 26 |
| 26 POLL_DELAY_SECONDS = 900 | 27 POLL_DELAY_SECONDS = 900 |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 previous_baselines = self.fs.files_under(dest_path, file_filter=self.is_
baseline) | 182 previous_baselines = self.fs.files_under(dest_path, file_filter=self.is_
baseline) |
| 182 for subpath in previous_baselines: | 183 for subpath in previous_baselines: |
| 183 full_path = self.fs.join(dest_path, subpath) | 184 full_path = self.fs.join(dest_path, subpath) |
| 184 if self.fs.glob(full_path.replace('-expected.txt', '*')) == [full_pa
th]: | 185 if self.fs.glob(full_path.replace('-expected.txt', '*')) == [full_pa
th]: |
| 185 self.fs.remove(full_path) | 186 self.fs.remove(full_path) |
| 186 | 187 |
| 187 if not keep_w3c_repos_around: | 188 if not keep_w3c_repos_around: |
| 188 self.print_('## Deleting temp repo directory %s.' % temp_repo_path) | 189 self.print_('## Deleting temp repo directory %s.' % temp_repo_path) |
| 189 self.rmtree(temp_repo_path) | 190 self.rmtree(temp_repo_path) |
| 190 | 191 |
| 192 self.print_('## Updating TestExpectations for any removed or renamed tes
ts.') |
| 193 self.update_test_expectations(self._list_deleted_tests(), self._list_ren
amed_tests()) |
| 194 |
| 191 return '%s@%s' % (dest_dir_name, master_commitish) | 195 return '%s@%s' % (dest_dir_name, master_commitish) |
| 192 | 196 |
| 193 def commit_changes_if_needed(self, chromium_commitish, import_commitish): | 197 def commit_changes_if_needed(self, chromium_commitish, import_commitish): |
| 194 if self.run(['git', 'diff', '--quiet', 'HEAD'], exit_on_failure=False)[0
]: | 198 if self.run(['git', 'diff', '--quiet', 'HEAD'], exit_on_failure=False)[0
]: |
| 195 self.print_('## Committing changes.') | 199 self.print_('## Committing changes.') |
| 196 commit_msg = ('Import %s\n' | 200 commit_msg = ('Import %s\n' |
| 197 '\n' | 201 '\n' |
| 198 'Using update-w3c-deps in Chromium %s.\n' | 202 'Using update-w3c-deps in Chromium %s.\n' |
| 199 % (import_commitish, chromium_commitish)) | 203 % (import_commitish, chromium_commitish)) |
| 200 path_to_commit_msg = self.path_from_webkit_base('commit_msg') | 204 path_to_commit_msg = self.path_from_webkit_base('commit_msg') |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 296 | 300 |
| 297 # First try: if there are failures, update expectations. | 301 # First try: if there are failures, update expectations. |
| 298 self.print_('## Triggering try jobs.') | 302 self.print_('## Triggering try jobs.') |
| 299 for try_bot in self.host.builders.all_try_builder_names(): | 303 for try_bot in self.host.builders.all_try_builder_names(): |
| 300 self.git_cl.run(['try', '-b', try_bot]) | 304 self.git_cl.run(['try', '-b', try_bot]) |
| 301 try_results = self.git_cl.wait_for_try_jobs() | 305 try_results = self.git_cl.wait_for_try_jobs() |
| 302 if not try_results: | 306 if not try_results: |
| 303 self.print_('## Timed out waiting for try results.') | 307 self.print_('## Timed out waiting for try results.') |
| 304 return | 308 return |
| 305 if try_results and self.git_cl.has_failing_try_results(try_results): | 309 if try_results and self.git_cl.has_failing_try_results(try_results): |
| 306 self.write_test_expectations() | 310 self.fetch_new_expectations_and_baselines() |
| 307 | 311 |
| 308 # Second try: if there are failures, then abort. | 312 # Second try: if there are failures, then abort. |
| 309 self.git_cl.run(['set-commit', '--rietveld']) | 313 self.git_cl.run(['set-commit', '--rietveld']) |
| 310 try_results = self.git_cl.wait_for_try_jobs() | 314 try_results = self.git_cl.wait_for_try_jobs() |
| 311 if not try_results: | 315 if not try_results: |
| 312 self.print_('Timed out waiting for try results.') | 316 self.print_('Timed out waiting for try results.') |
| 313 self.git_cl.run(['set-close']) | 317 self.git_cl.run(['set-close']) |
| 314 return False | 318 return False |
| 315 if self.git_cl.has_failing_try_results(try_results): | 319 if self.git_cl.has_failing_try_results(try_results): |
| 316 self.print_('CQ failed; aborting.') | 320 self.print_('CQ failed; aborting.') |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 | 357 |
| 354 def generate_email_list(self, changed_files, directory_to_owner): | 358 def generate_email_list(self, changed_files, directory_to_owner): |
| 355 """Returns a list of email addresses based on the given file list and | 359 """Returns a list of email addresses based on the given file list and |
| 356 directory-to-owner mapping. | 360 directory-to-owner mapping. |
| 357 | 361 |
| 358 Args: | 362 Args: |
| 359 changed_files: A list of file paths relative to the repository root. | 363 changed_files: A list of file paths relative to the repository root. |
| 360 directory_to_owner: A dict mapping layout test directories to emails
. | 364 directory_to_owner: A dict mapping layout test directories to emails
. |
| 361 | 365 |
| 362 Returns: | 366 Returns: |
| 363 A list of the email addresses to be notified for the current | 367 A list of the email addresses to be notified for the current import. |
| 364 import. | |
| 365 """ | 368 """ |
| 366 email_addresses = set() | 369 email_addresses = set() |
| 367 for file_path in changed_files: | 370 for file_path in changed_files: |
| 368 test_path = self.finder.layout_test_name(file_path) | 371 test_path = self.finder.layout_test_name(file_path) |
| 369 if test_path is None: | 372 if test_path is None: |
| 370 continue | 373 continue |
| 371 test_dir = self.fs.dirname(test_path) | 374 test_dir = self.fs.dirname(test_path) |
| 372 if test_dir in directory_to_owner: | 375 if test_dir in directory_to_owner: |
| 373 email_addresses.add(directory_to_owner[test_dir]) | 376 email_addresses.add(directory_to_owner[test_dir]) |
| 374 return sorted(email_addresses) | 377 return sorted(email_addresses) |
| 375 | 378 |
| 376 def write_test_expectations(self): | 379 def fetch_new_expectations_and_baselines(self): |
| 380 """Adds new expectations and downloads baselines based on try job result
s, then commits and uploads the change.""" |
| 377 self.print_('## Adding test expectations lines to LayoutTests/TestExpect
ations.') | 381 self.print_('## Adding test expectations lines to LayoutTests/TestExpect
ations.') |
| 378 script_path = self.path_from_webkit_base('Tools', 'Scripts', 'update-w3c
-test-expectations') | 382 script_path = self.path_from_webkit_base('Tools', 'Scripts', 'update-w3c
-test-expectations') |
| 379 self.run([self.host.executable, script_path, '--verbose']) | 383 self.run([self.host.executable, script_path, '--verbose']) |
| 380 message = 'Modify TestExpectations or download new baselines for tests.' | 384 message = 'Modify TestExpectations or download new baselines for tests.' |
| 381 self.check_run(['git', 'commit', '-a', '-m', message]) | 385 self.check_run(['git', 'commit', '-a', '-m', message]) |
| 382 self.git_cl.run(['upload', '-m', message, '--rietveld']) | 386 self.git_cl.run(['upload', '-m', message, '--rietveld']) |
| 387 |
| 388 def update_test_expectations(self, deleted_tests, renamed_tests): |
| 389 """Updates the TestExpectations file entries for tests that have been de
leted or renamed.""" |
| 390 port = self.host.port_factory.get() |
| 391 test_expectations = TestExpectations(port, include_overrides=False) |
| 392 # Tests for which files don't exist aren't stored in TestExpectationsMod
el, |
| 393 # so methods like TestExpectations.remove_expectation_line don't work; i
nstead |
| 394 # we can run through the TestExpectationLine objects that were parsed. |
| 395 # FIXME: This won't work for removed or renamed directories with test ex
pectations |
| 396 # that are directories rather than individual tests. |
| 397 new_lines = [] |
| 398 changed_lines = [] |
| 399 for expectation_line in test_expectations.expectations(): |
| 400 if expectation_line.name in deleted_tests: |
| 401 continue |
| 402 if expectation_line.name in renamed_tests: |
| 403 expectation_line.name = renamed_tests[expectation_line.name] |
| 404 # Upon parsing the file, a "path does not exist" warning is expe
cted |
| 405 # to be there for tests that have been renamed, and if there are
warnings, |
| 406 # then the original string is used. If the warnings are reset, t
hen the |
| 407 # expectation line is re-serialized when output. |
| 408 expectation_line.warnings = [] |
| 409 changed_lines.append(expectation_line) |
| 410 new_lines.append(expectation_line) |
| 411 self.host.filesystem.write_text_file( |
| 412 port.path_to_generic_test_expectations_file(), |
| 413 TestExpectations.list_to_string(new_lines, reconstitute_only_these=c
hanged_lines)) |
| 414 |
| 415 def _list_deleted_tests(self): |
| 416 """Returns a list of layout tests that have been deleted.""" |
| 417 out = self.check_run(['git', 'diff', 'origin/master', '--diff-filter=D',
'--name-only']) |
| 418 deleted_tests = [] |
| 419 for line in out.splitlines(): |
| 420 test = self.finder.layout_test_name(line) |
| 421 if test: |
| 422 deleted_tests.append(test) |
| 423 return deleted_tests |
| 424 |
| 425 def _list_renamed_tests(self): |
| 426 """Returns a dict mapping source to dest name for layout tests that have
been renamed.""" |
| 427 out = self.check_run(['git', 'diff', 'origin/master', '--diff-filter=R',
'--name-status']) |
| 428 renamed_tests = {} |
| 429 for line in out.splitlines(): |
| 430 _, source_path, dest_path = line.split() |
| 431 source_test = self.finder.layout_test_name(source_path) |
| 432 dest_test = self.finder.layout_test_name(dest_path) |
| 433 if source_test and dest_test: |
| 434 renamed_tests[source_test] = dest_test |
| 435 return renamed_tests |
| OLD | NEW |