Commit f9fbe7b6 authored by Jochen Eisinger's avatar Jochen Eisinger Committed by Commit Bot

Add presubmit check for set noparent rules

Bug: 1018108
Change-Id: I5d86962e4dcdd3a95058efef86735a11a75ac8c4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1908531
Commit-Queue: Jochen Eisinger <jochen@chromium.org>
Reviewed-by: default avatarDirk Pranke <dpranke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#716096}
parent c975bcfd
...@@ -3073,6 +3073,71 @@ def _CheckIpcOwners(input_api, output_api): ...@@ -3073,6 +3073,71 @@ def _CheckIpcOwners(input_api, output_api):
return results return results
def _CheckSetNoParent(input_api, output_api):
"""Checks that set noparent is only used together with an OWNERS file in
//build/OWNERS.setnoparent (see also
//docs/code_reviews.md#owners-files-details)
"""
errors = []
allowed_owners_files_file = 'build/OWNERS.setnoparent'
allowed_owners_files = set()
with open(allowed_owners_files_file, 'r') as f:
for line in f:
line = line.strip()
if not line or line.startswith('#'):
continue
allowed_owners_files.add(line)
per_file_pattern = input_api.re.compile('per-file (.+)=(.+)')
for f in input_api.AffectedFiles(include_deletes=False):
if not f.LocalPath().endswith('OWNERS'):
continue
found_owners_files = set()
found_set_noparent_lines = dict()
# Parse the OWNERS file.
for lineno, line in enumerate(f.NewContents(), 1):
line = line.strip()
if line.startswith('set noparent'):
found_set_noparent_lines[''] = lineno
if line.startswith('file://'):
if line in allowed_owners_files:
found_owners_files.add('')
if line.startswith('per-file'):
match = per_file_pattern.match(line)
if match:
glob = match.group(1).strip()
directive = match.group(2).strip()
if directive == 'set noparent':
found_set_noparent_lines[glob] = lineno
if directive.startswith('file://'):
if directive in allowed_owners_files:
found_owners_files.add(glob)
# Check that every set noparent line has a corresponding file:// line
# listed in build/OWNERS.setnoparent.
for set_noparent_line in found_set_noparent_lines:
if set_noparent_line in found_owners_files:
continue
errors.append(' %s:%d' % (f.LocalPath(),
found_set_noparent_lines[set_noparent_line]))
results = []
if errors:
if input_api.is_committing:
output = output_api.PresubmitError
else:
output = output_api.PresubmitPromptWarning
results.append(output(
'Found the following "set noparent" restrictions in OWNERS files that '
'do not include owners from build/OWNERS.setnoparent:',
long_text='\n\n'.join(errors)))
return results
def _CheckUselessForwardDeclarations(input_api, output_api): def _CheckUselessForwardDeclarations(input_api, output_api):
"""Checks that added or removed lines in non third party affected """Checks that added or removed lines in non third party affected
header files do not lead to new useless class or struct forward header files do not lead to new useless class or struct forward
...@@ -4192,6 +4257,7 @@ def _CommonChecks(input_api, output_api): ...@@ -4192,6 +4257,7 @@ def _CommonChecks(input_api, output_api):
results.extend(_CheckPydepsNeedsUpdating(input_api, output_api)) results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
results.extend(_CheckJavaStyle(input_api, output_api)) results.extend(_CheckJavaStyle(input_api, output_api))
results.extend(_CheckIpcOwners(input_api, output_api)) results.extend(_CheckIpcOwners(input_api, output_api))
results.extend(_CheckSetNoParent(input_api, output_api))
results.extend(_CheckUselessForwardDeclarations(input_api, output_api)) results.extend(_CheckUselessForwardDeclarations(input_api, output_api))
results.extend(_CheckForRelativeIncludes(input_api, output_api)) results.extend(_CheckForRelativeIncludes(input_api, output_api))
results.extend(_CheckForCcIncludes(input_api, output_api)) results.extend(_CheckForCcIncludes(input_api, output_api))
......
...@@ -2747,5 +2747,40 @@ class CheckFuzzTargetsTest(unittest.TestCase): ...@@ -2747,5 +2747,40 @@ class CheckFuzzTargetsTest(unittest.TestCase):
self.assertEqual(results[0].items, ['fuzzer.cc']) self.assertEqual(results[0].items, ['fuzzer.cc'])
class SetNoParentTest(unittest.TestCase):
def testSetNoParentMissing(self):
mock_input_api = MockInputApi()
mock_input_api.files = [
MockAffectedFile('goat/OWNERS',
[
'set noparent',
'jochen@chromium.org',
'per-file *.json=set noparent',
'per-file *.json=jochen@chromium.org',
])
]
mock_output_api = MockOutputApi()
errors = PRESUBMIT._CheckSetNoParent(mock_input_api, mock_output_api)
self.assertEqual(1, len(errors))
self.assertTrue('goat/OWNERS:1' in errors[0].long_text)
self.assertTrue('goat/OWNERS:3' in errors[0].long_text)
def testSetNoParentWithCorrectRule(self):
mock_input_api = MockInputApi()
mock_input_api.files = [
MockAffectedFile('goat/OWNERS',
[
'set noparent',
'file://ipc/SECURITY_OWNERS',
'per-file *.json=set noparent',
'per-file *.json=file://ipc/SECURITY_OWNERS',
])
]
mock_output_api = MockOutputApi()
errors = PRESUBMIT._CheckSetNoParent(mock_input_api, mock_output_api)
self.assertEqual([], errors)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment