| 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: | 7 If this script is given the argument --auto-update, it will also: |
| 8 1. Upload a CL. | 8 1. Upload a CL. |
| 9 2. Trigger try jobs and wait for them to complete. | 9 2. Trigger try jobs and wait for them to complete. |
| 10 3. Make any changes that are required for new failing tests. | 10 3. Make any changes that are required for new failing tests. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 | 48 |
| 49 def main(self, argv=None): | 49 def main(self, argv=None): |
| 50 options = self.parse_args(argv) | 50 options = self.parse_args(argv) |
| 51 self.verbose = options.verbose | 51 self.verbose = options.verbose |
| 52 log_level = logging.DEBUG if self.verbose else logging.INFO | 52 log_level = logging.DEBUG if self.verbose else logging.INFO |
| 53 logging.basicConfig(level=log_level, format='%(message)s') | 53 logging.basicConfig(level=log_level, format='%(message)s') |
| 54 | 54 |
| 55 if not self.checkout_is_okay(options.allow_local_commits): | 55 if not self.checkout_is_okay(options.allow_local_commits): |
| 56 return 1 | 56 return 1 |
| 57 | 57 |
| 58 self.git_cl = GitCL(self.host, auth_refresh_token_json=options.auth_refr
esh_token_json) | 58 self.git_cl = GitCL(self.host) |
| 59 | 59 |
| 60 _log.debug('Noting the current Chromium commit.') | 60 _log.debug('Noting the current Chromium commit.') |
| 61 _, show_ref_output = self.run(['git', 'show-ref', 'HEAD']) | 61 _, show_ref_output = self.run(['git', 'show-ref', 'HEAD']) |
| 62 chromium_commit = show_ref_output.split()[0] | 62 chromium_commit = show_ref_output.split()[0] |
| 63 | 63 |
| 64 assert options.target in ('wpt', 'css') | 64 assert options.target in ('wpt', 'css') |
| 65 dest_dir_name = WPT_DEST_NAME | 65 dest_dir_name = WPT_DEST_NAME |
| 66 repo_url = WPT_REPO_URL | 66 repo_url = WPT_REPO_URL |
| 67 if options.target != 'wpt': | 67 if options.target != 'wpt': |
| 68 dest_dir_name = CSS_DEST_NAME | 68 dest_dir_name = CSS_DEST_NAME |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 help='log what we are doing') | 117 help='log what we are doing') |
| 118 parser.add_argument('--allow-local-commits', action='store_true', | 118 parser.add_argument('--allow-local-commits', action='store_true', |
| 119 help='allow script to run even if we have local comm
its') | 119 help='allow script to run even if we have local comm
its') |
| 120 parser.add_argument('-r', dest='revision', action='store', | 120 parser.add_argument('-r', dest='revision', action='store', |
| 121 help='Target revision.') | 121 help='Target revision.') |
| 122 parser.add_argument('target', choices=['css', 'wpt'], | 122 parser.add_argument('target', choices=['css', 'wpt'], |
| 123 help='Target repository. "css" for csswg-test, "wpt
" for web-platform-tests.') | 123 help='Target repository. "css" for csswg-test, "wpt
" for web-platform-tests.') |
| 124 parser.add_argument('--auto-update', action='store_true', | 124 parser.add_argument('--auto-update', action='store_true', |
| 125 help='uploads CL and initiates commit queue.') | 125 help='uploads CL and initiates commit queue.') |
| 126 parser.add_argument('--auth-refresh-token-json', | 126 parser.add_argument('--auth-refresh-token-json', |
| 127 help='Rietveld auth refresh JSON token.') | 127 help='Auth refresh JSON token (ignored, deprecated)'
) |
| 128 parser.add_argument('--ignore-exportable-commits', action='store_true', | 128 parser.add_argument('--ignore-exportable-commits', action='store_true', |
| 129 help='Continue even if there are exportable commits
that may be overwritten.') | 129 help='Continue even if there are exportable commits
that may be overwritten.') |
| 130 return parser.parse_args(argv) | 130 return parser.parse_args(argv) |
| 131 | 131 |
| 132 def checkout_is_okay(self, allow_local_commits): | 132 def checkout_is_okay(self, allow_local_commits): |
| 133 git_diff_retcode, _ = self.run(['git', 'diff', '--quiet', 'HEAD'], exit_
on_failure=False) | 133 git_diff_retcode, _ = self.run(['git', 'diff', '--quiet', 'HEAD'], exit_
on_failure=False) |
| 134 if git_diff_retcode: | 134 if git_diff_retcode: |
| 135 _log.warning('Checkout is dirty; aborting.') | 135 _log.warning('Checkout is dirty; aborting.') |
| 136 return False | 136 return False |
| 137 | 137 |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 337 poll_delay_seconds=POLL_DELAY_SECONDS, timeout_seconds=TIMEOUT_SECON
DS) | 337 poll_delay_seconds=POLL_DELAY_SECONDS, timeout_seconds=TIMEOUT_SECON
DS) |
| 338 | 338 |
| 339 if not try_results: | 339 if not try_results: |
| 340 self.git_cl.run(['set-close']) | 340 self.git_cl.run(['set-close']) |
| 341 return False | 341 return False |
| 342 | 342 |
| 343 if try_results and self.git_cl.has_failing_try_results(try_results): | 343 if try_results and self.git_cl.has_failing_try_results(try_results): |
| 344 self.fetch_new_expectations_and_baselines() | 344 self.fetch_new_expectations_and_baselines() |
| 345 | 345 |
| 346 # Trigger CQ and wait for CQ try jobs to finish. | 346 # Trigger CQ and wait for CQ try jobs to finish. |
| 347 self.git_cl.run(['set-commit', '--rietveld']) | 347 self.git_cl.run(['set-commit', '--gerrit']) |
| 348 try_results = self.git_cl.wait_for_try_jobs( | 348 try_results = self.git_cl.wait_for_try_jobs( |
| 349 poll_delay_seconds=POLL_DELAY_SECONDS, timeout_seconds=TIMEOUT_SECON
DS) | 349 poll_delay_seconds=POLL_DELAY_SECONDS, timeout_seconds=TIMEOUT_SECON
DS) |
| 350 | 350 |
| 351 if not try_results: | 351 if not try_results: |
| 352 _log.error('No try job results.') | 352 _log.error('No try job results.') |
| 353 self.git_cl.run(['set-close']) | 353 self.git_cl.run(['set-close']) |
| 354 return False | 354 return False |
| 355 | 355 |
| 356 # If the CQ passes, then the issue will be closed. | 356 # If the CQ passes, then the issue will be closed. |
| 357 status = self.git_cl.run(['status' '--field', 'status']).strip() | 357 status = self.git_cl.run(['status' '--field', 'status']).strip() |
| 358 _log.info('CL status: "%s"', status) | 358 _log.info('CL status: "%s"', status) |
| 359 if status not in ('lgtm', 'closed'): | 359 if status not in ('lgtm', 'closed'): |
| 360 _log.error('CQ appears to have failed; aborting.') | 360 _log.error('CQ appears to have failed; aborting.') |
| 361 self.git_cl.run(['set-close']) | 361 self.git_cl.run(['set-close']) |
| 362 return False | 362 return False |
| 363 | 363 |
| 364 _log.info('Update completed.') | 364 _log.info('Update completed.') |
| 365 return True | 365 return True |
| 366 | 366 |
| 367 def _upload_cl(self): | 367 def _upload_cl(self): |
| 368 _log.info('Uploading change list.') | 368 _log.info('Uploading change list.') |
| 369 directory_owners = self.get_directory_owners() | 369 directory_owners = self.get_directory_owners() |
| 370 description = self._cl_description(directory_owners) | 370 description = self._cl_description(directory_owners) |
| 371 self.git_cl.run([ | 371 self.git_cl.run([ |
| 372 'upload', | 372 'upload', |
| 373 '-f', | 373 '-f', |
| 374 '--rietveld', | 374 '--gerrit', |
| 375 '-m', | 375 '-m', |
| 376 description, | 376 description, |
| 377 ] + ['--cc=' + email_address for email_address in directory_owners]) | 377 ] + ['--cc=' + email_address for email_address in directory_owners]) |
| 378 | 378 |
| 379 def get_directory_owners(self): | 379 def get_directory_owners(self): |
| 380 """Returns a list of email addresses of owners of changed tests.""" | 380 """Returns a list of email addresses of owners of changed tests.""" |
| 381 _log.info('Gathering directory owners emails to CC.') | 381 _log.info('Gathering directory owners emails to CC.') |
| 382 changed_files = self.host.git().changed_files() | 382 changed_files = self.host.git().changed_files() |
| 383 extractor = DirectoryOwnersExtractor(self.fs) | 383 extractor = DirectoryOwnersExtractor(self.fs) |
| 384 extractor.read_owner_map() | 384 extractor.read_owner_map() |
| (...skipping 23 matching lines...) Expand all Loading... |
| 408 message_lines.extend([' ' + d for d in directories]) | 408 message_lines.extend([' ' + d for d in directories]) |
| 409 return '\n'.join(message_lines) | 409 return '\n'.join(message_lines) |
| 410 | 410 |
| 411 def fetch_new_expectations_and_baselines(self): | 411 def fetch_new_expectations_and_baselines(self): |
| 412 """Adds new expectations and downloads baselines based on try job result
s, then commits and uploads the change.""" | 412 """Adds new expectations and downloads baselines based on try job result
s, then commits and uploads the change.""" |
| 413 _log.info('Adding test expectations lines to LayoutTests/TestExpectation
s.') | 413 _log.info('Adding test expectations lines to LayoutTests/TestExpectation
s.') |
| 414 expectation_updater = WPTExpectationsUpdater(self.host) | 414 expectation_updater = WPTExpectationsUpdater(self.host) |
| 415 expectation_updater.run(args=[]) | 415 expectation_updater.run(args=[]) |
| 416 message = 'Update test expectations and baselines.' | 416 message = 'Update test expectations and baselines.' |
| 417 self.check_run(['git', 'commit', '-a', '-m', message]) | 417 self.check_run(['git', 'commit', '-a', '-m', message]) |
| 418 self.git_cl.run(['upload', '-m', message, '--rietveld']) | 418 self.git_cl.run(['upload', '-m', message, '--gerrit']) |
| 419 | 419 |
| 420 def update_all_test_expectations_files(self, deleted_tests, renamed_tests): | 420 def update_all_test_expectations_files(self, deleted_tests, renamed_tests): |
| 421 """Updates all test expectations files for tests that have been deleted
or renamed.""" | 421 """Updates all test expectations files for tests that have been deleted
or renamed.""" |
| 422 port = self.host.port_factory.get() | 422 port = self.host.port_factory.get() |
| 423 for path, file_contents in port.all_expectations_dict().iteritems(): | 423 for path, file_contents in port.all_expectations_dict().iteritems(): |
| 424 parser = TestExpectationParser(port, all_tests=None, is_lint_mode=Fa
lse) | 424 parser = TestExpectationParser(port, all_tests=None, is_lint_mode=Fa
lse) |
| 425 expectation_lines = parser.parse(path, file_contents) | 425 expectation_lines = parser.parse(path, file_contents) |
| 426 self._update_single_test_expectations_file(path, expectation_lines,
deleted_tests, renamed_tests) | 426 self._update_single_test_expectations_file(path, expectation_lines,
deleted_tests, renamed_tests) |
| 427 | 427 |
| 428 def _update_single_test_expectations_file(self, path, expectation_lines, del
eted_tests, renamed_tests): | 428 def _update_single_test_expectations_file(self, path, expectation_lines, del
eted_tests, renamed_tests): |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 """Returns a dict mapping source to dest name for layout tests that have
been renamed.""" | 460 """Returns a dict mapping source to dest name for layout tests that have
been renamed.""" |
| 461 out = self.check_run(['git', 'diff', 'origin/master', '-M100%', '--diff-
filter=R', '--name-status']) | 461 out = self.check_run(['git', 'diff', 'origin/master', '-M100%', '--diff-
filter=R', '--name-status']) |
| 462 renamed_tests = {} | 462 renamed_tests = {} |
| 463 for line in out.splitlines(): | 463 for line in out.splitlines(): |
| 464 _, source_path, dest_path = line.split() | 464 _, source_path, dest_path = line.split() |
| 465 source_test = self.finder.layout_test_name(source_path) | 465 source_test = self.finder.layout_test_name(source_path) |
| 466 dest_test = self.finder.layout_test_name(dest_path) | 466 dest_test = self.finder.layout_test_name(dest_path) |
| 467 if source_test and dest_test: | 467 if source_test and dest_test: |
| 468 renamed_tests[source_test] = dest_test | 468 renamed_tests[source_test] = dest_test |
| 469 return renamed_tests | 469 return renamed_tests |
| OLD | NEW |