blob: fcc30a7e7c834cb7b8fde9bc38493e7a0bac5d4e [file] [log] [blame]
# Copyright 2016 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.
from contextlib import contextmanager
from PB.recipes.flutter.engine.engine import InputProperties
from PB.recipes.flutter.engine.engine import EnvProperties
from PB.go.chromium.org.luci.buildbucket.proto import build as build_pb2
from google.protobuf import struct_pb2
PYTHON_VERSION_COMPATIBILITY = 'PY3'
DEPS = [
'depot_tools/depot_tools',
'depot_tools/gclient',
'flutter/bucket_util',
'flutter/os_utils',
'flutter/repo_util',
'flutter/zip',
'fuchsia/gcloud',
'fuchsia/goma',
'recipe_engine/buildbucket',
'recipe_engine/context',
'recipe_engine/file',
'recipe_engine/path',
'recipe_engine/platform',
'recipe_engine/properties',
'recipe_engine/raw_io',
'recipe_engine/runtime',
'recipe_engine/step',
]
# Account for ~1 hour queue time when there is a high number of commits.
DRONE_TIMEOUT_SECS = 7200
BUCKET_NAME = 'flutter_infra_release'
MAVEN_BUCKET_NAME = 'download.flutter.io'
ICU_DATA_PATH = 'third_party/icu/flutter/icudtl.dat'
GIT_REPO = (
'https://flutter.googlesource.com/mirrors/engine')
PROPERTIES = InputProperties
ENV_PROPERTIES = EnvProperties
def GetCheckoutPath(api):
return api.path['cache'].join('builder', 'src')
def GetGitHash(api):
with api.context(cwd=GetCheckoutPath(api)):
return api.step(
"Retrieve git hash", ["git", "rev-parse", "HEAD"],
stdout=api.raw_io.output_text()).stdout.strip()
def GetCloudPath(api, path):
git_hash = api.buildbucket.gitiles_commit.id
if api.runtime.is_experimental:
return 'flutter/experimental/%s/%s' % (git_hash, path)
return 'flutter/%s/%s' % (git_hash, path)
def Build(api, config, *targets):
checkout = GetCheckoutPath(api)
build_dir = checkout.join('out/%s' % config)
goma_jobs = api.properties['goma_jobs']
ninja_args = [api.depot_tools.ninja_path, '-j', goma_jobs, '-C', build_dir]
ninja_args.extend(targets)
with api.goma.build_with_goma(), api.depot_tools.on_path():
name = 'build %s' % ' '.join([config] + list(targets))
api.step(name, ninja_args)
def RunGN(api, *args):
checkout = GetCheckoutPath(api)
gn_cmd = ['python', checkout.join('flutter/tools/gn'), '--goma']
gn_cmd.extend(args)
api.step('gn %s' % ' '.join(args), gn_cmd)
def NotifyPubsub(api,
buildername,
bucket,
topic='projects/flutter-dashboard/topics/luci-builds-prod'):
"""Sends a pubsub message to the topic specified with buildername and githash, identifying
the completed build.
Args:
api: luci api object.
buildername(str): The name of builder.
bucket(str): The name of the bucket.
topic(str): (optional) gcloud topic to publish message to.
"""
githash = GetGitHash(api)
cmd = [
'pubsub', 'topics', 'publish', topic,
'--message={"buildername" : "%s", "bucket" : "%s", "githash" : "%s"}' %
(buildername, bucket, githash)
]
api.gcloud(*cmd)
def UploadArtifacts(api,
platform,
file_paths=[],
directory_paths=[],
archive_name='artifacts.zip',
pkg_root=None):
dir_label = '%s UploadArtifacts %s' % (platform, archive_name)
with api.os_utils.make_temp_directory(dir_label) as temp_dir:
local_zip = temp_dir.join('artifacts.zip')
remote_name = '%s/%s' % (platform, archive_name)
remote_zip = GetCloudPath(api, remote_name)
if pkg_root is None:
pkg_root = GetCheckoutPath(api)
pkg = api.zip.make_package(pkg_root, local_zip)
api.bucket_util.add_files(pkg, file_paths)
api.bucket_util.add_directories(pkg, directory_paths)
pkg.zip('Zip %s %s' % (platform, archive_name))
if api.bucket_util.should_upload_packages():
api.bucket_util.safe_upload(local_zip, remote_zip)
def UploadDartSdk(api, archive_name, target_path='src/out/host_debug'):
api.bucket_util.upload_folder('Upload Dart SDK', target_path, 'dart-sdk',
archive_name)
def PackageLinuxDesktopVariant(api, label, bucket_name):
artifacts = [
'libflutter_linux_gtk.so',
]
if bucket_name.endswith('profile') or bucket_name.endswith('release'):
artifacts.append('gen_snapshot')
# Headers for the library are in the flutter_linux folder.
api.bucket_util.upload_folder_and_files(
'Upload linux-arm64 Flutter GTK artifacts',
'src/out/%s' % label,
'flutter_linux',
'linux-arm64-flutter-gtk.zip',
platform=bucket_name,
file_paths=artifacts
)
def BuildLinux(api):
RunGN(api, '--runtime-mode', 'debug', '--full-dart-sdk', '--target-os=linux',
'--linux-cpu=arm64', '--prebuilt-dart-sdk')
Build(api, 'linux_debug_arm64')
RunGN(api, '--runtime-mode', 'profile', '--no-lto', '--target-os=linux',
'--linux-cpu=arm64', '--prebuilt-dart-sdk')
Build(api, 'linux_profile_arm64')
RunGN(api, '--runtime-mode', 'release', '--target-os=linux',
'--linux-cpu=arm64', '--prebuilt-dart-sdk')
Build(api, 'linux_release_arm64')
UploadArtifacts(api, 'linux-arm64', [
ICU_DATA_PATH,
'out/linux_debug_arm64/flutter_tester',
'out/linux_debug_arm64/gen/flutter/impeller/compiler/LICENSE.impellerc.md',
'out/linux_debug_arm64/gen/flutter/tools/path_ops/LICENSE.path_ops.md',
'out/linux_debug_arm64/impellerc',
'out/linux_debug_arm64/libpath_ops.so',
'out/linux_debug_arm64/libtessellator.so',
'out/linux_debug_arm64/gen/flutter/lib/snapshot/isolate_snapshot.bin',
'out/linux_debug_arm64/gen/flutter/lib/snapshot/vm_isolate_snapshot.bin',
'out/linux_debug_arm64/gen/frontend_server.dart.snapshot',
])
# Font subset
UploadArtifacts(
api,
'linux-arm64', [
'out/linux_release_arm64/font-subset',
'out/linux_debug_arm64/gen/const_finder.dart.snapshot',
],
archive_name='font-subset.zip'
)
# Desktop embedding.
PackageLinuxDesktopVariant(api, 'linux_debug_arm64', 'linux-arm64-debug')
PackageLinuxDesktopVariant(api, 'linux_profile_arm64', 'linux-arm64-profile')
PackageLinuxDesktopVariant(api, 'linux_release_arm64', 'linux-arm64-release')
# Legacy; remove once Flutter tooling is updated to use the -debug location.
PackageLinuxDesktopVariant(api, 'linux_debug_arm64', 'linux-arm64')
UploadDartSdk(
api,
archive_name='dart-sdk-linux-arm64.zip',
target_path='src/out/linux_debug_arm64')
def RunSteps(api, properties, env_properties):
# Collect memory/cpu/process before task execution.
api.os_utils.collect_os_info()
cache_root = api.path['cache'].join('builder')
checkout = GetCheckoutPath(api)
api.file.rmtree('Clobber build output', checkout.join('out'))
api.file.ensure_directory('Ensure checkout cache', cache_root)
api.goma.ensure()
dart_bin = checkout.join('third_party', 'dart', 'tools', 'sdks', 'dart-sdk',
'bin')
android_home = checkout.join('third_party', 'android_tools', 'sdk')
env = {
'GOMA_DIR': api.goma.goma_dir,
'ANDROID_HOME': str(android_home),
'FLUTTER_PREBUILT_DART_SDK': 'True',
}
env_prefixes = {}
api.repo_util.engine_checkout(cache_root, env, env_prefixes)
# Delete derived data on mac. This is a noop for other platforms.
api.os_utils.clean_derived_data()
# Various scripts we run assume access to depot_tools on path for `ninja`.
with api.context(
cwd=cache_root, env=env,
env_prefixes=env_prefixes), api.depot_tools.on_path():
api.gclient.runhooks()
if api.platform.is_linux:
if api.properties.get('build_host', True):
BuildLinux(api)
if api.platform.is_mac:
# no-op
raise api.step.StepFailure('Mac Arm host builds not supported yet.')
if api.platform.is_win:
raise api.step.StepFailure('Windows Arm host builds not supported yet.')
# Notifies of build completion
# TODO(crbug.com/843720): replace this when user defined notifications is implemented.
try:
NotifyPubsub(api, api.buildbucket.builder_name,
api.buildbucket.build.builder.bucket)
except (api.step.StepFailure) as e:
pass
# This is to clean up leaked processes.
api.os_utils.kill_processes()
# Collect memory/cpu/process after task execution.
api.os_utils.collect_os_info()
# pylint: disable=line-too-long
# See https://chromium.googlesource.com/infra/luci/recipes-py/+/refs/heads/master/doc/user_guide.md
# The tests in here make sure that every line of code is used and does not fail.
# pylint: enable=line-too-long
def GenTests(api):
git_revision = 'abcd1234'
for platform in ('mac', 'linux', 'win'):
for should_upload in (True, False):
test = api.test(
'%s%s' % (platform, '_upload' if should_upload else ''),
api.platform(platform, 64),
api.buildbucket.ci_build(
builder='%s Engine' % platform.capitalize(),
git_repo=GIT_REPO,
project='flutter',
revision='%s' % git_revision,
),
api.runtime(is_experimental=False),
api.properties(
InputProperties(
clobber=False,
goma_jobs='1024',
fuchsia_ctl_version='version:0.0.2',
build_host=True,
build_fuchsia=True,
build_android_aot=True,
build_android_debug=True,
upload_packages=should_upload,
force_upload=True,
),),
api.properties.environ(
EnvProperties(SWARMING_TASK_ID='deadbeef')),
)
yield test
for should_upload in (True, False):
yield api.test(
'experimental%s' % ('_upload' if should_upload else ''),
api.buildbucket.ci_build(
builder='Linux Engine',
git_repo=GIT_REPO,
project='flutter',
),
api.runtime(is_experimental=True),
api.properties(
InputProperties(
goma_jobs='1024',
fuchsia_ctl_version='version:0.0.2',
android_sdk_license='android_sdk_hash',
android_sdk_preview_license='android_sdk_preview_hash',
upload_packages=should_upload,
)),
)
yield api.test(
'clobber',
api.buildbucket.ci_build(
builder='Linux Host Engine',
git_repo='https://github.com/flutter/engine',
project='flutter'),
api.runtime(is_experimental=True),
api.properties(
InputProperties(
clobber=True,
git_url='https://github.com/flutter/engine',
goma_jobs='200',
git_ref='refs/pull/1/head',
fuchsia_ctl_version='version:0.0.2',
build_host=True,
build_fuchsia=True,
build_android_aot=True,
build_android_debug=True,
android_sdk_license='android_sdk_hash',
android_sdk_preview_license='android_sdk_preview_hash')),
)
yield api.test(
'pull_request',
api.buildbucket.ci_build(
builder='Linux Host Engine',
git_repo='https://github.com/flutter/engine',
project='flutter'),
api.runtime(is_experimental=True),
api.properties(
InputProperties(
clobber=False,
git_url='https://github.com/flutter/engine',
goma_jobs='200',
git_ref='refs/pull/1/head',
fuchsia_ctl_version='version:0.0.2',
build_host=True,
build_fuchsia=True,
build_android_aot=True,
build_android_debug=True,
android_sdk_license='android_sdk_hash',
android_sdk_preview_license='android_sdk_preview_hash')),
)
yield api.test(
'gcloud_pubsub_failure',
api.buildbucket.ci_build(
builder='Linux Host Engine',
git_repo='https://github.com/flutter/engine',
project='flutter'),
# Next line force a fail condition for the bot update
# first execution.
api.step_data('gcloud pubsub', retcode=1),
api.runtime(is_experimental=True),
api.properties(
InputProperties(
clobber=False,
git_url='https://github.com/flutter/engine',
goma_jobs='200',
git_ref='refs/pull/1/head',
fuchsia_ctl_version='version:0.0.2',
build_host=True,
build_fuchsia=True,
build_android_aot=True,
build_android_debug=True,
android_sdk_license='android_sdk_hash',
android_sdk_preview_license='android_sdk_preview_hash')))