blob: 9bfc86ed28ddd80ad7a2937c2af447b541011cdb [file] [log] [blame]
# Copyright 2022 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Recipe for launching sequences of builders."""
import re
from PB.go.chromium.org.luci.buildbucket.proto import common as common_pb2
import PB.recipes.pigweed.pipeline as pipeline_pb2
from PB.recipe_engine import result
from recipe_engine import post_process
DEPS = [
'fuchsia/status_check',
'fuchsia/subbuild',
'recipe_engine/properties',
'recipe_engine/step',
]
PROPERTIES = pipeline_pb2.InputProperties
def RunSteps(api, props):
"""Launch sequences of builders."""
for i, round_property in enumerate(props.rounds):
with api.step.nest(f'round {i}') as pres:
builders = []
for builder_property in round_property.builders:
# TODO(b/245788264) Support non-current project.
assert not builder_property.project
# TODO(b/245788264) Support non-current bucket.
assert not builder_property.bucket
builders.append(builder_property.builder)
launched_builds = api.subbuild.launch(builders, pres)
build_ids = [x.build_id for x in launched_builds.values()]
collected_builds = api.subbuild.collect(build_ids)
failures = []
with api.step.defer_results():
for build in collected_builds.values():
with api.step.nest(build.builder) as sub_pres:
if build.build_proto.status != common_pb2.SUCCESS:
sub_pres.status = 'FAILURE'
failures.append(build.builder)
if failures:
return result.RawResult(
summary_markdown=f'Failed builds: {", ".join(failures)}',
status=common_pb2.FAILURE,
)
def GenTests(api): # pylint: disable=invalid-name
"""Create tests."""
def builder(name):
match = re.match(
r'(?:(?:(?P<project>[^/]+)/)?(?P<bucket>[^/]+)/)?(?P<name>[^/]+)$',
name,
)
assert match
return pipeline_pb2.Builder(
project=match.group('project') or '',
bucket=match.group('bucket') or '',
builder=match.group('name'),
)
def round(*builders, timeout_sec=0):
return pipeline_pb2.Round(
builders=list(builders), timeout_sec=timeout_sec,
)
def properties(*rounds):
return api.properties(pipeline_pb2.InputProperties(rounds=list(rounds)))
def result_ci(name, id, status='SUCCESS', **kwargs):
return api.subbuild.ci_build_message(
builder=name, build_id=id, status=status, **kwargs,
)
def assert_step_success(round, name):
return api.post_process(
post_process.StepSuccess, f'round {round}.{name}'
)
def assert_step_failure(round, name):
return api.post_process(
post_process.StepFailure, f'round {round}.{name}'
)
def assert_num_rounds(round):
return api.post_process(
post_process.MustRun, f'round {round-1}'
) + api.post_process(post_process.DoesNotRun, f'round {round}')
yield (
api.status_check.test('one_builder')
+ properties(round(builder('a')))
+ api.subbuild.child_build_steps(
[result_ci('a', 1000)],
launch_step='round 0',
collect_step='round 0',
)
+ assert_step_success(0, 'a')
+ assert_num_rounds(1)
)
yield (
api.status_check.test('two_builders')
+ properties(round(builder('a'), builder('b')),)
+ api.subbuild.child_build_steps(
[result_ci('a', 1000), result_ci('b', 1001)],
launch_step='round 0',
collect_step='round 0',
)
+ assert_step_success(0, 'a')
+ assert_step_success(0, 'b')
+ assert_num_rounds(1)
)
yield (
api.status_check.test('two_rounds')
+ properties(round(builder('a')), round(builder('b')),)
+ api.subbuild.child_build_steps(
[result_ci('a', 1000)],
launch_step='round 0',
collect_step='round 0',
)
+ api.subbuild.child_build_steps(
[result_ci('b', 2000)],
launch_step='round 1',
collect_step='round 1',
)
+ assert_step_success(0, 'a')
+ assert_step_success(1, 'b')
+ assert_num_rounds(2)
)
yield (
api.status_check.test('first_round_failure', status='failure')
+ properties(round(builder('a'), builder('b')), round(builder('c')),)
+ api.subbuild.child_build_steps(
[result_ci('a', 1000), result_ci('b', 1001, status='FAILURE')],
launch_step='round 0',
collect_step='round 0',
)
+ assert_step_success(0, 'a')
+ assert_step_failure(0, 'b')
+ assert_num_rounds(1)
)
yield (
api.status_check.test('second_round_failure', status='failure')
+ properties(
round(builder('a'), builder('b')),
round(builder('c')),
round(builder('d')),
)
+ api.subbuild.child_build_steps(
[result_ci('a', 1000), result_ci('b', 1001)],
launch_step='round 0',
collect_step='round 0',
)
+ api.subbuild.child_build_steps(
[result_ci('c', 2000, 'FAILURE')],
launch_step='round 1',
collect_step='round 1',
)
+ assert_step_success(0, 'a')
+ assert_step_success(0, 'b')
+ assert_step_failure(1, 'c')
+ assert_num_rounds(2)
)