OLD | NEW |
1 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2010 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 """Generic presubmit checks that can be reused by other presubmit checks.""" | 5 """Generic presubmit checks that can be reused by other presubmit checks.""" |
6 | 6 |
7 ### Description checks | 7 ### Description checks |
8 | 8 |
9 def CheckChangeHasTestField(input_api, output_api): | 9 def CheckChangeHasTestField(input_api, output_api): |
10 """Requires that the changelist have a TEST= field.""" | 10 """Requires that the changelist have a TEST= field.""" |
(...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 # Discard the output if returncode == 0 | 443 # Discard the output if returncode == 0 |
444 if subproc.returncode: | 444 if subproc.returncode: |
445 outputs.append('Test \'%s\' failed with code %d\n%s\n%s\n' % ( | 445 outputs.append('Test \'%s\' failed with code %d\n%s\n%s\n' % ( |
446 unit_test_name, subproc.returncode, stdoutdata, stderrdata)) | 446 unit_test_name, subproc.returncode, stdoutdata, stderrdata)) |
447 if outputs: | 447 if outputs: |
448 return [message_type('%d unit tests failed.' % len(outputs), | 448 return [message_type('%d unit tests failed.' % len(outputs), |
449 long_text='\n'.join(outputs))] | 449 long_text='\n'.join(outputs))] |
450 return [] | 450 return [] |
451 | 451 |
452 | 452 |
| 453 def _FetchAllFiles(input_api, white_list, black_list): |
| 454 """Hack to fetch all files.""" |
| 455 # We cannot use AffectedFiles here because we want to test every python |
| 456 # file on each single python change. It's because a change in a python file |
| 457 # can break another unmodified file. |
| 458 # Use code similar to InputApi.FilterSourceFile() |
| 459 def Find(filepath, filters): |
| 460 for item in filters: |
| 461 if input_api.re.match(item, filepath): |
| 462 return True |
| 463 return False |
| 464 |
| 465 import os |
| 466 files = [] |
| 467 path_len = len(input_api.PresubmitLocalPath()) |
| 468 for dirpath, dirnames, filenames in os.walk(input_api.PresubmitLocalPath()): |
| 469 # Passes dirnames in black list to speed up search. |
| 470 for item in dirnames[:]: |
| 471 filepath = input_api.os_path.join(dirpath, item)[path_len + 1:] |
| 472 if Find(filepath, black_list): |
| 473 dirnames.remove(item) |
| 474 for item in filenames: |
| 475 filepath = input_api.os_path.join(dirpath, item)[path_len + 1:] |
| 476 if Find(filepath, white_list) and not Find(filepath, black_list): |
| 477 files.append(filepath) |
| 478 return files |
| 479 |
| 480 |
453 def RunPylint(input_api, output_api, white_list=None, black_list=None): | 481 def RunPylint(input_api, output_api, white_list=None, black_list=None): |
454 """Run pylint on python files. | 482 """Run pylint on python files. |
455 | 483 |
456 The default white_list enforces looking only a *.py files. | 484 The default white_list enforces looking only a *.py files. |
457 """ | 485 """ |
458 white_list = white_list or ['.*\.py$'] | 486 white_list = white_list or ['.*\.py$'] |
459 black_list = black_list or input_api.DEFAULT_BLACK_LIST | 487 black_list = black_list or input_api.DEFAULT_BLACK_LIST |
460 | 488 |
461 # Only trigger if there is at least one python file affected. | 489 # Only trigger if there is at least one python file affected. |
462 src_filter = lambda x: input_api.FilterSourceFile(x, white_list, black_list) | 490 src_filter = lambda x: input_api.FilterSourceFile(x, white_list, black_list) |
463 if not input_api.AffectedSourceFiles(src_filter): | 491 if not input_api.AffectedSourceFiles(src_filter): |
464 return [] | 492 return [] |
465 | 493 |
466 # On certain pylint/python version combination, running pylint throws a lot of | 494 # On certain pylint/python version combination, running pylint throws a lot of |
467 # warning messages. | 495 # warning messages. |
468 import warnings | 496 import warnings |
469 warnings.filterwarnings('ignore', category=DeprecationWarning) | 497 warnings.filterwarnings('ignore', category=DeprecationWarning) |
470 try: | 498 try: |
471 # We cannot use AffectedFiles here because we want to test every python | 499 files = _FetchAllFiles(input_api, white_list, black_list) |
472 # file on each single python change. It's because a change in a python file | 500 if not files: |
473 # can break another unmodified file. | 501 return [] |
474 # Use code similar to InputApi.FilterSourceFile() | |
475 def Find(filepath, filters): | |
476 for item in filters: | |
477 if input_api.re.match(item, filepath): | |
478 return True | |
479 return False | |
480 | |
481 import os | |
482 files = [] | |
483 for dirpath, dirnames, filenames in os.walk(input_api.PresubmitLocalPath()): | |
484 # Passes dirnames in black list to speed up search. | |
485 for item in dirnames[:]: | |
486 if Find(input_api.os_path.join(dirpath, item), black_list): | |
487 dirnames.remove(item) | |
488 for item in filenames: | |
489 filepath = input_api.os_path.join(dirpath, item) | |
490 if Find(filepath, white_list) and not Find(filepath, black_list): | |
491 files.append(filepath) | |
492 | |
493 # Now that at least one python file was modified and all the python files | 502 # Now that at least one python file was modified and all the python files |
494 # were listed, try to run pylint. | 503 # were listed, try to run pylint. |
495 try: | 504 try: |
496 from pylint import lint | 505 from pylint import lint |
497 result = lint.Run(sorted(files)) | 506 result = lint.Run(sorted(files)) |
498 except SystemExit, e: | 507 except SystemExit, e: |
499 # pylint has the bad habit of calling sys.exit(), trap it here. | 508 # pylint has the bad habit of calling sys.exit(), trap it here. |
500 result = e.code | 509 result = e.code |
501 except ImportError: | 510 except ImportError: |
502 if input_api.platform == 'win32': | 511 if input_api.platform == 'win32': |
503 return [output_api.PresubmitNotifyResult( | 512 return [output_api.PresubmitNotifyResult( |
504 'Warning: Can\'t run pylint because it is not installed. Please ' | 513 'Warning: Can\'t run pylint because it is not installed. Please ' |
505 'install manually\n' | 514 'install manually\n' |
506 'Cannot do static analysis of python files.')] | 515 'Cannot do static analysis of python files.')] |
507 return [output_api.PresubmitError( | 516 return [output_api.PresubmitError( |
508 'Please install pylint with "sudo apt-get install python-setuptools; ' | 517 'Please install pylint with "sudo apt-get install python-setuptools; ' |
509 'sudo easy_install pylint"\n' | 518 'sudo easy_install pylint"\n' |
510 'Cannot do static analysis of python files.')] | 519 'Cannot do static analysis of python files.')] |
511 if result: | 520 if result: |
512 return [output_api.PresubmitPromptWarning('Fix pylint errors first.')] | 521 if input_api.is_committing: |
| 522 error_type = output_api.PresubmitError |
| 523 else: |
| 524 error_type = output_api.PresubmitPromptWarning |
| 525 return [error_type('Fix pylint errors first.')] |
513 return [] | 526 return [] |
514 finally: | 527 finally: |
515 warnings.filterwarnings('default', category=DeprecationWarning) | 528 warnings.filterwarnings('default', category=DeprecationWarning) |
516 | 529 |
517 | 530 |
518 def CheckRietveldTryJobExecution(input_api, output_api, host_url, platforms, | 531 def CheckRietveldTryJobExecution(input_api, output_api, host_url, platforms, |
519 owner): | 532 owner): |
520 if not input_api.is_committing: | 533 if not input_api.is_committing: |
521 return [] | 534 return [] |
522 if not input_api.change.issue or not input_api.change.patchset: | 535 if not input_api.change.issue or not input_api.change.patchset: |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 pending_builds_len = len(builder.get('pending_builds', [])) | 604 pending_builds_len = len(builder.get('pending_builds', [])) |
592 if pending_builds_len > max_pendings: | 605 if pending_builds_len > max_pendings: |
593 out.append('%s has %d build(s) pending' % | 606 out.append('%s has %d build(s) pending' % |
594 (builder_name, pending_builds_len)) | 607 (builder_name, pending_builds_len)) |
595 if out: | 608 if out: |
596 return [output_api.PresubmitPromptWarning( | 609 return [output_api.PresubmitPromptWarning( |
597 'Build(s) pending. It is suggested to wait that no more than %d ' | 610 'Build(s) pending. It is suggested to wait that no more than %d ' |
598 'builds are pending.' % max_pendings, | 611 'builds are pending.' % max_pendings, |
599 long_text='\n'.join(out))] | 612 long_text='\n'.join(out))] |
600 return [] | 613 return [] |
OLD | NEW |