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 # Justifications for each filter: | 10 # Justifications for each filter: |
| (...skipping 857 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 868 needed = 'LGTM from an OWNER' | 868 needed = 'LGTM from an OWNER' |
| 869 output = output_api.PresubmitError | 869 output = output_api.PresubmitError |
| 870 else: | 870 else: |
| 871 needed = 'OWNER reviewers' | 871 needed = 'OWNER reviewers' |
| 872 output = output_api.PresubmitNotifyResult | 872 output = output_api.PresubmitNotifyResult |
| 873 | 873 |
| 874 affected_files = set([f.LocalPath() for f in | 874 affected_files = set([f.LocalPath() for f in |
| 875 input_api.change.AffectedFiles(file_filter=source_file_filter)]) | 875 input_api.change.AffectedFiles(file_filter=source_file_filter)]) |
| 876 | 876 |
| 877 owners_db = input_api.owners_db | 877 owners_db = input_api.owners_db |
| 878 # TODO(tandrii): this will always return None, set() in case of Gerrit. | 878 owner_email, reviewers = _CodereviewOwnersAndReviewers( |
| 879 owner_email, reviewers = _RietveldOwnerAndReviewers( | |
| 880 input_api, | 879 input_api, |
| 881 owners_db.email_regexp, | 880 owners_db.email_regexp, |
| 882 approval_needed=input_api.is_committing) | 881 approval_needed=input_api.is_committing) |
| 883 | 882 |
| 884 owner_email = owner_email or input_api.change.author_email | 883 owner_email = owner_email or input_api.change.author_email |
| 885 | 884 |
| 886 if owner_email: | 885 if owner_email: |
| 887 reviewers_plus_owner = set([owner_email]).union(reviewers) | 886 reviewers_plus_owner = set([owner_email]).union(reviewers) |
| 888 missing_files = owners_db.files_not_covered_by(affected_files, | 887 missing_files = owners_db.files_not_covered_by(affected_files, |
| 889 reviewers_plus_owner) | 888 reviewers_plus_owner) |
| 890 else: | 889 else: |
| 891 missing_files = owners_db.files_not_covered_by(affected_files, reviewers) | 890 missing_files = owners_db.files_not_covered_by(affected_files, reviewers) |
| 892 | 891 |
| 893 if missing_files: | 892 if missing_files: |
| 894 output_list = [ | 893 output_list = [ |
| 895 output('Missing %s for these files:\n %s' % | 894 output('Missing %s for these files:\n %s' % |
| 896 (needed, '\n '.join(sorted(missing_files))))] | 895 (needed, '\n '.join(sorted(missing_files))))] |
| 897 if not input_api.is_committing: | 896 if not input_api.is_committing: |
| 898 suggested_owners = owners_db.reviewers_for(missing_files, owner_email) | 897 suggested_owners = owners_db.reviewers_for(missing_files, owner_email) |
| 899 output_list.append(output('Suggested OWNERS: ' + | 898 output_list.append(output('Suggested OWNERS: ' + |
| 900 '(Use "git-cl owners" to interactively select owners.)\n %s' % | 899 '(Use "git-cl owners" to interactively select owners.)\n %s' % |
| 901 ('\n '.join(suggested_owners or [])))) | 900 ('\n '.join(suggested_owners or [])))) |
| 902 return output_list | 901 return output_list |
| 903 | 902 |
| 904 if input_api.is_committing and not reviewers: | 903 if input_api.is_committing and not reviewers: |
| 905 return [output('Missing LGTM from someone other than %s' % owner_email)] | 904 return [output('Missing LGTM from someone other than %s' % owner_email)] |
| 906 return [] | 905 return [] |
| 907 | 906 |
| 907 def _CodereviewOwnersAndReviewers(input_api, email_regexp, approval_needed): | |
| 908 """Return the owner and reviewers of a change, if any. | |
| 909 | |
| 910 If approval_needed is True, only reviewers who have approved the change | |
| 911 will be returned. | |
| 912 """ | |
| 913 if input_api.gerrit: | |
| 914 return _GerritOwnerAndReviewers(input_api, email_regexp, approval_needed) | |
| 915 else: | |
| 916 # Rietveld is default. | |
| 917 return _RietveldOwnerAndReviewers(input_api, email_regexp, approval_needed) | |
| 918 | |
| 908 | 919 |
| 909 def _GetRietveldIssueProps(input_api, messages): | 920 def _GetRietveldIssueProps(input_api, messages): |
| 910 """Gets the issue properties from rietveld.""" | 921 """Gets the issue properties from rietveld.""" |
| 911 issue = input_api.change.issue | 922 issue = input_api.change.issue |
| 912 if issue and input_api.rietveld: | 923 if issue and input_api.rietveld: |
| 913 return input_api.rietveld.get_issue_properties( | 924 return input_api.rietveld.get_issue_properties( |
| 914 issue=int(issue), messages=messages) | 925 issue=int(issue), messages=messages) |
| 915 | 926 |
| 916 | 927 |
| 917 def _ReviewersFromChange(change): | 928 def _ReviewersFromChange(change): |
| 918 """Return the reviewers specified in the |change|, if any.""" | 929 """Return the reviewers specified in the |change|, if any.""" |
| 919 reviewers = set() | 930 reviewers = set() |
| 920 if change.R: | 931 if change.R: |
| 921 reviewers.update(set([r.strip() for r in change.R.split(',')])) | 932 reviewers.update(set([r.strip() for r in change.R.split(',')])) |
| 922 if change.TBR: | 933 if change.TBR: |
| 923 reviewers.update(set([r.strip() for r in change.TBR.split(',')])) | 934 reviewers.update(set([r.strip() for r in change.TBR.split(',')])) |
| 924 | 935 |
| 925 # Drop reviewers that aren't specified in email address format. | 936 # Drop reviewers that aren't specified in email address format. |
| 926 return set(reviewer for reviewer in reviewers if '@' in reviewer) | 937 return set(reviewer for reviewer in reviewers if '@' in reviewer) |
| 927 | 938 |
| 928 | 939 |
| 940 def _match_reviewer_email(r, owner_email, email_regexp): | |
| 941 return email_regexp.match(r) and r != owner_email | |
| 942 | |
| 929 def _RietveldOwnerAndReviewers(input_api, email_regexp, approval_needed=False): | 943 def _RietveldOwnerAndReviewers(input_api, email_regexp, approval_needed=False): |
| 930 """Return the owner and reviewers of a change, if any. | 944 """Return the owner and reviewers of a change, if any. |
| 931 | 945 |
| 932 If approval_needed is True, only reviewers who have approved the change | 946 If approval_needed is True, only reviewers who have approved the change |
| 933 will be returned. | 947 will be returned. |
| 934 """ | 948 """ |
| 935 issue_props = _GetRietveldIssueProps(input_api, True) | 949 issue_props = _GetRietveldIssueProps(input_api, True) |
| 936 if not issue_props: | 950 if not issue_props: |
| 937 reviewers = set() | 951 reviewers = set() |
| 938 if not approval_needed: | 952 if not approval_needed: |
| 939 reviewers = _ReviewersFromChange(input_api.change) | 953 reviewers = _ReviewersFromChange(input_api.change) |
| 940 return None, reviewers | 954 return None, reviewers |
| 941 | 955 |
| 942 if not approval_needed: | 956 if not approval_needed: |
| 943 return issue_props['owner_email'], set(issue_props['reviewers']) | 957 return issue_props['owner_email'], set(issue_props['reviewers']) |
| 944 | 958 |
| 945 owner_email = issue_props['owner_email'] | 959 owner_email = issue_props['owner_email'] |
| 946 | 960 |
| 947 def match_reviewer(r): | |
| 948 return email_regexp.match(r) and r != owner_email | |
| 949 | |
| 950 messages = issue_props.get('messages', []) | 961 messages = issue_props.get('messages', []) |
| 951 approvers = set( | 962 approvers = set( |
| 952 m['sender'] for m in messages | 963 m['sender'] for m in messages |
| 953 if m.get('approval') and match_reviewer(m['sender'])) | 964 if m.get('approval') and _match_reviewer_email(m['sender'], owner_email, |
| 965 email_regexp)) | |
| 966 return owner_email, approvers | |
| 954 | 967 |
| 955 return owner_email, approvers | 968 |
| 969 def _GerritOwnerAndReviewers(input_api, email_regexp, approval_needed=False): | |
| 970 """Return the owner and reviewers of a change, if any. | |
| 971 | |
| 972 If approval_needed is True, only reviewers who have approved the change | |
| 973 will be returned. | |
| 974 """ | |
| 975 issue = input_api.change.issue | |
|
Michael Achenbach
2016/04/28 07:17:29
5 lines code dupe. Maybe you can make this common?
tandrii(chromium)
2016/04/28 19:31:50
yep, tricky part is backwards compat, but I think
Michael Achenbach
2016/04/29 08:10:18
Ok - I just meant to share the duplicated code in
Michael Achenbach
2016/05/06 15:01:42
Guess this caused https://bugs.chromium.org/p/chro
| |
| 976 if not issue: | |
| 977 reviewers = set() | |
| 978 if not approval_needed: | |
| 979 reviewers = _ReviewersFromChange(input_api.change) | |
| 980 return None, reviewers | |
| 981 | |
| 982 owner_email = input_api.gerrit.GetChangeOwner(issue) | |
| 983 reviewers = set( | |
| 984 r for r in input_api.gerrit.GetChangeReviewers(issue, approval_needed) | |
| 985 if _match_reviewer_email(r, owner_email, email_regexp)) | |
| 986 return owner_email, reviewers | |
| 956 | 987 |
| 957 | 988 |
| 958 def _CheckConstNSObject(input_api, output_api, source_file_filter): | 989 def _CheckConstNSObject(input_api, output_api, source_file_filter): |
| 959 """Checks to make sure no objective-c files have |const NSSomeClass*|.""" | 990 """Checks to make sure no objective-c files have |const NSSomeClass*|.""" |
| 960 pattern = input_api.re.compile( | 991 pattern = input_api.re.compile( |
| 961 r'(?<!reinterpret_cast<)' | 992 r'(?<!reinterpret_cast<)' |
| 962 r'const\s+NS(?!(Point|Range|Rect|Size)\s*\*)\w*\s*\*') | 993 r'const\s+NS(?!(Point|Range|Rect|Size)\s*\*)\w*\s*\*') |
| 963 | 994 |
| 964 def objective_c_filter(f): | 995 def objective_c_filter(f): |
| 965 return (source_file_filter(f) and | 996 return (source_file_filter(f) and |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1128 for f in affected_files: | 1159 for f in affected_files: |
| 1129 cmd = ['gn', 'format', '--dry-run', f.AbsoluteLocalPath()] | 1160 cmd = ['gn', 'format', '--dry-run', f.AbsoluteLocalPath()] |
| 1130 rc = gn.main(cmd) | 1161 rc = gn.main(cmd) |
| 1131 if rc == 2: | 1162 if rc == 2: |
| 1132 warnings.append(output_api.PresubmitPromptWarning( | 1163 warnings.append(output_api.PresubmitPromptWarning( |
| 1133 '%s requires formatting. Please run `gn format --in-place %s`.' % ( | 1164 '%s requires formatting. Please run `gn format --in-place %s`.' % ( |
| 1134 f.AbsoluteLocalPath(), f.LocalPath()))) | 1165 f.AbsoluteLocalPath(), f.LocalPath()))) |
| 1135 # It's just a warning, so ignore other types of failures assuming they'll be | 1166 # It's just a warning, so ignore other types of failures assuming they'll be |
| 1136 # caught elsewhere. | 1167 # caught elsewhere. |
| 1137 return warnings | 1168 return warnings |
| OLD | NEW |