Add support for a global status files for OWNERS
This allows for having some global comments such as timezones or
long-term unavailability.
The comments go into build/OWNERS.status (that way, they should be
available in all repos that map in build/ for the gn config files).
The local can be overwritten in codereview.settings.
The format is
email: status
Comments (starting with #) are allowed in that file, but they're ignored.
BUG=694222
R=dpranke@chromium.org
Change-Id: I49f58be87497d1ccaaa74f0a2f3d373403be44e7
Reviewed-on: https://chromium-review.googlesource.com/459542
Commit-Queue: Jochen Eisinger <jochen@chromium.org>
Reviewed-by: Dirk Pranke <dpranke@chromium.org>
diff --git a/owners.py b/owners.py
index 068e35b..2a44a9d 100644
--- a/owners.py
+++ b/owners.py
@@ -68,6 +68,11 @@
BASIC_EMAIL_REGEXP = r'^[\w\-\+\%\.]+\@[\w\-\+\%\.]+$'
+# Key for global comments per email address. Should be unlikely to be a
+# pathname.
+GLOBAL_STATUS = '*'
+
+
def _assert_is_collection(obj):
assert not isinstance(obj, basestring)
# Module 'collections' has no 'Iterable' member
@@ -95,14 +100,16 @@
of changed files, and see if a list of changed files is covered by a
list of reviewers."""
- def __init__(self, root, fopen, os_path):
+ def __init__(self, root, status_file, fopen, os_path):
"""Args:
root: the path to the root of the Repository
+ status_file: the path relative to root to global status entries or None
open: function callback to open a text file for reading
os_path: module/object callback with fields for 'abspath', 'dirname',
'exists', 'join', and 'relpath'
"""
self.root = root
+ self.status_file = status_file
self.fopen = fopen
self.os_path = os_path
@@ -196,6 +203,7 @@
return dirpath
def load_data_needed_for(self, files):
+ self._read_global_comments()
for f in files:
dirpath = self.os_path.dirname(f)
while not self._owners_for(dirpath):
@@ -267,6 +275,44 @@
self._add_entry(dirpath, line, owners_path, lineno,
' '.join(comment))
+ def _read_global_comments(self):
+ if not self.status_file:
+ return
+
+ owners_status_path = self.os_path.join(self.root, self.status_file)
+ if not self.os_path.exists(owners_status_path):
+ raise IOError('Could not find global status file "%s"' %
+ owners_status_path)
+
+ if owners_status_path in self.read_files:
+ return
+
+ self.read_files.add(owners_status_path)
+
+ lineno = 0
+ for line in self.fopen(owners_status_path):
+ lineno += 1
+ line = line.strip()
+ if line.startswith('#'):
+ continue
+ if line == '':
+ continue
+
+ m = re.match('(.+?):(.+)', line)
+ if m:
+ owner = m.group(1).strip()
+ comment = m.group(2).strip()
+ if not self.email_regexp.match(owner):
+ raise SyntaxErrorInOwnersFile(owners_status_path, lineno,
+ 'invalid email address: "%s"' % owner)
+
+ self.comments.setdefault(owner, {})
+ self.comments[owner][GLOBAL_STATUS] = comment
+ continue
+
+ raise SyntaxErrorInOwnersFile(owners_status_path, lineno,
+ 'cannot parse status entry: "%s"' % line.strip())
+
def _add_entry(self, owned_paths, directive, owners_path, lineno, comment):
if directive == 'set noparent':
self._stop_looking.add(owned_paths)
@@ -281,8 +327,9 @@
self._owners_to_paths.setdefault(owner, set()).add(owned_paths)
self._paths_to_owners.setdefault(owned_paths, set()).add(owner)
elif self.email_regexp.match(directive) or directive == EVERYONE:
- self.comments.setdefault(directive, {})
- self.comments[directive][owned_paths] = comment
+ if comment:
+ self.comments.setdefault(directive, {})
+ self.comments[directive][owned_paths] = comment
self._owners_to_paths.setdefault(directive, set()).add(owned_paths)
self._paths_to_owners.setdefault(owned_paths, set()).add(directive)
else: