Automatically add extra CQ trybots for predetermined paths

If the CL does not contain a "CQ_EXTRA_TRYBOTS=" section then it constructs one from the paths modified in your CL.

If you already have an existing "CQ_EXTRA_TRYBOTS=" section in your CL then it parses it, preserves your options, and only adds the builders and masters that were missing.

Also ensures no trybots are repeated (i.e. each master trybot combination only shows up once).

And I killed the hashtags feature in this CL, nobody was using it.

BUG=skia:4364

Review URL: https://codereview.chromium.org/1383743002
This commit is contained in:
rmistry 2015-10-01 08:24:03 -07:00 committed by Commit bot
parent 9806d4ded5
commit 5827653e42
2 changed files with 74 additions and 76 deletions

View File

@ -1,22 +0,0 @@
# This file is used by the post upload hook in the PRESUBMIT file to
# automatically change a CL's description based on the specified hashtags.
# Please see skia:3586 for more details.
#
# The format of this file is:
# hashtag_name,mapped_text
#
# Here are some examples:
# * "projectxyz, BUG=skia:123" would convert "#projectxyz" into "BUG=skia:123".
# * "notry, NOTRY=true" would convert "#notry" into "NOTRY=true".
dummyproject,BUG=skia:2139,BUG=skia:2812
notry,NOTRY=true
nocommit,COMMIT=false
floats,BUG=skia:3592
neon,#n5,#n9
n5,CQ_INCLUDE_TRYBOTS=client.skia.android:Test-Android-Nexus5-Adreno330-Arm7-Debug-Trybot
n7,CQ_INCLUDE_TRYBOTS=client.skia.android:Test-Android-Nexus7-Tegra3-Arm7-Debug-Trybot
n9,CQ_INCLUDE_TRYBOTS=client.skia.android:Test-Android-Nexus9-TegraK1-Arm64-Release-Trybot
crskps,BUG=skia:3574,NOTRY=true

View File

@ -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):