| // Copyright 2013 The Flutter Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| import 'dart:async'; | |
| import 'dart:convert'; | |
| import 'dart:io' as io; | |
| import 'package:args/command_runner.dart'; | |
| import 'package:path/path.dart' as path; | |
| import 'environment.dart'; | |
| import 'felt_config.dart'; | |
| import 'package_lock.dart'; | |
| class GenerateBuilderJsonCommand extends Command<bool> { | |
| @override | |
| String get description => | |
| 'Generates JSON for the engine_v2 builders to build and copy all artifacts, ' | |
| 'compile all test bundles, and run all test suites on all platforms.'; | |
| @override | |
| String get name => 'generate-builder-json'; | |
| @override | |
| FutureOr<bool>? run() { | |
| final PackageLock packageLock = PackageLock(); | |
| final FeltConfig config = FeltConfig.fromFile( | |
| path.join(environment.webUiTestDir.path, 'felt_config.yaml') | |
| ); | |
| final String configString = generate(config, packageLock); | |
| final io.File configFile = io.File(path.join( | |
| environment.flutterDirectory.path, | |
| 'ci', | |
| 'builders', | |
| 'linux_web_engine.json', | |
| )); | |
| configFile.writeAsStringSync('$configString\n'); | |
| return true; | |
| } | |
| String generate(FeltConfig config, PackageLock packageLock) { | |
| final Map<String, dynamic> outputJson = <String, dynamic>{ | |
| '_comment': 'THIS IS A GENERATED FILE. Do not edit this file directly.', | |
| '_comment2': 'See `generate_builder_json.dart` for the generator code', | |
| 'builds': <dynamic>[ | |
| _getArtifactBuildStep(), | |
| for (final TestBundle bundle in config.testBundles) | |
| _getBundleBuildStep(bundle), | |
| ], | |
| 'tests': _getAllTestSteps(config.testSuites, packageLock) | |
| }; | |
| return const JsonEncoder.withIndent(' ').convert(outputJson); | |
| } | |
| Map<String, dynamic> _getArtifactBuildStep() { | |
| return <String, dynamic>{ | |
| 'name': 'web_tests/artifacts', | |
| 'drone_dimensions': <String>[ | |
| 'device_type=none', | |
| 'os=Linux', | |
| 'cores=32' | |
| ], | |
| 'gclient_variables': <String, dynamic>{ | |
| 'download_android_deps': false, | |
| 'download_jdk': false, | |
| 'download_emsdk': true, | |
| }, | |
| 'gn': <String>[ | |
| '--web', | |
| '--runtime-mode=release', | |
| '--no-goma', | |
| ], | |
| 'ninja': <String, dynamic>{ | |
| 'config': 'wasm_release', | |
| 'targets': <String>[ | |
| 'flutter/web_sdk:flutter_web_sdk_archive' | |
| ] | |
| }, | |
| 'archives': <dynamic>[ | |
| <String, dynamic>{ | |
| 'name': 'wasm_release', | |
| 'base_path': 'out/wasm_release/zip_archives/', | |
| 'type': 'gcs', | |
| 'include_paths': <String>[ | |
| 'out/wasm_release/zip_archives/flutter-web-sdk.zip' | |
| ], | |
| 'realm': 'production', | |
| } | |
| ], | |
| 'generators': <String, dynamic>{ | |
| 'tasks': <dynamic>[ | |
| <String, dynamic>{ | |
| 'name': 'check licenses', | |
| 'parameters': <String>[ | |
| 'check-licenses' | |
| ], | |
| 'scripts': <String>[ 'flutter/lib/web_ui/dev/felt' ], | |
| }, | |
| <String, dynamic>{ | |
| 'name': 'web engine analysis', | |
| 'parameters': <String>[ | |
| 'analyze' | |
| ], | |
| 'scripts': <String>[ 'flutter/lib/web_ui/dev/felt' ], | |
| }, | |
| <String, dynamic>{ | |
| 'name': 'copy artifacts for web tests', | |
| 'parameters': <String>[ | |
| 'test', | |
| '--copy-artifacts', | |
| ], | |
| 'scripts': <String>[ 'flutter/lib/web_ui/dev/felt' ], | |
| }, | |
| ] | |
| }, | |
| }; | |
| } | |
| Map<String, dynamic> _getBundleBuildStep(TestBundle bundle) { | |
| return <String, dynamic>{ | |
| 'name': 'web_tests/test_bundles/${bundle.name}', | |
| 'drone_dimensions': <String>[ | |
| 'device_type=none', | |
| 'os=Linux', | |
| ], | |
| 'generators': <String, dynamic>{ | |
| 'tasks': <dynamic>[ | |
| <String, dynamic>{ | |
| 'name': 'compile bundle ${bundle.name}', | |
| 'parameters': <String>[ | |
| 'test', | |
| '--compile', | |
| '--bundle=${bundle.name}', | |
| ], | |
| 'scripts': <String>[ 'flutter/lib/web_ui/dev/felt' ], | |
| } | |
| ] | |
| }, | |
| }; | |
| } | |
| Iterable<dynamic> _getAllTestSteps(List<TestSuite> suites, PackageLock packageLock) { | |
| return <dynamic>[ | |
| _getTestStepForPlatformAndBrowser(suites, packageLock, 'Linux', BrowserName.chrome), | |
| _getTestStepForPlatformAndBrowser(suites, packageLock, 'Linux', BrowserName.firefox), | |
| _getTestStepForPlatformAndBrowser(suites, packageLock, 'Mac', BrowserName.safari, specificOS: 'Mac-13', cpu: 'arm64'), | |
| _getTestStepForPlatformAndBrowser(suites, packageLock, 'Windows', BrowserName.chrome) | |
| ]; | |
| } | |
| Map<String, dynamic> _getTestStepForPlatformAndBrowser( | |
| List<TestSuite> suites, | |
| PackageLock packageLock, | |
| String platform, | |
| BrowserName browser, { | |
| String? specificOS, | |
| String? cpu, | |
| }) { | |
| final filteredSuites = suites.where((suite) => suite.runConfig.browser == browser); | |
| final bundles = filteredSuites.map((suite) => suite.testBundle).toSet(); | |
| return <String, dynamic>{ | |
| 'name': '$platform run ${browser.name} suites', | |
| 'recipe': 'engine_v2/tester_engine', | |
| 'drone_dimensions': <String>[ | |
| 'device_type=none', | |
| 'os=${specificOS ?? platform}', | |
| if (cpu != null) 'cpu=$cpu', | |
| ], | |
| 'gclient_variables': <String, dynamic>{ | |
| 'download_android_deps': false, | |
| 'download_jdk': false, | |
| }, | |
| 'dependencies': <String>[ | |
| 'web_tests/artifacts', | |
| ...bundles.map((bundle) => 'web_tests/test_bundles/${bundle.name}'), | |
| ], | |
| 'test_dependencies': <dynamic>[ | |
| <String, dynamic>{ | |
| 'dependency': 'goldctl', | |
| 'version': 'git_revision:720a542f6fe4f92922c3b8f0fdcc4d2ac6bb83cd', | |
| }, | |
| if (browser == BrowserName.chrome) | |
| <String, dynamic>{ | |
| 'dependency': 'chrome_and_driver', | |
| 'version': packageLock.chromeLock.version, | |
| }, | |
| if (browser == BrowserName.firefox) | |
| <String, dynamic>{ | |
| 'dependency': 'firefox', | |
| 'version': 'version:${packageLock.firefoxLock.version}', | |
| } | |
| ], | |
| 'tasks': filteredSuites.map((suite) => <String, dynamic> { | |
| 'name': 'run suite ${suite.name}', | |
| 'parameters': <String>[ | |
| 'test', | |
| '--run', | |
| '--suite=${suite.name}', | |
| ], | |
| 'script': 'flutter/lib/web_ui/dev/felt', | |
| }).toList(), | |
| }; | |
| } | |
| } |