[owners] Validate owners config in Depot Tools client.
Change-Id: Ia9cb19d2b1f776c41ef7e96e6a0ebfb0fcd41344
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/2548029
Auto-Submit: Edward Lesmes <ehmaldonado@chromium.org>
Commit-Queue: Anthony Polito <apolito@google.com>
Reviewed-by: Anthony Polito <apolito@google.com>
diff --git a/owners_client.py b/owners_client.py
index da259a3..3d15020 100644
--- a/owners_client.py
+++ b/owners_client.py
@@ -14,6 +14,10 @@
INSUFFICIENT_REVIEWERS = 'INSUFFICIENT_REVIEWERS'
+class InvalidOwnersConfig(Exception):
+ pass
+
+
class OwnersClient(object):
"""Interact with OWNERS files in a repository.
@@ -36,7 +40,7 @@
raise Exception('Not implemented')
def GetChangeApprovalStatus(self, change_id):
- """Check the approval status for the latest patch in a change.
+ """Check the approval status for the latest revision_id in a change.
Returns a map of path to approval status, where the status can be one of:
- APPROVED: An owner of the file has reviewed the change.
@@ -46,7 +50,7 @@
"""
raise Exception('Not implemented')
- def IsOwnerConfigurationValid(self, change_id, patch):
+ def ValidateOwnersConfig(self, change_id):
"""Check if the owners configuration in a change is valid."""
raise Exception('Not implemented')
@@ -56,6 +60,8 @@
def __init__(self, host, root, fopen, os_path, branch):
super(DepotToolsClient, self).__init__(host)
self._root = root
+ self._fopen = fopen
+ self._os_path = os_path
self._branch = branch
self._db = owners.Database(root, fopen, os_path)
self._db.override_files = self._GetOriginalOwnersFiles()
@@ -96,3 +102,18 @@
else:
status[f] = INSUFFICIENT_REVIEWERS
return status
+
+ def ValidateOwnersConfig(self, change_id):
+ data = gerrit_util.GetChange(
+ self._host, change_id,
+ ['DETAILED_ACCOUNTS', 'DETAILED_LABELS', 'CURRENT_FILES',
+ 'CURRENT_REVISION'])
+
+ files = data['revisions'][data['current_revision']]['files']
+
+ db = owners.Database(self._root, self._fopen, self._os_path)
+ try:
+ db.load_data_needed_for(
+ [f for f in files if os.path.basename(f) == 'OWNERS'])
+ except Exception as e:
+ raise InvalidOwnersConfig('Error parsing OWNERS files:\n%s' % e)
diff --git a/tests/owners_client_test.py b/tests/owners_client_test.py
index 74cccc5..691c24e 100644
--- a/tests/owners_client_test.py
+++ b/tests/owners_client_test.py
@@ -20,39 +20,40 @@
from testing_support import filesystem_mock
-_TEST_CHANGE = {
- "labels": {
- "Code-Review": {
- "all": [
- {
- "value": 1,
- "email": "approver@example.com",
- }
+def _get_change():
+ return {
+ "labels": {
+ "Code-Review": {
+ "all": [
+ {
+ "value": 1,
+ "email": "approver@example.com",
+ }
+ ],
+ "values": {
+ "-1": "Don't submit as-is",
+ " 0": "No score",
+ "+1": "Looks good to me"
+ },
+ },
+ },
+ "reviewers": {
+ "REVIEWER": [
+ {"email": "approver@example.com"},
+ {"email": "reviewer@example.com"},
],
- "values": {
- "-1": "Don't submit as-is",
- " 0": "No score",
- "+1": "Looks good to me"
+ },
+ "current_revision": "cb90826d03533d6c4e1f0e974ebcbfd7a6f42406",
+ "revisions": {
+ "cb90826d03533d6c4e1f0e974ebcbfd7a6f42406": {
+ "files": {
+ "approved.cc": {},
+ "reviewed.h": {},
+ "bar/insufficient.py": {},
+ },
},
},
- },
- "reviewers": {
- "REVIEWER": [
- {"email": "approver@example.com"},
- {"email": "reviewer@example.com"},
- ],
- },
- "current_revision": "cb90826d03533d6c4e1f0e974ebcbfd7a6f42406",
- "revisions": {
- "cb90826d03533d6c4e1f0e974ebcbfd7a6f42406": {
- "files": {
- "approved.cc": {},
- "reviewed.h": {},
- "bar/insufficient.py": {},
- },
- },
- },
-}
+ }
@@ -70,32 +71,45 @@
'/bar/everyone/OWNERS': '*',
'/bar/everyone/foo.txt': '',
})
- self.files = self.repo.files
self.root = '/'
self.fopen = self.repo.open_for_reading
mock.patch(
'owners_client.DepotToolsClient._GetOriginalOwnersFiles',
return_value={}).start()
self.addCleanup(mock.patch.stopall)
+ self.client = owners_client.DepotToolsClient(
+ 'host', '/', self.fopen, self.repo, 'branch')
def testListOwners(self):
- client = owners_client.DepotToolsClient(
- 'host', '/', self.fopen, self.repo, 'branch')
self.assertEquals(
['*', 'missing@example.com'],
- client.ListOwnersForFile('project', 'branch', 'bar/everyone/foo.txt'))
+ self.client.ListOwnersForFile(
+ 'project', 'branch', 'bar/everyone/foo.txt'))
- @mock.patch('gerrit_util.GetChange', return_value=_TEST_CHANGE)
+ @mock.patch('gerrit_util.GetChange', return_value=_get_change())
def testGetChangeApprovalStatus(self, _mock):
- client = owners_client.DepotToolsClient(
- 'host', '/', self.fopen, self.repo, 'branch')
self.assertEquals(
{
'approved.cc': owners_client.APPROVED,
'reviewed.h': owners_client.PENDING,
'bar/insufficient.py': owners_client.INSUFFICIENT_REVIEWERS,
},
- client.GetChangeApprovalStatus('changeid'))
+ self.client.GetChangeApprovalStatus('changeid'))
+
+ @mock.patch('gerrit_util.GetChange', return_value=_get_change())
+ def testValidateOwnersConfig_OK(self, get_change_mock):
+ self.client.ValidateOwnersConfig('changeid')
+
+ @mock.patch('gerrit_util.GetChange', return_value=_get_change())
+ def testValidateOwnersConfig_Invalid(self, get_change_mock):
+ change = get_change_mock()
+ change['revisions'][change['current_revision']]['files'] = {'/OWNERS': {}}
+ self.repo.files['/OWNERS'] = '\n'.join([
+ 'foo@example.com',
+ 'invalid directive',
+ ])
+ with self.assertRaises(owners_client.InvalidOwnersConfig):
+ self.client.ValidateOwnersConfig('changeid')
if __name__ == '__main__':