Index: PRESUBMIT.py |
diff --git a/PRESUBMIT.py b/PRESUBMIT.py |
index e589a47e5b5dfe81ce4f17e6163d99b07a0125a2..743a2e3126549ee8f44d68970c4faee47e123f8e 100644 |
--- a/PRESUBMIT.py |
+++ b/PRESUBMIT.py |
@@ -9,6 +9,7 @@ See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts |
for more details about the presubmit API built into gcl. |
""" |
+import collections |
import csv |
import fnmatch |
import os |
@@ -22,9 +23,6 @@ REVERT_CL_SUBJECT_PREFIX = 'Revert ' |
SKIA_TREE_STATUS_URL = 'http://skia-tree-status.appspot.com' |
-CQ_KEYWORDS_THAT_NEED_APPENDING = ('CQ_INCLUDE_TRYBOTS', 'CQ_EXTRA_TRYBOTS', |
- 'CQ_EXCLUDE_TRYBOTS', 'CQ_TRYBOTS') |
- |
# Please add the complete email address here (and not just 'xyz@' or 'xyz'). |
PUBLIC_API_OWNERS = ( |
'reed@chromium.org', |
@@ -39,6 +37,19 @@ AUTHORS_FILE_NAME = 'AUTHORS' |
DOCS_PREVIEW_URL = 'https://skia.org/?cl=' |
+# Path to CQ bots feature is described in skbug.com/4364 |
+PATH_PREFIX_TO_EXTRA_TRYBOTS = { |
+ # pylint: disable=line-too-long |
+ 'cmake/': 'client.skia.compile:Build-Mac10.9-Clang-x86_64-Release-CMake-Trybot,Build-Ubuntu-GCC-x86_64-Release-CMake-Trybot', |
+ # pylint: disable=line-too-long |
+ 'src/opts/': 'client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot', |
+ |
+ # Below are examples to show what is possible with this feature. |
+ # 'src/svg/': 'master1:abc;master2:def', |
+ # 'src/svg/parser/': 'master3:ghi,jkl;master4:mno', |
+ # 'src/image/SkImage_Base.h': 'master5:pqr,stu;master1:abc1;master2:def', |
+} |
+ |
def _CheckChangeHasEol(input_api, output_api, source_file_filter=None): |
"""Checks that files end with atleast one \n (LF).""" |
@@ -339,6 +350,7 @@ def PostUploadHook(cl, change, output_api): |
work on them. |
* Adds 'NOPRESUBMIT=true' for non master branch changes since those don't |
run the presubmit checks. |
+ * Adds extra trybots for the paths defined in PATH_TO_EXTRA_TRYBOTS. |
""" |
results = [] |
@@ -408,34 +420,22 @@ def PostUploadHook(cl, change, output_api): |
output_api.PresubmitNotifyResult( |
'Branch changes do not run the presubmit checks.')) |
- # Read and process the HASHTAGS file. |
- hashtags_fullpath = os.path.join(change._local_root, 'HASHTAGS') |
- with open(hashtags_fullpath, 'rb') as hashtags_csv: |
- hashtags_reader = csv.reader(hashtags_csv, delimiter=',') |
- for row in hashtags_reader: |
- if not row or row[0].startswith('#'): |
- # Ignore empty lines and comments |
- continue |
- hashtag = row[0] |
- # Search for the hashtag in the description. |
- if re.search('#%s' % hashtag, new_description, re.M | re.I): |
- for mapped_text in row[1:]: |
- # Special case handling for CQ_KEYWORDS_THAT_NEED_APPENDING. |
- appended_description = _HandleAppendingCQKeywords( |
- hashtag, mapped_text, new_description, results, output_api) |
- if appended_description: |
- new_description = appended_description |
- continue |
- |
- # Add the mapped text if it does not already exist in the |
- # CL's description. |
- if not re.search( |
- r'^%s$' % mapped_text, new_description, re.M | re.I): |
- new_description += '\n%s' % mapped_text |
- results.append( |
- output_api.PresubmitNotifyResult( |
- 'Found \'#%s\', automatically added \'%s\' to the CL\'s ' |
- 'description' % (hashtag, mapped_text))) |
+ # Automatically set CQ_EXTRA_TRYBOTS if any of the changed files here begin |
+ # with the paths of interest. |
+ cq_master_to_trybots = collections.defaultdict(set) |
+ for affected_file in change.AffectedFiles(): |
+ affected_file_path = affected_file.LocalPath() |
+ for path_prefix, extra_bots in PATH_PREFIX_TO_EXTRA_TRYBOTS.iteritems(): |
+ if affected_file_path.startswith(path_prefix): |
+ results.append( |
+ output_api.PresubmitNotifyResult( |
+ 'Your CL modifies the path %s.\nAutomatically adding %s to ' |
+ 'the CL description.' % (affected_file_path, extra_bots))) |
+ _MergeCQExtraTrybotsMaps( |
+ cq_master_to_trybots, _GetCQExtraTrybotsMap(extra_bots)) |
+ if cq_master_to_trybots: |
+ new_description = _AddCQExtraTrybotsToDesc( |
+ cq_master_to_trybots, new_description) |
# If the description has changed update it. |
if new_description != original_description: |
@@ -444,29 +444,49 @@ def PostUploadHook(cl, change, output_api): |
return results |
-def _HandleAppendingCQKeywords(hashtag, keyword_and_value, description, |
- results, output_api): |
- """Handles the CQ keywords that need appending if specified in hashtags.""" |
- keyword = keyword_and_value.split('=')[0] |
- if keyword in CQ_KEYWORDS_THAT_NEED_APPENDING: |
- # If the keyword is already in the description then append to it. |
- match = re.search( |
- r'^%s=(.*)$' % keyword, description, re.M | re.I) |
- if match: |
- old_values = match.group(1).split(';') |
- new_value = keyword_and_value.split('=')[1] |
- if new_value in old_values: |
- # Do not need to do anything here. |
- return description |
- # Update the description with the new values. |
- new_description = description.replace( |
- match.group(0), "%s;%s" % (match.group(0), new_value)) |
- results.append( |
- output_api.PresubmitNotifyResult( |
- 'Found \'#%s\', automatically appended \'%s\' to %s in ' |
- 'the CL\'s description' % (hashtag, new_value, keyword))) |
- return new_description |
- return None |
+def _AddCQExtraTrybotsToDesc(cq_master_to_trybots, description): |
+ """Adds the specified master and trybots to the CQ_EXTRA_TRYBOTS keyword. |
+ |
+ If the keyword already exists in the description then it appends to it only |
+ if the specified values do not already exist. |
+ If the keyword does not exist then it creates a new section in the |
+ description. |
+ """ |
+ match = re.search(r'^CQ_EXTRA_TRYBOTS=(.*)$', description, re.M | re.I) |
+ if match: |
+ original_trybots_map = _GetCQExtraTrybotsMap(match.group(1)) |
+ _MergeCQExtraTrybotsMaps(cq_master_to_trybots, original_trybots_map) |
+ new_description = description.replace( |
+ match.group(0), _GetCQExtraTrybotsStr(cq_master_to_trybots)) |
+ else: |
+ new_description = description + "\n%s" % ( |
+ _GetCQExtraTrybotsStr(cq_master_to_trybots)) |
+ return new_description |
+ |
+ |
+def _MergeCQExtraTrybotsMaps(dest_map, map_to_be_consumed): |
+ """Merges two maps of masters to trybots into one.""" |
+ for master, trybots in map_to_be_consumed.iteritems(): |
+ dest_map[master].update(trybots) |
+ return dest_map |
+ |
+ |
+def _GetCQExtraTrybotsMap(cq_extra_trybots_str): |
+ """Parses the CQ_EXTRA_TRYBOTS str and returns a map of masters to trybots.""" |
+ cq_master_to_trybots = collections.defaultdict(set) |
+ for section in cq_extra_trybots_str.split(';'): |
+ if section: |
+ master, bots = section.split(':') |
+ cq_master_to_trybots[master].update(bots.split(',')) |
+ return cq_master_to_trybots |
+ |
+ |
+def _GetCQExtraTrybotsStr(cq_master_to_trybots): |
+ """Constructs the CQ_EXTRA_TRYBOTS str from a map of masters to trybots.""" |
+ sections = [] |
+ for master, trybots in cq_master_to_trybots.iteritems(): |
+ sections.append('%s:%s' % (master, ','.join(trybots))) |
+ return 'CQ_EXTRA_TRYBOTS=%s' % ';'.join(sections) |
def CheckChangeOnCommit(input_api, output_api): |