Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 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 import os as _os | 7 import os as _os |
| 8 _HERE = _os.path.dirname(_os.path.abspath(__file__)) | 8 _HERE = _os.path.dirname(_os.path.abspath(__file__)) |
| 9 | 9 |
| 10 | 10 |
| (...skipping 724 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 735 out.append('%s has %d build(s) pending' % | 735 out.append('%s has %d build(s) pending' % |
| 736 (builder_name, pending_builds_len)) | 736 (builder_name, pending_builds_len)) |
| 737 if out: | 737 if out: |
| 738 return [output_api.PresubmitPromptWarning( | 738 return [output_api.PresubmitPromptWarning( |
| 739 'Build(s) pending. It is suggested to wait that no more than %d ' | 739 'Build(s) pending. It is suggested to wait that no more than %d ' |
| 740 'builds are pending.' % max_pendings, | 740 'builds are pending.' % max_pendings, |
| 741 long_text='\n'.join(out))] | 741 long_text='\n'.join(out))] |
| 742 return [] | 742 return [] |
| 743 | 743 |
| 744 | 744 |
| 745 def CheckOwners(input_api, output_api, source_file_filter=None): | 745 def CheckOwners(input_api, output_api, source_file_filter=None, |
| 746 issue_props=None): | |
|
M-A Ruel
2012/11/28 02:43:49
Can you rebase on ToT and remove this argument now
Isaac (away)
2012/11/28 22:28:17
done.
| |
| 746 if input_api.is_committing: | 747 if input_api.is_committing: |
| 747 if input_api.tbr: | 748 if input_api.tbr: |
| 748 return [output_api.PresubmitNotifyResult( | 749 return [output_api.PresubmitNotifyResult( |
| 749 '--tbr was specified, skipping OWNERS check')] | 750 '--tbr was specified, skipping OWNERS check')] |
| 750 if not input_api.change.issue: | 751 if not input_api.change.issue: |
| 751 return [output_api.PresubmitError("OWNERS check failed: this change has " | 752 return [output_api.PresubmitError("OWNERS check failed: this change has " |
| 752 "no Rietveld issue number, so we can't check it for approvals.")] | 753 "no Rietveld issue number, so we can't check it for approvals.")] |
| 753 needed = 'LGTM from an OWNER' | 754 needed = 'LGTM from an OWNER' |
| 754 output = output_api.PresubmitError | 755 output = output_api.PresubmitError |
| 755 else: | 756 else: |
| 756 needed = 'OWNER reviewers' | 757 needed = 'OWNER reviewers' |
| 757 output = output_api.PresubmitNotifyResult | 758 output = output_api.PresubmitNotifyResult |
| 758 | 759 |
| 759 affected_files = set([f.LocalPath() for f in | 760 affected_files = set([f.LocalPath() for f in |
| 760 input_api.change.AffectedFiles(file_filter=source_file_filter)]) | 761 input_api.change.AffectedFiles(file_filter=source_file_filter)]) |
| 761 | 762 |
| 762 owners_db = input_api.owners_db | 763 owners_db = input_api.owners_db |
| 764 issue_props = issue_props or _GetRietveldIssueProps(input_api, True) | |
| 763 owner_email, reviewers = _RietveldOwnerAndReviewers( | 765 owner_email, reviewers = _RietveldOwnerAndReviewers( |
| 764 input_api, | 766 issue_props, |
| 765 owners_db.email_regexp, | 767 owners_db.email_regexp, |
| 766 approval_needed=input_api.is_committing) | 768 approval_needed=input_api.is_committing) |
| 767 | 769 |
| 768 if owner_email: | 770 if owner_email: |
| 769 message = '' | 771 message = '' |
| 770 reviewers_plus_owner = reviewers.union(set([owner_email])) | 772 reviewers_plus_owner = reviewers.union(set([owner_email])) |
| 771 else: | 773 else: |
| 772 message = ('\nUntil the issue is uploaded, this list will include ' | 774 message = ('\nUntil the issue is uploaded, this list will include ' |
| 773 'directories for which you \nare an OWNER.') | 775 'directories for which you \nare an OWNER.') |
| 774 owner_email = '' | 776 owner_email = '' |
| 775 reviewers_plus_owner = set() | 777 reviewers_plus_owner = set() |
| 776 | 778 |
| 777 missing_directories = owners_db.directories_not_covered_by(affected_files, | 779 missing_directories = owners_db.directories_not_covered_by(affected_files, |
| 778 reviewers_plus_owner) | 780 reviewers_plus_owner) |
| 779 if missing_directories: | 781 if missing_directories: |
| 780 output_list = [ | 782 output_list = [ |
| 781 output('Missing %s for files in these directories:\n %s%s' % | 783 output('Missing %s for files in these directories:\n %s%s' % |
| 782 (needed, '\n '.join(missing_directories), message))] | 784 (needed, '\n '.join(missing_directories), message))] |
| 783 if not input_api.is_committing: | 785 if not input_api.is_committing: |
| 784 suggested_owners = owners_db.reviewers_for(affected_files) | 786 suggested_owners = owners_db.reviewers_for(affected_files) |
| 785 output_list.append(output('Suggested OWNERS:\n %s' % | 787 output_list.append(output('Suggested OWNERS:\n %s' % |
| 786 ('\n '.join(suggested_owners)))) | 788 ('\n '.join(suggested_owners)))) |
| 787 return output_list | 789 return output_list |
| 788 | 790 |
| 789 if input_api.is_committing and not reviewers: | 791 if input_api.is_committing and not reviewers: |
| 790 return [output('Missing LGTM from someone other than %s' % owner_email)] | 792 return [output('Missing LGTM from someone other than %s' % owner_email)] |
| 791 return [] | 793 return [] |
| 792 | 794 |
| 793 | 795 |
| 794 def _RietveldOwnerAndReviewers(input_api, email_regexp, approval_needed=False): | 796 def _GetRietveldIssueProps(input_api, messages): |
| 797 """Gets the issue properties from rietveld.""" | |
| 798 issue = input_api.change.issue | |
| 799 if issue and input_api.rietveld: | |
| 800 return input_api.rietveld.get_issue_properties( | |
| 801 issue=issue, messages=messages) | |
| 802 | |
| 803 | |
| 804 def CheckIssueNotClosed(issue_props, output_api): | |
| 805 """Verify issue is not closed. | |
| 806 | |
| 807 We should not be working with a closed review. CQ and dcommit set this bit, | |
| 808 so it is a pretty good indicator of whether an issue has been committed. | |
| 809 """ | |
| 810 if issue_props['closed']: | |
| 811 return [output_api.PresubmitError( | |
| 812 'Issue %s is closed. If this issue was already used for a commit,\n' | |
| 813 'please reset the issue number associated with this branch with:\n' | |
| 814 'git cl issue 0\n' % issue_props['issue'] | |
| 815 )] | |
| 816 return [] | |
| 817 | |
| 818 | |
| 819 def _RietveldOwnerAndReviewers(issue_props, email_regexp, | |
| 820 approval_needed=False): | |
| 795 """Return the owner and reviewers of a change, if any. | 821 """Return the owner and reviewers of a change, if any. |
| 796 | 822 |
| 797 If approval_needed is True, only reviewers who have approved the change | 823 If approval_needed is True, only reviewers who have approved the change |
| 798 will be returned. | 824 will be returned. |
| 799 """ | 825 """ |
| 800 if not input_api.change.issue: | 826 if not issue_props: |
| 801 return None, None | 827 return None, None |
| 802 | 828 |
| 803 issue_props = input_api.rietveld.get_issue_properties( | |
| 804 int(input_api.change.issue), True) | |
| 805 if not approval_needed: | 829 if not approval_needed: |
| 806 return issue_props['owner_email'], set(issue_props['reviewers']) | 830 return issue_props['owner_email'], set(issue_props['reviewers']) |
| 807 | 831 |
| 808 owner_email = issue_props['owner_email'] | 832 owner_email = issue_props['owner_email'] |
| 809 | 833 |
| 810 def match_reviewer(r): | 834 def match_reviewer(r): |
| 811 return email_regexp.match(r) and r != owner_email | 835 return email_regexp.match(r) and r != owner_email |
| 812 | 836 |
| 813 messages = issue_props.get('messages', []) | 837 messages = issue_props.get('messages', []) |
| 814 approvers = set( | 838 approvers = set( |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 928 snapshot_memory = [] | 952 snapshot_memory = [] |
| 929 def snapshot(msg): | 953 def snapshot(msg): |
| 930 """Measures & prints performance warning if a rule is running slow.""" | 954 """Measures & prints performance warning if a rule is running slow.""" |
| 931 dt2 = input_api.time.clock() | 955 dt2 = input_api.time.clock() |
| 932 if snapshot_memory: | 956 if snapshot_memory: |
| 933 delta_ms = int(1000*(dt2 - snapshot_memory[0])) | 957 delta_ms = int(1000*(dt2 - snapshot_memory[0])) |
| 934 if delta_ms > 500: | 958 if delta_ms > 500: |
| 935 print " %s took a long time: %dms" % (snapshot_memory[1], delta_ms) | 959 print " %s took a long time: %dms" % (snapshot_memory[1], delta_ms) |
| 936 snapshot_memory[:] = (dt2, msg) | 960 snapshot_memory[:] = (dt2, msg) |
| 937 | 961 |
| 962 issue_props = _GetRietveldIssueProps(input_api, messages=True) | |
| 938 if owners_check: | 963 if owners_check: |
| 939 snapshot("checking owners") | 964 snapshot("checking owners") |
| 940 results.extend(input_api.canned_checks.CheckOwners( | 965 results.extend(input_api.canned_checks.CheckOwners( |
| 941 input_api, output_api, source_file_filter=None)) | 966 input_api=input_api, |
| 967 output_api=output_api, | |
| 968 source_file_filter=None, | |
| 969 issue_props=issue_props)) | |
| 970 | |
| 971 if issue_props: | |
| 972 snapshot("checking review not closed") | |
| 973 results.extend(input_api.canned_checks.CheckIssueNotClosed( | |
| 974 issue_props, output_api)) | |
| 942 | 975 |
| 943 snapshot("checking long lines") | 976 snapshot("checking long lines") |
| 944 results.extend(input_api.canned_checks.CheckLongLines( | 977 results.extend(input_api.canned_checks.CheckLongLines( |
| 945 input_api, output_api, source_file_filter=sources)) | 978 input_api, output_api, source_file_filter=sources)) |
| 946 snapshot( "checking tabs") | 979 snapshot( "checking tabs") |
| 947 results.extend(input_api.canned_checks.CheckChangeHasNoTabs( | 980 results.extend(input_api.canned_checks.CheckChangeHasNoTabs( |
| 948 input_api, output_api, source_file_filter=sources)) | 981 input_api, output_api, source_file_filter=sources)) |
| 949 snapshot( "checking stray whitespace") | 982 snapshot( "checking stray whitespace") |
| 950 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace( | 983 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace( |
| 951 input_api, output_api, source_file_filter=sources)) | 984 input_api, output_api, source_file_filter=sources)) |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 966 results.extend(input_api.canned_checks.CheckSvnForCommonMimeTypes( | 999 results.extend(input_api.canned_checks.CheckSvnForCommonMimeTypes( |
| 967 input_api, output_api)) | 1000 input_api, output_api)) |
| 968 snapshot("checking license") | 1001 snapshot("checking license") |
| 969 results.extend(input_api.canned_checks.CheckLicense( | 1002 results.extend(input_api.canned_checks.CheckLicense( |
| 970 input_api, output_api, license_header, source_file_filter=sources)) | 1003 input_api, output_api, license_header, source_file_filter=sources)) |
| 971 snapshot("checking was uploaded") | 1004 snapshot("checking was uploaded") |
| 972 results.extend(input_api.canned_checks.CheckChangeWasUploaded( | 1005 results.extend(input_api.canned_checks.CheckChangeWasUploaded( |
| 973 input_api, output_api)) | 1006 input_api, output_api)) |
| 974 snapshot("done") | 1007 snapshot("done") |
| 975 return results | 1008 return results |
| OLD | NEW |