blob: 3b514d573ec2b187f5658dc32138ecf6b11ba715 [file]
# Copyright 2022 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.
"""Compilator recipe.
Triggered by the orchestrator recipe to perform all
check-out-related tasks: sync, hooks, compile, isolate and read all
configs from check-out: MB for building and builders.pyl for testing.
All properties needed by the orchestrator are returned at the end of the
build: CAS digests and test configurations.
The compilator is only used in a trybot setting.
"""
import json
from PB.go.chromium.org.luci.buildbucket.proto import common as common_pb
from PB.recipe_engine import result as result_pb2
from recipe_engine.post_process import DropExpectation, SummaryMarkdown
from recipe_engine.recipe_api import Property
from dataclasses import dataclass
from recipe_engine.recipe_api import RecipeScriptApi
from recipe_engine.recipe_test_api import RecipeTestApi
from RECIPE_MODULES.build import (
builder_group,
chromium,
v8,
v8_tests,
)
from RECIPE_MODULES.recipe_engine import (
buildbucket,
file,
json as json_module,
path,
platform,
runtime,
step,
)
@dataclass
class DEPS(RecipeScriptApi):
buildbucket: buildbucket.API
builder_group: builder_group.API
chromium: chromium.API
file: file.API
json: json_module.API
path: path.API
platform: platform.API
runtime: runtime.API
step: step.API
v8: v8.API
v8_tests: v8_tests.API
@dataclass
class TEST_DEPS(RecipeTestApi):
buildbucket: buildbucket.TEST_API
builder_group: builder_group.TEST_API
json: json_module.TEST_API
platform: platform.TEST_API
runtime: runtime.TEST_API
step: step.TEST_API
v8: v8.TEST_API
v8_tests: v8_tests.TEST_API
PROPERTIES = {
# Mapping of custom dependencies to sync (dependency name as in DEPS
# file -> deps url).
'custom_deps': Property(default=None, kind=dict),
# Optional list of default targets. If not specified the implicit "all"
# target will be built.
'default_targets': Property(default=None, kind=list),
# Mapping of additional gclient variables to set (map name -> value).
'gclient_vars': Property(default=None, kind=dict),
# One of intel|arm|mips.
'target_arch': Property(default=None, kind=str),
# One of android|fuchsia|linux|mac|win.
'target_platform': Property(default=None, kind=str),
# Revision to compile
'revision': Property(default=None, kind=str),
}
CANCELLATION_MESSAGE = (
'Parent orchestrator build ended, causing this build to be canceled.'
)
def orchestrator_name(api: DEPS):
"""Contruct orchestrator name by compilator name.
Returns the orchestrator name by naming convention. Same as compilator
name with the "_compile" infix removed.
"""
name = api.buildbucket.builder_name
if api.buildbucket.build.builder.bucket.startswith('try'):
allowed_suffixes = ('_compile_rel', '_compile_dbg', '_compile_perf_try')
assert name.endswith(allowed_suffixes), (
f'Compilator name doesn\'t follow the naming convention. Must end '
f'in {", ".join(allowed_suffixes)}, but was {name}.'
)
prefix, suffix = name.rsplit('_compile_', 1)
return f'{prefix}_{suffix}'
return name
def read_test_spec(api: DEPS, source_dir):
"""Dynamically load test specifications from all discovered test roots."""
test_spec = api.v8_tests.TEST_SPEC()
for test_root in api.v8.get_test_roots(source_dir):
test_spec.update(api.v8.read_test_spec(test_root, [orchestrator_name(api)]))
return test_spec
def emit_compilator_properties(api: DEPS, test_spec):
properties = dict(test_spec.as_properties_dict_single())
properties['swarm_hashes'] = api.v8_tests.isolated_tests
properties['gn_args'] = api.v8_tests.gn_args
properties_step = api.step('compilator properties', [])
properties_step.presentation.properties['compilator_properties'] = properties
properties_step.presentation.logs['compilator_properties'] = api.json.dumps(
properties, indent=2
)
def compilator_steps(
api: DEPS,
custom_deps,
default_targets,
gclient_vars,
target_arch,
target_platform,
revision,
):
v8 = api.v8
api.v8_tests.load_static_test_configs()
bot_config = v8.get_bot_config(
binary_size_tracking=None,
clusterfuzz_archive=None,
coverage=None,
enable_swarming=True,
target_arch=target_arch,
target_platform=target_platform,
track_build_dependencies=None,
triggers=None,
triggers_proxy=None,
)
v8.apply_bot_config(bot_config, revision=revision)
v8.set_gclient_custom_vars(gclient_vars)
v8.set_gclient_custom_deps(custom_deps)
v8.set_chromium_configs(clobber=False, default_targets=default_targets)
with api.step.nest('initialization'):
update_result = v8.checkout(revision)
source_dir = update_result.source_root.path
build_dir = api.v8.build_dir(source_dir)
api.v8_tests.set_up_swarming()
api.v8.runhooks(source_dir, build_dir)
test_spec = read_test_spec(api, source_dir)
with api.step.nest('build'):
compile_failure = v8.compile(source_dir, build_dir, test_spec)
if compile_failure:
return compile_failure
emit_compilator_properties(api, test_spec)
def RunSteps(
api: DEPS,
custom_deps,
default_targets,
gclient_vars,
target_arch,
target_platform,
revision,
):
try:
return compilator_steps(
api,
custom_deps,
default_targets,
gclient_vars,
target_arch,
target_platform,
revision,
)
finally:
if api.runtime.in_global_shutdown:
# pylint: disable=lost-exception
# Cancellation can cause all sorts of spurious exceptions.
return result_pb2.RawResult(
status=common_pb.CANCELED, summary_markdown=CANCELLATION_MESSAGE
)
def GenTests(api: TEST_DEPS):
def test(name, builder_name='v8_foobar_compile_rel', status='SUCCESS'):
build_msg = api.buildbucket.try_build_message(
project='v8',
revision='deadbeef' * 5,
builder=builder_name,
git_repo='https://chromium.googlesource.com/v8/v8',
change_number=456789,
patch_set=12,
tags=api.buildbucket.tags(
user_agent='cq',
buildset='patch/gerrit/chromium-review.googlesource.com/456789/12',
),
)
api.buildbucket.update_backend_service_account(
build_msg, 'v8-try-builder@chops-service-accounts.iam.gserviceaccount.com'
)
return (
api.test(name, status=status)
+ api.builder_group.for_current('tryserver.v8')
+ api.platform('linux', 64)
+ api.buildbucket.build(build_msg)
+ api.v8.example_test_roots('test_checkout')
+ api.v8.hide_infra_steps()
)
test_spec = json.dumps({'tests': [{'name': 'v8testing'}]}, indent=2)
yield (
test('basic') + api.v8.test_spec_in_checkout('v8_foobar_rel', test_spec)
)
yield (
api.test('basic_ci', status='SUCCESS')
+ api.builder_group.for_current('client.v8')
+ api.buildbucket.ci_build(
project='v8',
revision='deadbeef' * 5,
builder='Random CI builder',
git_repo='https://chromium.googlesource.com/v8/v8',
)
+ api.v8.example_test_roots('test_checkout')
+ api.v8.hide_infra_steps()
+ api.v8.test_spec_in_checkout('Random CI builder', test_spec)
)
yield (
test('windows', 'v8_foobar_compile_dbg')
+ api.v8.test_spec_in_checkout('v8_foobar_dbg', test_spec)
+ api.platform('win', 64)
+ api.post_process(DropExpectation)
)
yield (
test('compile_failure', status='FAILURE')
+ api.step_data('build.compile', retcode=1)
+ api.post_process(DropExpectation)
)
yield (
test('cancellation', status='CANCELED')
+ api.runtime.global_shutdown_on_step('build.compile')
+ api.post_process(SummaryMarkdown, CANCELLATION_MESSAGE)
+ api.post_process(DropExpectation)
)