Skip to content

Commit

Permalink
Add watchlists to 'gcl upload'
Browse files Browse the repository at this point in the history
Watchlists provides an opportunity for someone interested in a particular
code section to make comments before commit. One can subscribe to watchlists
depending on filepath (regular expressions) and she'll automatically get
cc-ed to changes when the watchlist is triggered.

Additional examples of watchlist_rules in diff repo:
http://codereview.chromium.org/118431
http://codereview.chromium.org/119356
Review URL: http://codereview.chromium.org/118432

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@18209 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
[email protected] committed Jun 11, 2009
1 parent 899410c commit b2ab494
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 0 deletions.
24 changes: 24 additions & 0 deletions WATCHLISTS
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# Watchlist Rules
# Refer: http://dev.chromium.org/developers/contributing-code/watchlists

{

'WATCHLIST_DEFINITIONS': {
'this_file': {
'filepath': '^WATCHLISTS$',
},
'depot_tools': {
'filepath': '.+',
},
},

'WATCHLISTS': {
'this_file': ['[email protected]'],
'depot_tools': ['[email protected]'],
},

}
13 changes: 13 additions & 0 deletions gcl.py
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,7 @@ def Help(argv=None):
gcl upload change_name [-r [email protected],[email protected],...]
[--send_mail] [--no_try] [--no_presubmit]
[--no_watchlists]
Uploads the changelist to the server for review.
gcl commit change_name [--no_presubmit]
Expand Down Expand Up @@ -738,6 +739,8 @@ def UploadCL(change_info, args):
if not OptionallyDoPresubmitChecks(change_info, False, args):
return
no_try = FilterFlag(args, "--no_try") or FilterFlag(args, "--no-try")
no_watchlists = FilterFlag(args, "--no_watchlists") or \
FilterFlag(args, "--no-watchlists")

# Map --send-mail to --send_mail
if FilterFlag(args, "--send-mail"):
Expand Down Expand Up @@ -775,7 +778,17 @@ def UploadCL(change_info, args):
os.write(handle, change_info.description)
os.close(handle)

# Watchlist processing -- CC people interested in this changeset
# http://dev.chromium.org/developers/contributing-code/watchlists
if not no_watchlists:
import watchlists
watchlist = watchlists.Watchlists(GetRepositoryRoot())
watchers = watchlist.GetWatchersForPaths(change_info.FileList())

cc_list = GetCodeReviewSetting("CC_LIST")
if not no_watchlists and watchers:
# Filter out all empty elements and join by ','
cc_list = ','.join(filter(None, [cc_list] + watchers))
if cc_list:
upload_arg.append("--cc=" + cc_list)
upload_arg.append("--description_file=" + desc_file + "")
Expand Down
117 changes: 117 additions & 0 deletions watchlists.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/usr/bin/python
# Copyright (c) 2009 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Watchlists
Watchlists is a mechanism that allow a developer (a "watcher") to watch over
portions of code that he is interested in. A "watcher" will be cc-ed to
changes that modify that portion of code, thereby giving him an opportunity
to make comments on codereview.chromium.org even before the change is
committed.
Refer: http://dev.chromium.org/developers/contributing-code/watchlists
When invoked directly from the base of a repository, this script lists out
the watchers for files given on the command line. This is useful to verify
changes to WATCHLISTS files.
"""

import logging
import os
import re
import sys


class Watchlists(object):
"""Manage Watchlists.
This class provides mechanism to load watchlists for a repo and identify
watchers.
Usage:
wl = Watchlists("/path/to/repo/root")
watchers = wl.GetWatchersForPaths(["/path/to/file1",
"/path/to/file2",])
"""

_RULES = "WATCHLISTS"
_RULES_FILENAME = _RULES
_repo_root = None
_defns = {} # Definitions
_watchlists = {} # name to email mapping

def __init__(self, repo_root):
self._repo_root = repo_root
self._LoadWatchlistRules()

def _GetRulesFilePath(self):
return os.path.join(self._repo_root, self._RULES_FILENAME)

def _HasWatchlistsFile(self):
"""Determine if watchlists are available for this repo."""
return os.path.exists(self._GetRulesFilePath())

def _LoadWatchlistRules(self):
if not self._HasWatchlistsFile():
return
watchlists_file = open(self._GetRulesFilePath())
contents = watchlists_file.read()
watchlists_file.close()

watchlists_data = None
try:
watchlists_data = eval(contents, {'__builtins__': None}, None)
except SyntaxError, e:
logging.error("Cannot parse %s. %s" % (self._GetRulesFilePath(), e))
return

defns = watchlists_data.get("WATCHLIST_DEFINITIONS")
if not defns:
logging.error("WATCHLIST_DEFINITIONS not defined in %s" %
self._GetRulesFilePath())
return
watchlists = watchlists_data.get("WATCHLISTS")
if not watchlists:
logging.error("WATCHLISTS not defined in %s" % self._GetRulesFilePath())
return
self._defns = defns
self._watchlists = watchlists

# Verify that all watchlist names are defined
for name in watchlists:
if name not in defns:
logging.error("%s not defined in %s" % (name, self._GetRulesFilePath()))

def GetWatchersForPaths(self, paths):
"""Fetch the list of watchers for |paths|
Args:
paths: [path1, path2, ...]
Returns:
[[email protected], [email protected], ...]
"""
watchers = set() # A set, to avoid duplicates
for path in paths:
for name, rule in self._defns.iteritems():
if name not in self._watchlists: continue
rex_str = rule.get('filepath')
if not rex_str: continue
if re.search(rex_str, path):
map(watchers.add, self._watchlists[name])
return list(watchers)


def main(argv):
# Confirm that watchlists can be parsed and spew out the watchers
if len(argv) < 2:
print "Usage (from the base of repo):"
print " %s [file-1] [file-2] ...." % argv[0]
return 1
wl = Watchlists(os.getcwd())
watchers = wl.GetWatchersForPaths(argv[1:])
print watchers


if __name__ == '__main__':
main(sys.argv)

0 comments on commit b2ab494

Please sign in to comment.