blob: 3b25dea82ae028cc0b465e69270e130f653a213b [file] [log] [blame]
# Copyright 2014 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.
"""This recipe module allows triggering builds within the same master.
See README.md.
"""
from recipe_engine import recipe_api
class TriggerApi(recipe_api.RecipeApi):
"""APIs for triggering new builds."""
def __init__(self, **kwargs):
super(TriggerApi, self).__init__(**kwargs)
def _port_from_properties_only(self, trigger_spec):
"""Convert from previous "properties-only" mode to trigger spec."""
builder_name = trigger_spec.get('buildername')
if not builder_name:
return trigger_spec
props = trigger_spec.copy()
del props['buildername']
return {
'builder_name': builder_name,
'properties': props,
}
def __call__(self, *trigger_specs, **kwargs):
"""Triggers new builds by builder names.
Args:
trigger_specs: a list of trigger dicts, where each dict specifies a build
to trigger. Supported keys:
builder_name (str): in BuildBot context, builder name
bucket (str): buildbucket bucket where the triggered builds will be
placed.
critical (bool): if True (default) and triggering fails on the
buildbot master side, mark entire build as failed (exception).
properties (dict): build properties for a new build.
buildbot_changes (list of dict): list of Buildbot changes to create.
See below.
tags (dict or list of str): if the trigger build is scheduled through
buildbucket, |tags| will be appended to the buildbucket build.
name: name of the step. If not specified, it is generated
automatically. Its format may change in future.
Buildbot changes:
buildbot_changes (a list of dicts) is a list of changes for the
triggered builds. Each change is a dict with keys (all optional):
author (str)
revision
revlink (str): link to a web view of the revision.
comment
when_timestamp (int): timestamp of the change, in seconds since Unix
Epoch.
branch
category (str): Buildbot change category
files (list of str): list of changed filenames
The first change is used to populate source stamp properties.
Examples:
Basic:
api.trigger({
'builder_name': 'Release',
'properties': {
'my_prop': 123,
},
})
Using BuildBucket:
api.trigger({
'builder_name': 'Release',
'bucket': 'master.tryserver.chromium.linux',
'properties': {
'my_prop': 123,
},
})
WARNING: on buildbot, this requires certain configuration on the
master prior first use. See ./README.md.
Create Buildbot changes:
api.trigger({
'builder_name': 'Release',
'buildbot_changes': [{
'author': 'someone@chromium.org',
'branch': 'master',
'files': ['a.txt.'],
'comments': 'Refactoring',
'revision': 'deadbeef',
'revlink':
'http://chromium.googlesource.com/chromium/src/+/deadbeef',
'when_timestamp': 1416859562,
}]
})
"""
# Backward-compatibility:
trigger_specs = map(self._port_from_properties_only, trigger_specs)
builder_names = set()
for trigger in trigger_specs:
assert isinstance(trigger, dict), ('trigger spec must be a dict: %s'
% (trigger,))
builder_name = trigger.get('builder_name')
assert builder_name, 'builder_name is missing: %s' % (trigger,)
builder_names.add(builder_name)
tags = trigger.get('tags', [])
# Convert dict tags
if isinstance(tags, dict):
tags = ['%s:%s' % item for item in tags.iteritems()]
trigger['tags'] = tags
# Validate tags.
for t in tags:
assert isinstance(t, basestring), t
assert len(t) >= 3 and ':' in t, t
key, value = t.split(':', 1)
assert key
assert value
assert key != 'buildset', 'buildset tag is reserved'
assert key != 'parent_build_id', 'parent_build_id tag is reserved'
result = self.m.step(
kwargs.get('name', 'trigger'),
cmd=[],
trigger_specs=trigger_specs,
)
if 'name' not in kwargs:
result.presentation.step_text = "<br />".join(sorted(builder_names))
return result