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, issue_props, source_file_filter=None): |
|
M-A Ruel
2012/11/21 20:48:38
https://code.google.com/p/chromium/source/search?q
Isaac (away)
2012/11/22 06:53:15
Changed to be an optional argument and moved to th
| |
| 746 if input_api.is_committing: | 746 if input_api.is_committing: |
| 747 if input_api.tbr: | 747 if input_api.tbr: |
| 748 return [output_api.PresubmitNotifyResult( | 748 return [output_api.PresubmitNotifyResult( |
| 749 '--tbr was specified, skipping OWNERS check')] | 749 '--tbr was specified, skipping OWNERS check')] |
| 750 if not input_api.change.issue: | 750 if not input_api.change.issue: |
| 751 return [output_api.PresubmitError("OWNERS check failed: this change has " | 751 return [output_api.PresubmitError("OWNERS check failed: this change has " |
| 752 "no Rietveld issue number, so we can't check it for approvals.")] | 752 "no Rietveld issue number, so we can't check it for approvals.")] |
| 753 needed = 'LGTM from an OWNER' | 753 needed = 'LGTM from an OWNER' |
| 754 output = output_api.PresubmitError | 754 output = output_api.PresubmitError |
| 755 else: | 755 else: |
| 756 needed = 'OWNER reviewers' | 756 needed = 'OWNER reviewers' |
| 757 output = output_api.PresubmitNotifyResult | 757 output = output_api.PresubmitNotifyResult |
| 758 | 758 |
| 759 affected_files = set([f.LocalPath() for f in | 759 affected_files = set([f.LocalPath() for f in |
| 760 input_api.change.AffectedFiles(file_filter=source_file_filter)]) | 760 input_api.change.AffectedFiles(file_filter=source_file_filter)]) |
| 761 | 761 |
| 762 owners_db = input_api.owners_db | 762 owners_db = input_api.owners_db |
| 763 owner_email, reviewers = _RietveldOwnerAndReviewers( | 763 owner_email, reviewers = _RietveldOwnerAndReviewers( |
| 764 input_api, | 764 issue_props, |
| 765 owners_db.email_regexp, | 765 owners_db.email_regexp, |
| 766 approval_needed=input_api.is_committing) | 766 approval_needed=input_api.is_committing) |
| 767 | 767 |
| 768 if owner_email: | 768 if owner_email: |
| 769 message = '' | 769 message = '' |
| 770 reviewers_plus_owner = reviewers.union(set([owner_email])) | 770 reviewers_plus_owner = reviewers.union(set([owner_email])) |
| 771 else: | 771 else: |
| 772 message = ('\nUntil the issue is uploaded, this list will include ' | 772 message = ('\nUntil the issue is uploaded, this list will include ' |
| 773 'directories for which you \nare an OWNER.') | 773 'directories for which you \nare an OWNER.') |
| 774 owner_email = '' | 774 owner_email = '' |
| 775 reviewers_plus_owner = set() | 775 reviewers_plus_owner = set() |
| 776 | 776 |
| 777 missing_directories = owners_db.directories_not_covered_by(affected_files, | 777 missing_directories = owners_db.directories_not_covered_by(affected_files, |
| 778 reviewers_plus_owner) | 778 reviewers_plus_owner) |
| 779 if missing_directories: | 779 if missing_directories: |
| 780 output_list = [ | 780 output_list = [ |
| 781 output('Missing %s for files in these directories:\n %s%s' % | 781 output('Missing %s for files in these directories:\n %s%s' % |
| 782 (needed, '\n '.join(missing_directories), message))] | 782 (needed, '\n '.join(missing_directories), message))] |
| 783 if not input_api.is_committing: | 783 if not input_api.is_committing: |
| 784 suggested_owners = owners_db.reviewers_for(affected_files) | 784 suggested_owners = owners_db.reviewers_for(affected_files) |
| 785 output_list.append(output('Suggested OWNERS:\n %s' % | 785 output_list.append(output('Suggested OWNERS:\n %s' % |
| 786 ('\n '.join(suggested_owners)))) | 786 ('\n '.join(suggested_owners)))) |
| 787 return output_list | 787 return output_list |
| 788 | 788 |
| 789 if input_api.is_committing and not reviewers: | 789 if input_api.is_committing and not reviewers: |
| 790 return [output('Missing LGTM from someone other than %s' % owner_email)] | 790 return [output('Missing LGTM from someone other than %s' % owner_email)] |
| 791 return [] | 791 return [] |
| 792 | 792 |
| 793 | 793 |
| 794 def _RietveldOwnerAndReviewers(input_api, email_regexp, approval_needed=False): | 794 def _GetRietveldIssueProps(input_api, messages): |
| 795 """Gets the issue properties from rietveld.""" | |
| 796 issue = input_api.change.issue | |
| 797 if issue and input_api.rietveld: | |
| 798 return input_api.rietveld.get_issue_properties( | |
|
M-A Ruel
2012/11/21 20:48:38
BTW, this could be cached in the interface instead
Isaac (away)
2012/11/22 06:53:15
Good idea, but I'd like to punt on that. Also it
| |
| 799 issue=issue, messages=messages) | |
| 800 | |
| 801 | |
| 802 def CheckIssueNotClosed(issue_props, output_api): | |
| 803 """Verify issue is not closed. | |
| 804 | |
| 805 We should not be working with a closed review. CQ and dcommit set this bit, | |
| 806 so it is a pretty good indicator of whether an issue has been committed. | |
| 807 """ | |
| 808 if issue_props['closed']: | |
| 809 return [output_api.PresubmitError( | |
| 810 'Issue %s is closed. If this issue was already used for a commit,\n' | |
| 811 'please reset the issue number associated with this branch with:\n' | |
| 812 'git cl issue 0\n' % issue_props['issue'] | |
| 813 )] | |
| 814 return [] | |
| 815 | |
| 816 | |
| 817 def _RietveldOwnerAndReviewers(issue_props, email_regexp, | |
| 818 approval_needed=False): | |
| 795 """Return the owner and reviewers of a change, if any. | 819 """Return the owner and reviewers of a change, if any. |
| 796 | 820 |
| 797 If approval_needed is True, only reviewers who have approved the change | 821 If approval_needed is True, only reviewers who have approved the change |
| 798 will be returned. | 822 will be returned. |
| 799 """ | 823 """ |
| 800 if not input_api.change.issue: | 824 if not issue_props: |
| 801 return None, None | 825 return None, None |
| 802 | 826 |
| 803 issue_props = input_api.rietveld.get_issue_properties( | |
| 804 int(input_api.change.issue), True) | |
| 805 if not approval_needed: | 827 if not approval_needed: |
| 806 return issue_props['owner_email'], set(issue_props['reviewers']) | 828 return issue_props['owner_email'], set(issue_props['reviewers']) |
| 807 | 829 |
| 808 owner_email = issue_props['owner_email'] | 830 owner_email = issue_props['owner_email'] |
| 809 | 831 |
| 810 def match_reviewer(r): | 832 def match_reviewer(r): |
| 811 return email_regexp.match(r) and r != owner_email | 833 return email_regexp.match(r) and r != owner_email |
| 812 | 834 |
| 813 messages = issue_props.get('messages', []) | 835 messages = issue_props.get('messages', []) |
| 814 approvers = set( | 836 approvers = set( |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 928 snapshot_memory = [] | 950 snapshot_memory = [] |
| 929 def snapshot(msg): | 951 def snapshot(msg): |
| 930 """Measures & prints performance warning if a rule is running slow.""" | 952 """Measures & prints performance warning if a rule is running slow.""" |
| 931 dt2 = input_api.time.clock() | 953 dt2 = input_api.time.clock() |
| 932 if snapshot_memory: | 954 if snapshot_memory: |
| 933 delta_ms = int(1000*(dt2 - snapshot_memory[0])) | 955 delta_ms = int(1000*(dt2 - snapshot_memory[0])) |
| 934 if delta_ms > 500: | 956 if delta_ms > 500: |
| 935 print " %s took a long time: %dms" % (snapshot_memory[1], delta_ms) | 957 print " %s took a long time: %dms" % (snapshot_memory[1], delta_ms) |
| 936 snapshot_memory[:] = (dt2, msg) | 958 snapshot_memory[:] = (dt2, msg) |
| 937 | 959 |
| 960 issue_props = _GetRietveldIssueProps(input_api, messages=True) | |
| 938 if owners_check: | 961 if owners_check: |
| 939 snapshot("checking owners") | 962 snapshot("checking owners") |
| 940 results.extend(input_api.canned_checks.CheckOwners( | 963 results.extend(input_api.canned_checks.CheckOwners( |
| 941 input_api, output_api, source_file_filter=None)) | 964 input_api, output_api, issue_props, source_file_filter=None)) |
| 965 | |
| 966 if issue_props: | |
| 967 snapshot("checking review not closed") | |
| 968 results.extend(input_api.canned_checks.CheckIssueNotClosed( | |
| 969 issue_props, output_api)) | |
| 942 | 970 |
| 943 snapshot("checking long lines") | 971 snapshot("checking long lines") |
| 944 results.extend(input_api.canned_checks.CheckLongLines( | 972 results.extend(input_api.canned_checks.CheckLongLines( |
| 945 input_api, output_api, source_file_filter=sources)) | 973 input_api, output_api, source_file_filter=sources)) |
| 946 snapshot( "checking tabs") | 974 snapshot( "checking tabs") |
| 947 results.extend(input_api.canned_checks.CheckChangeHasNoTabs( | 975 results.extend(input_api.canned_checks.CheckChangeHasNoTabs( |
| 948 input_api, output_api, source_file_filter=sources)) | 976 input_api, output_api, source_file_filter=sources)) |
| 949 snapshot( "checking stray whitespace") | 977 snapshot( "checking stray whitespace") |
| 950 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace( | 978 results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace( |
| 951 input_api, output_api, source_file_filter=sources)) | 979 input_api, output_api, source_file_filter=sources)) |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 966 results.extend(input_api.canned_checks.CheckSvnForCommonMimeTypes( | 994 results.extend(input_api.canned_checks.CheckSvnForCommonMimeTypes( |
| 967 input_api, output_api)) | 995 input_api, output_api)) |
| 968 snapshot("checking license") | 996 snapshot("checking license") |
| 969 results.extend(input_api.canned_checks.CheckLicense( | 997 results.extend(input_api.canned_checks.CheckLicense( |
| 970 input_api, output_api, license_header, source_file_filter=sources)) | 998 input_api, output_api, license_header, source_file_filter=sources)) |
| 971 snapshot("checking was uploaded") | 999 snapshot("checking was uploaded") |
| 972 results.extend(input_api.canned_checks.CheckChangeWasUploaded( | 1000 results.extend(input_api.canned_checks.CheckChangeWasUploaded( |
| 973 input_api, output_api)) | 1001 input_api, output_api)) |
| 974 snapshot("done") | 1002 snapshot("done") |
| 975 return results | 1003 return results |
| OLD | NEW |